1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include "parser.h"
32 #include "trace.h"
33 #include "util.h"
34 #include "symtab.h"
35 #include "io.h"
36 #include "bindings.h"
37 #include "errlog.h"
38 
39 
40 /* File globals. */
41 static void generate_a_binding(char *, char *);
42 
43 static int strpqcmp(char *, char *, char *);
44 static void strpqprint(char *, char *, FILE *);
45 
46 /*
47  * Bindings: do three-valued logic, where a binding can be
48  *	an expression to evaluate for truthfulness,
49  *	true,
50  *	false, or
51  *	empty.
52  *
53  *	Exception	Result	Evaluate?	Notes
54  *	---------	------	---------	-----
55  *
56  *	true		ok	yes		warn[1]
57  *	false		ok	no
58  *	empty		ok	no		treat as true
59  *	expr		ok	yes		s = !e
60  *
61  * Notes:
62  *	[1] Always exceptional, shows errno at run-time
63  *
64  */
65 
66 /*
67  * need_bindings -- see if we have to do anything at all. Implements
68  *	the following rows from the table above (die and evaluate=no lines)
69  *	Returns NO if we don't have to evaluate bindings at all.
70  *
71  *	Exception	Result	Evaluate?	Notes
72  *	---------	------	---------	-----
73  *	false		ok	no
74  *	empty		ok	no		treat as true
75  */
76 int
77 need_bindings(char *exception)
78 {
79 
80 	errlog(BEGIN, "need_bindings() {");
81 
82 	if (exception == NULL)
83 		exception = "";
84 
85 	/*	empty		false		ok	no */
86 	/*	empty		empty		ok	no, treat as true */
87 	if (strcmp(exception, "false") == 0 ||
88 	    *exception == '\0') {
89 		errlog(END, "}");
90 		return (NO);
91 	}
92 	errlog(END, "}");
93 	return (YES);
94 }
95 
96 
97 int
98 need_exception_binding(void)
99 {
100 	ENTRY	*e;
101 	char *exception;
102 
103 	exception = ((e = symtab_get_exception()) != NULL)?
104 	    (name_of(e)? name_of(e): ""): "";
105 
106 	return (need_bindings(exception));
107 
108 }
109 
110 /*
111  * generate_bindings -- make the code for exception bindings
112  *
113  *	Exception	Result	Evaluate?	Notes
114  *	---------	------	---------	-----
115  *	true		ok	yes		warn[2]
116  *	expr		ok	yes		s::= !e
117  *
118  *	Returns NO if we need both bindings, YES (ANTONYM) if we
119  *	only need to evaluate success.
120  */
121 int
122 generate_bindings(char *exception)
123 {
124 	int ret = NO;
125 
126 	errlog(BEGIN, "generate_bindings() {");
127 	errlog(TRACING,  "exception=%s\n", exception ? exception : "NULL");
128 
129 	/* Exception	Result	Evaluate?	Notes	*/
130 	/* ---------	------	---------	-----	*/
131 	/* true		ok	yes		warn[2] */
132 	if (exception != NULL) {
133 		generate_a_binding("exception", exception);
134 		errlog(END, "}");
135 	}
136 
137 	return (ret);
138 }
139 
140 /*
141  * bindings_exist -- make sure we don't use one if they're not there.
142  */
143 int
144 bindings_exist(void)
145 {
146 	int ret;
147 
148 	errlog(BEGIN, "bindings_exist() {");
149 	errlog(END, "}");
150 
151 	ret = validity_of(symtab_get_exception()) == YES;
152 
153 	return (ret);
154 }
155 
156 
157 
158 /*
159  * generate_a_binding -- generate just one, with a set of transformations
160  *	applied. Eg, return->_return, errno->functions_errvar,
161  *	unchanged(x)->x == 0, etc. Oneof and someof TBD.
162  */
163 static void
164 generate_a_binding(char *name, char *value)
165 {
166 	char *p = value;
167 	ENTRY	*e = symtab_get_errval();
168 	char	*errvar = (e == NULL)? NULL: name_of(e);
169 	char	*q;
170 
171 	errlog(BEGIN, "generate_a_binding() {");
172 	if (*value == NULL) {
173 		errlog(FATAL, "programmer error: asked to generate an "
174 			"empty binding");
175 	}
176 
177 	{
178 		/*
179 		 * XXX - friggin spaghetti
180 		 */
181 		ENTRY	*exc = symtab_get_exception();
182 
183 		if (exc != NULL)
184 			(void) fprintf(Bodyfp,
185 			    "#line %d \"%s\"\n",
186 			    line_of(exc), symtab_get_filename());
187 	}
188 
189 	/* Generate prefix. */
190 	(void) fprintf(Bodyfp, "    %s = (", name);
191 
192 	/* Walk across line, emitting tokens and transformed tokens */
193 
194 	for (; *p != NULL; p = q) {
195 		p = skipb(p);
196 		q = nextsep(p);
197 
198 		if (p == q) {
199 			/* We're at the end, a "(", ")" or an operator. */
200 			if (*p == '(') {
201 				/* We're at a parenthesized expression */
202 				q++;
203 			} else if (*p == ')') {
204 				/* And the end of an expression. */
205 				q++;
206 			} else if (*p == '!' && *(p+1) != '=') {
207 				/* Or a negated expression */
208 				q++;
209 			} else if ((q = nextb(p)) == p) {
210 				/* Real end! */
211 				break;
212 			}
213 
214 			/* Else it was an operator, boogy onwards. */
215 		}
216 		if (strpqcmp("$return", p, q) == 0) {
217 			(void) fputs("_return", Bodyfp);
218 		} else if (errvar != NULL && strpqcmp(errvar, p, q) == 0) {
219 			(void) fputs("functions_errvar", Bodyfp);
220 		} else if (strpqcmp("unchanged", p, q) == 0) {
221 			/* This will look odd. */
222 			(void) fputs("0 == ", Bodyfp);
223 		} else if (strpqcmp("oneof", p, q) == 0) {
224 			errlog(WARNING,  "Oneof unimplemented in spec2trace"
225 				"It will be treated as the token 'false'");
226 			(void) fputs("false", Bodyfp);
227 			break;
228 		} else if (strpqcmp("someof", p, q) == 0) {
229 			errlog(WARNING, "Someof unimplemented in spec2trace, "
230 				"It will be treated as the token 'false'");
231 			(void) fputs("false", Bodyfp);
232 			break;
233 		} else if (strpqcmp("errno", p, q) == 0) {
234 			(void) fputs("ABI_ERRNO", Bodyfp);
235 		} else {
236 			/* Just copy it. */
237 
238 			strpqprint(p, q, Bodyfp);
239 		}
240 		(void) putc(' ', Bodyfp);
241 	}
242 	(void) (void) fputs(");\n", Bodyfp);
243 	errlog(END, "}");
244 }
245 
246 /*
247  * strpqcmp -- compare a null-terminated string with a pq-bracketed string.
248  */
249 static int
250 strpqcmp(char *v1, char *p, char *q)
251 {
252 	int	rc;
253 	char	saved;
254 
255 	errlog(BEGIN, "strpqcmp() {");
256 	saved = *q;
257 	*q = NULL;
258 	rc = (strcmp(v1, p));
259 	*q = saved;
260 	errlog(END, "}");
261 	return (rc);
262 }
263 
264 /*
265  * strpqprint -- print a pq-bracketed string
266  */
267 static void
268 strpqprint(char *p, char *q, FILE *fp)
269 {
270 	char	saved;
271 
272 	errlog(BEGIN, "strpqprint() {");
273 	saved = *q;
274 	*q = NULL;
275 	(void) fputs(p, fp);
276 	*q = saved;
277 	errlog(END, "}");
278 }
279