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
need_bindings(char * exception)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
need_exception_binding(void)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
generate_bindings(char * exception)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
bindings_exist(void)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
generate_a_binding(char * name,char * value)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
strpqcmp(char * v1,char * p,char * q)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
strpqprint(char * p,char * q,FILE * fp)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