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