blob: 3f9b2feca88f6d94e7f9f18aae1d7f308aaaef1c [file] [log] [blame]
Adam Tkacfded0782008-03-22 11:20:54 +00001/* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
2/*
3
4Copyright (c) 1993, 1994 X Consortium
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of the X Consortium shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from the X Consortium.
26
27*/
28
29#include "def.h"
30
31extern char *directives[];
32extern struct inclist maininclist;
33
34find_includes(filep, file, file_red, recursion, failOK)
35 struct filepointer *filep;
36 struct inclist *file, *file_red;
37 int recursion;
38 boolean failOK;
39{
40 register char *line;
41 register int type;
42 boolean recfailOK;
43
44 while (line = getline(filep)) {
45 switch(type = deftype(line, filep, file_red, file, TRUE)) {
46 case IF:
47 doif:
48 type = find_includes(filep, file,
49 file_red, recursion+1, failOK);
50 while ((type == ELIF) || (type == ELIFFALSE) ||
51 (type == ELIFGUESSFALSE))
52 type = gobble(filep, file, file_red);
53 if (type == ELSE)
54 gobble(filep, file, file_red);
55 break;
56 case IFFALSE:
57 case IFGUESSFALSE:
58 doiffalse:
59 if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
60 recfailOK = TRUE;
61 else
62 recfailOK = failOK;
63 type = gobble(filep, file, file_red);
64 if (type == ELSE)
65 find_includes(filep, file,
66 file_red, recursion+1, recfailOK);
67 else
68 if (type == ELIF)
69 goto doif;
70 else
71 if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
72 goto doiffalse;
73 break;
74 case IFDEF:
75 case IFNDEF:
76 if ((type == IFDEF && isdefined(line, file_red, NULL))
77 || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
78 debug(1,(type == IFNDEF ?
79 "line %d: %s !def'd in %s via %s%s\n" : "",
80 filep->f_line, line,
81 file->i_file, file_red->i_file, ": doit"));
82 type = find_includes(filep, file,
83 file_red, recursion+1, failOK);
84 while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
85 type = gobble(filep, file, file_red);
86 if (type == ELSE)
87 gobble(filep, file, file_red);
88 }
89 else {
90 debug(1,(type == IFDEF ?
91 "line %d: %s !def'd in %s via %s%s\n" : "",
92 filep->f_line, line,
93 file->i_file, file_red->i_file, ": gobble"));
94 type = gobble(filep, file, file_red);
95 if (type == ELSE)
96 find_includes(filep, file,
97 file_red, recursion+1, failOK);
98 else if (type == ELIF)
99 goto doif;
100 else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
101 goto doiffalse;
102 }
103 break;
104 case ELSE:
105 case ELIFFALSE:
106 case ELIFGUESSFALSE:
107 case ELIF:
108 if (!recursion)
109 gobble(filep, file, file_red);
110 case ENDIF:
111 if (recursion)
112 return(type);
113 case DEFINE:
114 define(line, file);
115 break;
116 case UNDEF:
117 if (!*line) {
118 warning("%s, line %d: incomplete undef == \"%s\"\n",
119 file_red->i_file, filep->f_line, line);
120 break;
121 }
122 undefine(line, file_red);
123 break;
124 case INCLUDE:
125 add_include(filep, file, file_red, line, FALSE, failOK);
126 break;
127 case INCLUDEDOT:
128 add_include(filep, file, file_red, line, TRUE, failOK);
129 break;
130 case ERROR:
131 warning("(from %s) %s: %d: %s\n",
132 file_red->i_file, file->i_file,
133 filep->f_line, line);
134 break;
135
136 case PRAGMA:
137 case IDENT:
138 case SCCS:
139 case EJECT:
140 break;
141 case -1:
142 warning("%s", file_red->i_file);
143 if (file_red != file)
144 warning1(" (reading %s)", file->i_file);
145 warning1(", line %d: unknown directive == \"%s\"\n",
146 filep->f_line, line);
147 break;
148 case -2:
149 warning("%s", file_red->i_file);
150 if (file_red != file)
151 warning1(" (reading %s)", file->i_file);
152 warning1(", line %d: incomplete include == \"%s\"\n",
153 filep->f_line, line);
154 break;
155 }
156 }
157 return(-1);
158}
159
160gobble(filep, file, file_red)
161 register struct filepointer *filep;
162 struct inclist *file, *file_red;
163{
164 register char *line;
165 register int type;
166
167 while (line = getline(filep)) {
168 switch(type = deftype(line, filep, file_red, file, FALSE)) {
169 case IF:
170 case IFFALSE:
171 case IFGUESSFALSE:
172 case IFDEF:
173 case IFNDEF:
174 type = gobble(filep, file, file_red);
175 while ((type == ELIF) || (type == ELIFFALSE) ||
176 (type == ELIFGUESSFALSE))
177 type = gobble(filep, file, file_red);
178 if (type == ELSE)
179 (void)gobble(filep, file, file_red);
180 break;
181 case ELSE:
182 case ENDIF:
183 debug(0,("%s, line %d: #%s\n",
184 file->i_file, filep->f_line,
185 directives[type]));
186 return(type);
187 case DEFINE:
188 case UNDEF:
189 case INCLUDE:
190 case INCLUDEDOT:
191 case PRAGMA:
192 case ERROR:
193 case IDENT:
194 case SCCS:
195 case EJECT:
196 break;
197 case ELIF:
198 case ELIFFALSE:
199 case ELIFGUESSFALSE:
200 return(type);
201 case -1:
202 warning("%s, line %d: unknown directive == \"%s\"\n",
203 file_red->i_file, filep->f_line, line);
204 break;
205 }
206 }
207 return(-1);
208}
209
210/*
211 * Decide what type of # directive this line is.
212 */
213int deftype (line, filep, file_red, file, parse_it)
214 register char *line;
215 register struct filepointer *filep;
216 register struct inclist *file_red, *file;
217 int parse_it;
218{
219 register char *p;
220 char *directive, savechar;
221 register int ret;
222
223 /*
224 * Parse the directive...
225 */
226 directive=line+1;
227 while (*directive == ' ' || *directive == '\t')
228 directive++;
229
230 p = directive;
231 while (*p >= 'a' && *p <= 'z')
232 p++;
233 savechar = *p;
234 *p = '\0';
235 ret = match(directive, directives);
236 *p = savechar;
237
238 /* If we don't recognize this compiler directive or we happen to just
239 * be gobbling up text while waiting for an #endif or #elif or #else
240 * in the case of an #elif we must check the zero_value and return an
241 * ELIF or an ELIFFALSE.
242 */
243
244 if (ret == ELIF && !parse_it)
245 {
246 while (*p == ' ' || *p == '\t')
247 p++;
248 /*
249 * parse an expression.
250 */
251 debug(0,("%s, line %d: #elif %s ",
252 file->i_file, filep->f_line, p));
253 ret = zero_value(p, filep, file_red);
254 if (ret != IF)
255 {
256 debug(0,("false...\n"));
257 if (ret == IFFALSE)
258 return(ELIFFALSE);
259 else
260 return(ELIFGUESSFALSE);
261 }
262 else
263 {
264 debug(0,("true...\n"));
265 return(ELIF);
266 }
267 }
268
269 if (ret < 0 || ! parse_it)
270 return(ret);
271
272 /*
273 * now decide how to parse the directive, and do it.
274 */
275 while (*p == ' ' || *p == '\t')
276 p++;
277 switch (ret) {
278 case IF:
279 /*
280 * parse an expression.
281 */
282 ret = zero_value(p, filep, file_red);
283 debug(0,("%s, line %d: %s #if %s\n",
284 file->i_file, filep->f_line, ret?"false":"true", p));
285 break;
286 case IFDEF:
287 case IFNDEF:
288 debug(0,("%s, line %d: #%s %s\n",
289 file->i_file, filep->f_line, directives[ret], p));
290 case UNDEF:
291 /*
292 * separate the name of a single symbol.
293 */
294 while (isalnum(*p) || *p == '_')
295 *line++ = *p++;
296 *line = '\0';
297 break;
298 case INCLUDE:
299 debug(2,("%s, line %d: #include %s\n",
300 file->i_file, filep->f_line, p));
301
302 /* Support ANSI macro substitution */
303 {
304 struct symtab *sym = isdefined(p, file_red, NULL);
305 while (sym) {
306 p = sym->s_value;
307 debug(3,("%s : #includes SYMBOL %s = %s\n",
308 file->i_incstring,
309 sym -> s_name,
310 sym -> s_value));
311 /* mark file as having included a 'soft include' */
312 file->i_included_sym = TRUE;
313 sym = isdefined(p, file_red, NULL);
314 }
315 }
316
317 /*
318 * Separate the name of the include file.
319 */
320 while (*p && *p != '"' && *p != '<')
321 p++;
322 if (! *p)
323 return(-2);
324 if (*p++ == '"') {
325 ret = INCLUDEDOT;
326 while (*p && *p != '"')
327 *line++ = *p++;
328 } else
329 while (*p && *p != '>')
330 *line++ = *p++;
331 *line = '\0';
332 break;
333 case DEFINE:
334 /*
335 * copy the definition back to the beginning of the line.
336 */
337 strcpy (line, p);
338 break;
339 case ELSE:
340 case ENDIF:
341 case ELIF:
342 case PRAGMA:
343 case ERROR:
344 case IDENT:
345 case SCCS:
346 case EJECT:
347 debug(0,("%s, line %d: #%s\n",
348 file->i_file, filep->f_line, directives[ret]));
349 /*
350 * nothing to do.
351 */
352 break;
353 }
354 return(ret);
355}
356
357struct symtab *isdefined(symbol, file, srcfile)
358 register char *symbol;
359 struct inclist *file;
360 struct inclist **srcfile;
361{
362 register struct symtab *val;
363
364 if (val = slookup(symbol, &maininclist)) {
365 debug(1,("%s defined on command line\n", symbol));
366 if (srcfile != NULL) *srcfile = &maininclist;
367 return(val);
368 }
369 if (val = fdefined(symbol, file, srcfile))
370 return(val);
371 debug(1,("%s not defined in %s\n", symbol, file->i_file));
372 return(NULL);
373}
374
375struct symtab *fdefined(symbol, file, srcfile)
376 register char *symbol;
377 struct inclist *file;
378 struct inclist **srcfile;
379{
380 register struct inclist **ip;
381 register struct symtab *val;
382 register int i;
383 static int recurse_lvl = 0;
384
385 if (file->i_defchecked)
386 return(NULL);
387 file->i_defchecked = TRUE;
388 if (val = slookup(symbol, file))
389 debug(1,("%s defined in %s as %s\n", symbol, file->i_file, val->s_value));
390 if (val == NULL && file->i_list)
391 {
392 for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
393 if (val = fdefined(symbol, *ip, srcfile)) {
394 break;
395 }
396 }
397 else if (val != NULL && srcfile != NULL) *srcfile = file;
398 recurse_lvl--;
399 file->i_defchecked = FALSE;
400
401 return(val);
402}
403
404/*
405 * Return type based on if the #if expression evaluates to 0
406 */
407zero_value(exp, filep, file_red)
408 register char *exp;
409 register struct filepointer *filep;
410 register struct inclist *file_red;
411{
412 if (cppsetup(exp, filep, file_red))
413 return(IFFALSE);
414 else
415 return(IF);
416}
417
418define(def, file)
419 char *def;
420 struct inclist *file;
421{
422 char *val;
423
424 /* Separate symbol name and its value */
425 val = def;
426 while (isalnum(*val) || *val == '_')
427 val++;
428 if (*val)
429 *val++ = '\0';
430 while (*val == ' ' || *val == '\t')
431 val++;
432
433 if (!*val)
434 val = "1";
435 define2(def, val, file);
436}
437
438define2(name, val, file)
439 char *name, *val;
440 struct inclist *file;
441{
442 int first, last, below;
443 register struct symtab *sp = NULL, *dest;
444
445 /* Make space if it's needed */
446 if (file->i_defs == NULL)
447 {
448 file->i_defs = (struct symtab *)
449 malloc(sizeof (struct symtab) * SYMTABINC);
450 file->i_deflen = SYMTABINC;
451 file->i_ndefs = 0;
452 }
453 else if (file->i_ndefs == file->i_deflen)
454 file->i_defs = (struct symtab *)
455 realloc(file->i_defs,
456 sizeof(struct symtab)*(file->i_deflen+=SYMTABINC));
457
458 if (file->i_defs == NULL)
459 fatalerr("malloc()/realloc() failure in insert_defn()\n");
460
461 below = first = 0;
462 last = file->i_ndefs - 1;
463 while (last >= first)
464 {
465 /* Fast inline binary search */
466 register char *s1;
467 register char *s2;
468 register int middle = (first + last) / 2;
469
470 /* Fast inline strchr() */
471 s1 = name;
472 s2 = file->i_defs[middle].s_name;
473 while (*s1++ == *s2++)
474 if (s2[-1] == '\0') break;
475
476 /* If exact match, set sp and break */
477 if (*--s1 == *--s2)
478 {
479 sp = file->i_defs + middle;
480 break;
481 }
482
483 /* If name > i_defs[middle] ... */
484 if (*s1 > *s2)
485 {
486 below = first;
487 first = middle + 1;
488 }
489 /* else ... */
490 else
491 {
492 below = last = middle - 1;
493 }
494 }
495
496 /* Search is done. If we found an exact match to the symbol name,
497 just replace its s_value */
498 if (sp != NULL)
499 {
500 free(sp->s_value);
501 sp->s_value = copy(val);
502 return;
503 }
504
505 sp = file->i_defs + file->i_ndefs++;
506 dest = file->i_defs + below + 1;
507 while (sp > dest)
508 {
509 *sp = sp[-1];
510 sp--;
511 }
512 sp->s_name = copy(name);
513 sp->s_value = copy(val);
514}
515
516struct symtab *slookup(symbol, file)
517 register char *symbol;
518 register struct inclist *file;
519{
520 register int first = 0;
521 register int last = file->i_ndefs - 1;
522
523 if (file) while (last >= first)
524 {
525 /* Fast inline binary search */
526 register char *s1;
527 register char *s2;
528 register int middle = (first + last) / 2;
529
530 /* Fast inline strchr() */
531 s1 = symbol;
532 s2 = file->i_defs[middle].s_name;
533 while (*s1++ == *s2++)
534 if (s2[-1] == '\0') break;
535
536 /* If exact match, we're done */
537 if (*--s1 == *--s2)
538 {
539 return file->i_defs + middle;
540 }
541
542 /* If symbol > i_defs[middle] ... */
543 if (*s1 > *s2)
544 {
545 first = middle + 1;
546 }
547 /* else ... */
548 else
549 {
550 last = middle - 1;
551 }
552 }
553 return(NULL);
554}
555
556undefine(symbol, file)
557 char *symbol;
558 register struct inclist *file;
559{
560 register struct symtab *ptr;
561 struct inclist *srcfile;
562 while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
563 {
564 srcfile->i_ndefs--;
565 for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
566 *ptr = ptr[1];
567 }
568}