1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * preprocessor library control interface
26 */
27
28 #include "pplib.h"
29 #include "pptab.h"
30
31 #include <ls.h>
32
33 #define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab)
34 #define REFALL (pp.truncate?pp.dirtab:pp.symtab)
35
36 #define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
37
38 /*
39 * set option value
40 * initialization files have lowest precedence
41 */
42
43 int
ppset(register long * p,register long op,int val)44 ppset(register long* p, register long op, int val)
45 {
46 long* r;
47
48 r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
49 if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & op))
50 {
51 debug((-7, "set %s %s skipped -- readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
52 return 0;
53 }
54 if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN)) && (p != &pp.mode || !(op & BUILTIN)) && (p != &pp.option || !(op & PREDEFINED)))
55 {
56 *r |= op;
57 debug((-7, "set %s %s readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
58 }
59 if (val)
60 *p |= op;
61 else
62 *p &= ~op;
63 debug((-7, "set %s %s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
64 return 1;
65 }
66
67 /*
68 * initialize hash table with keywords from key
69 */
70
71 static void
inithash(register Hash_table_t * tab,register struct ppkeyword * key)72 inithash(register Hash_table_t* tab, register struct ppkeyword* key)
73 {
74 register char* s;
75
76 for (; s = key->name; key++)
77 {
78 if (!ppisid(*s))
79 s++;
80 hashput(tab, s, key->value);
81 }
82 }
83
84 /*
85 * return ppkeyword table name given value
86 */
87
88 char*
ppkeyname(register int value,int dir)89 ppkeyname(register int value, int dir)
90 {
91 register char* s;
92 register struct ppkeyword* p;
93
94 if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
95 {
96 s = (p + (value - p->value))->name;
97 return s + !ppisid(*s);
98 }
99 #if DEBUG
100 error(PANIC, "no keyword table name for value=%d", value);
101 #endif
102 return "UNKNOWN";
103 }
104
105 /*
106 * add to the include maps
107 */
108
109 void
ppmapinclude(char * file,register char * s)110 ppmapinclude(char* file, register char* s)
111 {
112 register int c;
113 register struct ppdirs* dp;
114 int fd;
115 int flags;
116 int index;
117 int token;
118 char* t;
119 char* old_file;
120 long old_state;
121 struct ppfile* fp;
122 struct ppfile* mp;
123
124 old_file = error_info.file;
125 old_state = pp.state;
126 if (s)
127 PUSH_BUFFER("mapinclude", s, 1);
128 else if (file)
129 {
130 if (*file == '-')
131 {
132 if (!error_info.file)
133 {
134 error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
135 return;
136 }
137 s = t = strcopy(pp.tmpbuf, error_info.file);
138 c = *++file;
139 for (;;)
140 {
141 if (s <= pp.tmpbuf || *s == '/')
142 {
143 s = t;
144 break;
145 }
146 else if (*s == c)
147 break;
148 s--;
149 }
150 strcpy(s, file);
151 file = pp.tmpbuf;
152 }
153 if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
154 return;
155 PUSH_FILE(file, fd);
156 }
157 else
158 return;
159 #if CATSTRINGS
160 pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
161 #else
162 pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
163 #endif
164 pp.level++;
165 flags = INC_MAPALL;
166 fp = mp = 0;
167 for (;;)
168 {
169 switch (token = pplex())
170 {
171 case 0:
172 case T_STRING:
173 case T_HEADER:
174 if (fp)
175 {
176 fp->guard = INC_IGNORE;
177 for (dp = pp.firstdir->next; dp; dp = dp->next)
178 if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
179 {
180 ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
181 break;
182 }
183 }
184 if (!token)
185 break;
186 pathcanon(pp.token, 0, 0);
187 fp = ppsetfile(pp.token);
188 if (mp)
189 {
190 mp->flags |= flags;
191 if (streq(fp->name, "."))
192 mp->flags |= INC_MAPNOLOCAL;
193 else
194 mp->bound[index] = fp;
195
196 fp = mp = 0;
197 }
198 else
199 index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
200 continue;
201 case '=':
202 if (!(mp = fp))
203 error(3, "%s: \"name\" = \"binding\" expected");
204 fp = 0;
205 continue;
206 case '\n':
207 continue;
208 case T_ID:
209 if (streq(pp.token, "all"))
210 {
211 flags = INC_MAPALL;
212 continue;
213 }
214 else if (streq(pp.token, "hosted"))
215 {
216 flags = INC_MAPHOSTED;
217 continue;
218 }
219 else if (streq(pp.token, "nohosted"))
220 {
221 flags = INC_MAPNOHOSTED;
222 continue;
223 }
224 /*FALLTHROUGH*/
225 default:
226 error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
227 break;
228 }
229 break;
230 }
231 pp.level--;
232 error_info.file = old_file;
233 pp.state = old_state;
234 }
235
236 /*
237 * return non-0 if file is identical to fd
238 */
239
240 static int
identical(char * file,int fd)241 identical(char* file, int fd)
242 {
243 struct stat a;
244 struct stat b;
245
246 return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
247 }
248
249 /*
250 * compare up to pp.truncate chars
251 *
252 * NOTE: __STD* and symbols containing ' ' are not truncated
253 */
254
255 static int
trunccomp(register char * a,register char * b)256 trunccomp(register char* a, register char* b)
257 {
258 return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
259 }
260
261 /*
262 * hash up to pp.truncate chars
263 *
264 * NOTE: __STD* and symbols containing ' ' are not truncated
265 */
266
267 static unsigned int
trunchash(char * a)268 trunchash(char* a)
269 {
270 int n;
271
272 return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
273 }
274
275 #if DEBUG & TRACE_debug
276 /*
277 * append context to debug trace
278 */
279
280 static int
context(Sfio_t * sp,int level,int flags)281 context(Sfio_t* sp, int level, int flags)
282 {
283 static int state;
284
285 NoP(level);
286 NoP(flags);
287 if (error_info.trace <= -10 && pp.state != state)
288 {
289 state = pp.state;
290 sfprintf(sp, " %s", ppstatestr(pp.state));
291 }
292 return 1;
293 }
294 #endif
295
296 /*
297 * reset include guard
298 */
299
300 static int
unguard(const char * name,char * v,void * handle)301 unguard(const char* name, char* v, void* handle)
302 {
303 register struct ppfile* fp = (struct ppfile*)v;
304
305 fp->guard = 0;
306 return 0;
307 }
308
309 /*
310 * reset macro definition
311 */
312
313 static void
undefine(void * p)314 undefine(void* p)
315 {
316 struct ppmacro* mac = ((struct ppsymbol*)p)->macro;
317
318 if (mac)
319 {
320 if (mac->formals)
321 free(mac->formals);
322 free(mac->value);
323 free(mac);
324 }
325 }
326
327 /*
328 * return non-zero if its ok to ppop(op)
329 */
330
331 static int
ppok(int op)332 ppok(int op)
333 {
334 long n;
335 long* r;
336
337 r = &pp.ro_op[op >> 5];
338 n = 1L << op;
339 if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & n))
340 {
341 debug((-7, "set op %d index %d skipped -- readonly", op, op >> 5));
342 return 0;
343 }
344 else if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN)))
345 {
346 *r |= n;
347 debug((-7, "set op %d index %d readonly", op, op >> 5));
348 }
349 else
350 debug((-7, "set op %d index %d", op, op >> 5));
351 return 1;
352 }
353
354 /*
355 * pp operations
356 *
357 * NOTE: PP_INIT must be done before the first pplex() call
358 * PP_DONE must be done after the last pplex() call
359 * PP_INIT-PP_DONE must be done for each new PP_INPUT
360 */
361
362 void
ppop(int op,...)363 ppop(int op, ...)
364 {
365 va_list ap;
366 register char* p;
367 register struct ppkeyword* kp;
368 register char* s;
369 int c;
370 long n;
371 long* r __unused;
372 char* t;
373 struct ppdirs* dp;
374 struct ppdirs* hp;
375 struct ppsymkey* key;
376 struct oplist* xp;
377 Sfio_t* sp;
378 struct stat st;
379 PPCOMMENT ppcomment;
380 PPLINESYNC pplinesync;
381
382 static int initialized;
383
384 va_start(ap, op);
385 switch (op)
386 {
387 case PP_ASSERT:
388 case PP_DEFINE:
389 case PP_DIRECTIVE:
390 case PP_OPTION:
391 case PP_READ:
392 case PP_UNDEF:
393 if (pp.initialized)
394 goto before;
395 if ((p = va_arg(ap, char*)) && *p)
396 {
397 if (pp.lastop)
398 pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
399 else
400 pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
401 pp.lastop->op = op;
402 pp.lastop->value = p;
403 }
404 break;
405 case PP_BUILTIN:
406 pp.builtin = va_arg(ap, PPBUILTIN);
407 break;
408 case PP_CDIR:
409 p = va_arg(ap, char*);
410 c = va_arg(ap, int);
411 pp.cdir.path = 0;
412 if (!p)
413 pp.c = c;
414 else if (streq(p, "-"))
415 {
416 pp.c = c;
417 for (dp = pp.firstdir; dp; dp = dp->next)
418 dp->c = c;
419 }
420 else if (!pp.c)
421 {
422 if (!*p || stat((pathcanon(p, 0, 0), p), &st))
423 pp.c = c;
424 else
425 {
426 for (dp = pp.firstdir; dp; dp = dp->next)
427 {
428 if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
429 pp.c = 1;
430 dp->c = pp.c == 1;
431 }
432 if (!pp.c)
433 {
434 pp.cdir.path = p;
435 SAVEID(&pp.cdir.id, &st);
436 }
437 }
438 }
439 break;
440 case PP_CHOP:
441 if (p = va_arg(ap, char*))
442 {
443 c = strlen(p);
444 xp = newof(0, struct oplist, 1, c + 1);
445 xp->value = ((char*)xp) + sizeof(struct oplist);
446 s = xp->value;
447 c = *p++;
448 while (*p && *p != c)
449 *s++ = *p++;
450 *s++ = '/';
451 xp->op = s - xp->value;
452 *s++ = 0;
453 if (*p && *++p && *p != c)
454 {
455 while (*p && *p != c)
456 *s++ = *p++;
457 *s++ = '/';
458 }
459 *s = 0;
460 xp->next = pp.chop;
461 pp.chop = xp;
462 }
463 break;
464 case PP_COMMENT:
465 if (pp.comment = va_arg(ap, PPCOMMENT))
466 pp.flags |= PP_comment;
467 else
468 pp.flags &= ~PP_comment;
469 break;
470 case PP_COMPATIBILITY:
471 if (ppset(&pp.state, COMPATIBILITY, va_arg(ap, int)))
472 {
473 #if COMPATIBLE
474 if (pp.initialized)
475 ppfsm(FSM_COMPATIBILITY, NiL);
476 #else
477 if (pp.state & COMPATIBILITY)
478 error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
479 #endif
480 if (pp.state & COMPATIBILITY)
481 pp.flags |= PP_compatibility;
482 else
483 pp.flags &= ~PP_compatibility;
484 }
485 break;
486 case PP_COMPILE:
487 if (pp.initialized)
488 goto before;
489 pp.state |= COMPILE;
490 if (!pp.symtab)
491 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
492 if (kp = va_arg(ap, struct ppkeyword*))
493 for (; s = kp->name; kp++)
494 {
495 n = SYM_LEX;
496 switch (*s)
497 {
498 case '-':
499 s++;
500 break;
501 case '+':
502 s++;
503 if (!(pp.option & PLUSPLUS))
504 break;
505 /*FALLTHROUGH*/
506 default:
507 n |= SYM_KEYWORD;
508 break;
509 }
510 if (key = ppkeyset(pp.symtab, s))
511 {
512 key->sym.flags = n;
513 key->lex = kp->value;
514 }
515 }
516 break;
517 case PP_DEBUG:
518 error_info.trace = va_arg(ap, int);
519 break;
520 case PP_DEFAULT:
521 if (p = va_arg(ap, char*))
522 p = strdup(p);
523 if (pp.ppdefault)
524 free(pp.ppdefault);
525 pp.ppdefault = p;
526 break;
527 case PP_DONE:
528 #if CHECKPOINT
529 if (pp.mode & DUMP)
530 ppdump();
531 #endif
532 if (pp.mode & FILEDEPS)
533 {
534 sfputc(pp.filedeps.sp, '\n');
535 if (pp.filedeps.sp == sfstdout)
536 sfsync(pp.filedeps.sp);
537 else
538 sfclose(pp.filedeps.sp);
539 }
540 if (pp.state & STANDALONE)
541 {
542 if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
543 ppputchar('\n');
544 ppflushout();
545 }
546 error_info.file = 0;
547 break;
548 case PP_DUMP:
549 ppset(&pp.mode, DUMP, va_arg(ap, int));
550 #if !CHECKPOINT
551 if (pp.mode & DUMP)
552 error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
553 #endif
554 break;
555 case PP_FILEDEPS:
556 if (n = va_arg(ap, int))
557 pp.filedeps.flags |= n;
558 else
559 pp.filedeps.flags = 0;
560 break;
561 case PP_FILENAME:
562 error_info.file = va_arg(ap, char*);
563 break;
564 case PP_HOSTDIR:
565 if (!(pp.mode & INIT))
566 pp.ro_mode |= HOSTED;
567 else if (pp.ro_mode & HOSTED)
568 break;
569 pp.ro_mode |= INIT;
570 p = va_arg(ap, char*);
571 c = va_arg(ap, int);
572 pp.hostdir.path = 0;
573 if (!p)
574 pp.hosted = c;
575 else if (streq(p, "-"))
576 {
577 if (pp.initialized)
578 ppset(&pp.mode, HOSTED, c);
579 else
580 {
581 pp.hosted = c ? 1 : 2;
582 for (dp = pp.firstdir; dp; dp = dp->next)
583 if (pp.hosted == 1)
584 dp->type |= TYPE_HOSTED;
585 else
586 dp->type &= ~TYPE_HOSTED;
587 }
588 }
589 else if (!pp.hosted)
590 {
591 if (!*p || stat((pathcanon(p, 0, 0), p), &st))
592 pp.hosted = 1;
593 else
594 {
595 for (dp = pp.firstdir; dp; dp = dp->next)
596 {
597 if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
598 pp.hosted = 1;
599 if (pp.hosted == 1)
600 dp->type |= TYPE_HOSTED;
601 else
602 dp->type &= ~TYPE_HOSTED;
603 }
604 if (!pp.hosted)
605 {
606 pp.hostdir.path = p;
607 SAVEID(&pp.hostdir.id, &st);
608 }
609 }
610 }
611 break;
612 case PP_ID:
613 p = va_arg(ap, char*);
614 c = va_arg(ap, int);
615 if (p)
616 ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
617 break;
618 case PP_IGNORE:
619 if (p = va_arg(ap, char*))
620 {
621 pathcanon(p, 0, 0);
622 ppsetfile(p)->guard = INC_IGNORE;
623 message((-3, "%s: ignore", p));
624 }
625 break;
626 case PP_IGNORELIST:
627 if (pp.initialized)
628 goto before;
629 pp.ignore = va_arg(ap, char*);
630 break;
631 case PP_INCLUDE:
632 if ((p = va_arg(ap, char*)) && *p)
633 {
634 pathcanon(p, 0, 0);
635 if (stat(p, &st))
636 break;
637 for (dp = pp.stddirs; dp = dp->next;)
638 if (dp->name && SAMEID(&dp->id, &st))
639 break;
640 if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
641 {
642 pp.cdir.path = 0;
643 pp.c = 1;
644 }
645 if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
646 {
647 pp.hostdir.path = 0;
648 pp.hosted = 1;
649 }
650 if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
651 pp.hosted = 1;
652 c = dp && dp->c || pp.c == 1;
653 n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
654 if (!dp || dp == pp.lastdir->next)
655 {
656 if (dp)
657 {
658 c = dp->c;
659 n = dp->type & TYPE_HOSTED;
660 }
661 dp = newof(0, struct ppdirs, 1, 0);
662 dp->name = p;
663 SAVEID(&dp->id, &st);
664 dp->type |= TYPE_INCLUDE;
665 dp->index = INC_LOCAL + pp.ignoresrc != 0;
666 dp->next = pp.lastdir->next;
667 pp.lastdir = pp.lastdir->next = dp;
668 }
669 dp->c = c;
670 if (n)
671 dp->type |= TYPE_HOSTED;
672 else
673 dp->type &= ~TYPE_HOSTED;
674 }
675 break;
676 case PP_INCREF:
677 pp.incref = va_arg(ap, PPINCREF);
678 break;
679 case PP_RESET:
680 pp.reset.on = 1;
681 break;
682 case PP_INIT:
683 if (pp.initialized)
684 {
685 error_info.errors = 0;
686 error_info.warnings = 0;
687 }
688 else
689 {
690 /*
691 * context initialization
692 */
693
694 if (!initialized)
695 {
696 /*
697 * out of malloc is fatal
698 */
699
700 memfatal();
701
702 /*
703 * initialize the error message interface
704 */
705
706 error_info.version = (char*)pp.version;
707 #if DEBUG & TRACE_debug
708 error_info.auxilliary = context;
709 pptrace(0);
710 #endif
711
712 /*
713 * initialize pplex tables
714 */
715
716 ppfsm(FSM_INIT, NiL);
717
718 /*
719 * fixed macro stack size -- room for improvement
720 */
721
722 pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
723 pp.macp->next = pp.macp + 1;
724 pp.maxmac = (char*)pp.macp + DEFMACSTACK;
725 initialized = 1;
726
727 /*
728 * initial include/if control stack
729 */
730
731 pp.control = newof(0, long, pp.constack, 0);
732 pp.maxcon = pp.control + pp.constack - 1;
733 }
734
735 /*
736 * validate modes
737 */
738
739 switch (pp.arg_mode)
740 {
741 case 'a':
742 case 'C':
743 ppop(PP_COMPATIBILITY, 0);
744 ppop(PP_TRANSITION, 1);
745 break;
746 case 'A':
747 case 'c':
748 ppop(PP_COMPATIBILITY, 0);
749 ppop(PP_STRICT, 1);
750 break;
751 case 'f':
752 ppop(PP_COMPATIBILITY, 1);
753 ppop(PP_PLUSPLUS, 1);
754 ppop(PP_TRANSITION, 1);
755 break;
756 case 'F':
757 ppop(PP_COMPATIBILITY, 0);
758 ppop(PP_PLUSPLUS, 1);
759 break;
760 case 'k':
761 case 's':
762 ppop(PP_COMPATIBILITY, 1);
763 ppop(PP_STRICT, 1);
764 break;
765 case 'o':
766 case 'O':
767 ppop(PP_COMPATIBILITY, 1);
768 ppop(PP_TRANSITION, 0);
769 break;
770 case 't':
771 ppop(PP_COMPATIBILITY, 1);
772 ppop(PP_TRANSITION, 1);
773 break;
774 }
775 if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
776 ppop(PP_PEDANTIC, 1);
777 if (pp.state & PASSTHROUGH)
778 {
779 if (pp.state & COMPILE)
780 {
781 pp.state &= ~PASSTHROUGH;
782 error(1, "passthrough ignored for compile");
783 }
784 else
785 {
786 ppop(PP_COMPATIBILITY, 1);
787 ppop(PP_HOSTDIR, "-", 1);
788 ppop(PP_SPACEOUT, 1);
789 ppset(&pp.state, DISABLE, va_arg(ap, int));
790 }
791 }
792
793 /*
794 * create the hash tables
795 */
796
797 if (!pp.symtab)
798 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
799 if (!pp.dirtab)
800 {
801 pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
802 inithash(pp.dirtab, directives);
803 }
804 if (!pp.filtab)
805 pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
806 if (!pp.prdtab)
807 pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
808 if (!pp.strtab)
809 {
810 pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
811 inithash(pp.strtab, options);
812 inithash(pp.strtab, predicates);
813 inithash(pp.strtab, variables);
814 }
815 pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
816 pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
817
818 /*
819 * mark macros that are builtin predicates
820 */
821
822 for (kp = predicates; s = kp->name; kp++)
823 {
824 if (!ppisid(*s))
825 s++;
826 ppassert(DEFINE, s, 0);
827 }
828
829 /*
830 * the remaining entry names must be allocated
831 */
832
833 hashset(pp.dirtab, HASH_ALLOCATE);
834 hashset(pp.filtab, HASH_ALLOCATE);
835 hashset(pp.prdtab, HASH_ALLOCATE);
836 hashset(pp.strtab, HASH_ALLOCATE);
837 hashset(pp.symtab, HASH_ALLOCATE);
838 if (pp.test & TEST_nonoise)
839 {
840 c = error_info.trace;
841 error_info.trace = 0;
842 }
843 #if DEBUG
844 if (!(pp.test & TEST_noinit))
845 {
846 #endif
847
848 /*
849 * compose, push and read the builtin initialization script
850 */
851
852 if (!(sp = sfstropen()))
853 error(3, "temporary buffer allocation error");
854 sfprintf(sp,
855 "\
856 #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
857 #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
858 ",
859 dirname(PRAGMA),
860 pp.pass,
861 keyname(X_MAP),
862 dirname(DEFINE),
863 dirname(PRAGMA),
864 pp.pass,
865 keyname(X_MAP),
866 dirname(UNDEF));
867 if (pp.ppdefault && *pp.ppdefault)
868 {
869 if (pp.probe)
870 {
871 c = pp.lastdir->next->type;
872 pp.lastdir->next->type = 0;
873 }
874 if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
875 {
876 free(pp.ppdefault);
877 if (!(pp.ppdefault = pathprobe("C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0, pp.path, MAXTOKEN + 1, NiL, 0)))
878 error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
879 }
880 if (pp.probe)
881 pp.lastdir->next->type = c;
882 }
883 while (pp.firstop)
884 {
885 switch (pp.firstop->op)
886 {
887 case PP_ASSERT:
888 sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
889 break;
890 case PP_DEFINE:
891 if (*pp.firstop->value == '#')
892 sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
893 else
894 {
895 if (s = strchr(pp.firstop->value, '='))
896 sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
897 else
898 sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
899 }
900 break;
901 case PP_DIRECTIVE:
902 sfprintf(sp, "#%s\n", pp.firstop->value);
903 break;
904 case PP_OPTION:
905 if (s = strchr(pp.firstop->value, '='))
906 sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
907 else
908 sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
909 break;
910 case PP_READ:
911 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
912 break;
913 case PP_UNDEF:
914 sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
915 break;
916 }
917 pp.lastop = pp.firstop;
918 pp.firstop = pp.firstop->next;
919 free(pp.lastop);
920 }
921 sfprintf(sp,
922 "\
923 #%s %s:%s\n\
924 #%s %s:%s\n\
925 #%s !#%s(%s)\n\
926 #%s !#%s(%s) || #%s(%s)\n\
927 "
928 , dirname(PRAGMA)
929 , pp.pass
930 , keyname(X_BUILTIN)
931 , dirname(PRAGMA)
932 , pp.pass
933 , keyname(X_PREDEFINED)
934 , dirname(IF)
935 , keyname(X_OPTION)
936 , keyname(X_PLUSPLUS)
937 , dirname(IF)
938 , keyname(X_OPTION)
939 , keyname(X_COMPATIBILITY)
940 , keyname(X_OPTION)
941 , keyname(X_TRANSITION)
942 );
943 sfprintf(sp,
944 "\
945 #%s #%s(%s)\n\
946 #%s %s:%s\n\
947 #%s %s:%s\n\
948 #%s __STRICT__ 1\n\
949 #%s\n\
950 #%s\n\
951 "
952 , dirname(IF)
953 , keyname(X_OPTION)
954 , keyname(X_STRICT)
955 , dirname(PRAGMA)
956 , pp.pass
957 , keyname(X_ALLMULTIPLE)
958 , dirname(PRAGMA)
959 , pp.pass
960 , keyname(X_READONLY)
961 , dirname(DEFINE)
962 , dirname(ENDIF)
963 , dirname(ENDIF)
964 );
965 for (kp = readonlys; s = kp->name; kp++)
966 {
967 if (!ppisid(*s))
968 s++;
969 sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
970 }
971 sfprintf(sp,
972 "\
973 #%s\n\
974 #%s __STDPP__ 1\n\
975 #%s %s:no%s\n\
976 "
977 , dirname(ENDIF)
978 , dirname(DEFINE)
979 , dirname(PRAGMA)
980 , pp.pass
981 , keyname(X_PREDEFINED)
982 );
983 if (!pp.truncate)
984 sfprintf(sp,
985 "\
986 #%s __STDPP__directive #(%s)\n\
987 "
988 , dirname(DEFINE)
989 , keyname(V_DIRECTIVE)
990 );
991 for (kp = variables; s = kp->name; kp++)
992 if (ppisid(*s) || *s++ == '+')
993 {
994 t = *s == '_' ? "" : "__";
995 sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
996 }
997 sfprintf(sp,
998 "\
999 #%s %s:no%s\n\
1000 #%s %s:no%s\n\
1001 "
1002 , dirname(PRAGMA)
1003 , pp.pass
1004 , keyname(X_READONLY)
1005 , dirname(PRAGMA)
1006 , pp.pass
1007 , keyname(X_BUILTIN)
1008 );
1009 if (pp.ppdefault && *pp.ppdefault)
1010 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
1011 sfprintf(sp,
1012 "\
1013 #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
1014 #%s __STDC__ #(STDC)\n\
1015 #%s\n\
1016 "
1017 , dirname(IF)
1018 , dirname(DEFINE)
1019 , dirname(ENDIF)
1020 );
1021 t = sfstruse(sp);
1022 debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
1023 ppcomment = pp.comment;
1024 pp.comment = 0;
1025 pplinesync = pp.linesync;
1026 pp.linesync = 0;
1027 PUSH_INIT(pp.pass, t);
1028 pp.mode |= INIT;
1029 while (pplex());
1030 pp.mode &= ~INIT;
1031 pp.comment = ppcomment;
1032 pp.linesync = pplinesync;
1033 pp.prefix = 0;
1034 sfstrclose(sp);
1035 if (error_info.trace)
1036 for (dp = pp.firstdir; dp; dp = dp->next)
1037 message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
1038 #if DEBUG
1039 }
1040 if (pp.test & TEST_nonoise)
1041 error_info.trace = c;
1042 #endif
1043 {
1044 /*
1045 * this is sleazy but at least it's
1046 * hidden in the library
1047 */
1048 #include <preroot.h>
1049 #if FS_PREROOT
1050 struct pplist* preroot;
1051
1052 if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
1053 setpreroot(NiL, preroot->value);
1054 #endif
1055 }
1056 if (pp.ignoresrc)
1057 {
1058 if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
1059 error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
1060 pp.lcldirs = pp.lcldirs->next;
1061 }
1062 if (pp.ignore)
1063 {
1064 if (*pp.ignore)
1065 ppmapinclude(pp.ignore, NiL);
1066 else
1067 pp.ignore = 0;
1068 }
1069 if (pp.standalone)
1070 pp.state |= STANDALONE;
1071 #if COMPATIBLE
1072 ppfsm(FSM_COMPATIBILITY, NiL);
1073 #endif
1074 ppfsm(FSM_PLUSPLUS, NiL);
1075 pp.initialized = 1;
1076 if (pp.reset.on)
1077 {
1078 pp.reset.symtab = pp.symtab;
1079 pp.symtab = 0;
1080 pp.reset.ro_state = pp.ro_state;
1081 pp.reset.ro_mode = pp.ro_mode;
1082 pp.reset.ro_option = pp.ro_option;
1083 }
1084 }
1085 if (pp.reset.on)
1086 {
1087 if (pp.symtab)
1088 {
1089 hashwalk(pp.filtab, 0, unguard, NiL);
1090 hashfree(pp.symtab);
1091 }
1092 pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
1093 hashview(pp.symtab, pp.reset.symtab);
1094 pp.ro_state = pp.reset.ro_state;
1095 pp.ro_mode = pp.reset.ro_mode;
1096 pp.ro_option = pp.reset.ro_option;
1097 }
1098 #if CHECKPOINT
1099 if (pp.mode & DUMP)
1100 {
1101 if (!pp.pragma)
1102 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
1103 (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
1104 }
1105 #endif
1106 if (n = pp.filedeps.flags)
1107 {
1108 if (!(n & PP_deps_file))
1109 {
1110 pp.state |= NOTEXT;
1111 pp.option |= KEEPNOTEXT;
1112 pp.linesync = 0;
1113 }
1114 if (n & PP_deps_generated)
1115 pp.mode |= GENDEPS;
1116 if (n & PP_deps_local)
1117 pp.mode &= ~HEADERDEPS;
1118 else if (!(pp.mode & FILEDEPS))
1119 pp.mode |= HEADERDEPS;
1120 pp.mode |= FILEDEPS;
1121 }
1122
1123 /*
1124 * push the main input file -- special case for hosted mark
1125 */
1126
1127 if (pp.firstdir->type & TYPE_HOSTED)
1128 pp.mode |= MARKHOSTED;
1129 else
1130 pp.mode &= ~MARKHOSTED;
1131 #if CHECKPOINT
1132 if (!(pp.mode & DUMP))
1133 #endif
1134 {
1135 if (!(p = error_info.file))
1136 p = "";
1137 else
1138 {
1139 error_info.file = 0;
1140 if (*p)
1141 {
1142 pathcanon(p, 0, 0);
1143 p = ppsetfile(p)->name;
1144 }
1145 }
1146 PUSH_FILE(p, 0);
1147 }
1148 if (pp.mode & FILEDEPS)
1149 {
1150 if (s = strrchr(error_info.file, '/'))
1151 s++;
1152 else
1153 s = error_info.file;
1154 if (!*s)
1155 s = "-";
1156 s = strcpy(pp.tmpbuf, s);
1157 if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
1158 {
1159 if (c = *++p)
1160 while (*++p == c);
1161 if (*p)
1162 t = 0;
1163 else
1164 t++;
1165 }
1166 if (!t)
1167 {
1168 t = s + strlen(s);
1169 *t++ = '.';
1170 }
1171 *(t + 1) = 0;
1172 if (pp.state & NOTEXT)
1173 pp.filedeps.sp = sfstdout;
1174 else
1175 {
1176 *t = 'd';
1177 if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
1178 error(ERROR_SYSTEM|3, "%s: cannot create", s);
1179 }
1180 *t = 'o';
1181 pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
1182 if (*error_info.file)
1183 pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
1184 }
1185 if (xp = pp.firsttx)
1186 {
1187 if (!(sp = sfstropen()))
1188 error(3, "temporary buffer allocation error");
1189 while (xp)
1190 {
1191 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
1192 xp = xp->next;
1193 }
1194 t = sfstruse(sp);
1195 PUSH_BUFFER("options", t, 1);
1196 sfstrclose(sp);
1197 }
1198 break;
1199 case PP_INPUT:
1200 #if CHECKPOINT && POOL
1201 if (!(pp.mode & DUMP) || pp.pool.input)
1202 #else
1203 #if CHECKPOINT
1204 if (!(pp.mode & DUMP))
1205 #else
1206 #if POOL
1207 if (pp.pool.input)
1208 #endif
1209 #endif
1210 #endif
1211 {
1212 p = va_arg(ap, char*);
1213 if (!error_info.file)
1214 error_info.file = p;
1215 close(0);
1216 if (open(p, O_RDONLY) != 0)
1217 error(ERROR_SYSTEM|3, "%s: cannot read", p);
1218 if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
1219 {
1220 ppset(&pp.mode, CATLITERAL, 0);
1221 ppop(PP_SPACEOUT, 1);
1222 }
1223 break;
1224 }
1225 /*FALLTHROUGH*/
1226 case PP_TEXT:
1227 if (pp.initialized)
1228 goto before;
1229 if ((p = va_arg(ap, char*)) && *p)
1230 {
1231 if (pp.lasttx)
1232 pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
1233 else
1234 pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
1235 pp.lasttx->op = op;
1236 pp.lasttx->value = p;
1237 }
1238 break;
1239 case PP_KEYARGS:
1240 if (pp.initialized)
1241 goto before;
1242 ppset(&pp.option, KEYARGS, va_arg(ap, int));
1243 if (pp.option & KEYARGS)
1244 #if MACKEYARGS
1245 ppset(&pp.mode, CATLITERAL, 1);
1246 #else
1247 error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1248 #endif
1249 break;
1250 case PP_LINE:
1251 if (ppok(op))
1252 pp.linesync = va_arg(ap, PPLINESYNC);
1253 break;
1254 case PP_LINEBASE:
1255 if (ppok(op))
1256 {
1257 if (va_arg(ap, int))
1258 pp.flags |= PP_linebase;
1259 else
1260 pp.flags &= ~PP_linebase;
1261 }
1262 break;
1263 case PP_LINEFILE:
1264 if (ppok(op))
1265 {
1266 if (va_arg(ap, int))
1267 pp.flags |= PP_linefile;
1268 else
1269 pp.flags &= ~PP_linefile;
1270 }
1271 break;
1272 case PP_LINEID:
1273 if (ppok(op))
1274 {
1275 if (!(p = va_arg(ap, char*)))
1276 pp.lineid = "";
1277 else if (*p != '-')
1278 pp.lineid = strdup(p);
1279 else
1280 pp.option |= IGNORELINE;
1281 }
1282 break;
1283 case PP_LINETYPE:
1284 if (ppok(op))
1285 {
1286 if ((n = va_arg(ap, int)) >= 1)
1287 pp.flags |= PP_linetype;
1288 else
1289 pp.flags &= ~PP_linetype;
1290 if (n >= 2)
1291 pp.flags |= PP_linehosted;
1292 else
1293 pp.flags &= ~PP_linehosted;
1294 }
1295 break;
1296 case PP_LOCAL:
1297 if (pp.initialized)
1298 goto before;
1299 pp.ignoresrc++;
1300 pp.stddirs = pp.lastdir;
1301 if (!(pp.ro_option & PREFIX))
1302 pp.option &= ~PREFIX;
1303 break;
1304 case PP_MACREF:
1305 pp.macref = va_arg(ap, PPMACREF);
1306 break;
1307 case PP_MULTIPLE:
1308 ppset(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
1309 break;
1310 case PP_NOHASH:
1311 ppset(&pp.option, NOHASH, va_arg(ap, int));
1312 break;
1313 case PP_NOISE:
1314 op = va_arg(ap, int);
1315 ppset(&pp.option, NOISE, op);
1316 ppset(&pp.option, NOISEFILTER, op < 0);
1317 break;
1318 case PP_OPTARG:
1319 pp.optarg = va_arg(ap, PPOPTARG);
1320 break;
1321 case PP_OUTPUT:
1322 pp.outfile = va_arg(ap, char*);
1323 if (identical(pp.outfile, 0))
1324 error(3, "%s: identical to input", pp.outfile);
1325 close(1);
1326 if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
1327 error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
1328 break;
1329 case PP_PASSTHROUGH:
1330 if (!(pp.state & COMPILE))
1331 ppset(&pp.state, PASSTHROUGH, va_arg(ap, int));
1332 break;
1333 case PP_PEDANTIC:
1334 ppset(&pp.mode, PEDANTIC, va_arg(ap, int));
1335 break;
1336 case PP_PLUSCOMMENT:
1337 if (ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized)
1338 ppfsm(FSM_PLUSPLUS, NiL);
1339 break;
1340 case PP_PLUSPLUS:
1341 if (ppset(&pp.option, PLUSPLUS, va_arg(ap, int)) && ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized)
1342 ppfsm(FSM_PLUSPLUS, NiL);
1343 break;
1344 case PP_POOL:
1345 if (pp.initialized)
1346 goto before;
1347 if (va_arg(ap, int))
1348 {
1349 #if POOL
1350 pp.pool.input = dup(0);
1351 pp.pool.output = dup(1);
1352 p = "/dev/null";
1353 if (!identical(p, 0))
1354 {
1355 if (!identical(p, 1))
1356 ppop(PP_OUTPUT, p);
1357 ppop(PP_INPUT, p);
1358 }
1359 #else
1360 error(3, "preprocessor not compiled with input pool enabled [POOL]");
1361 #endif
1362 }
1363 break;
1364 case PP_PRAGMA:
1365 pp.pragma = va_arg(ap, PPPRAGMA);
1366 break;
1367 case PP_PRAGMAFLAGS:
1368 if (p = va_arg(ap, char*))
1369 {
1370 n = OPT_GLOBAL;
1371 if (*p == '-')
1372 p++;
1373 else
1374 n |= OPT_PASS;
1375 if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
1376 pp.optflags[c] = n;
1377 }
1378 break;
1379 case PP_PROBE:
1380 pp.probe = va_arg(ap, char*);
1381 break;
1382 case PP_QUOTE:
1383 p = va_arg(ap, char*);
1384 c = va_arg(ap, int);
1385 if (p)
1386 ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
1387 break;
1388 case PP_REGUARD:
1389 ppset(&pp.option, REGUARD, va_arg(ap, int));
1390 break;
1391 case PP_RESERVED:
1392 if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
1393 {
1394 if (!(sp = sfstropen()))
1395 error(3, "temporary buffer allocation error");
1396 sfputr(sp, p, -1);
1397 p = sfstruse(sp);
1398 if (s = strchr(p, '='))
1399 *s++ = 0;
1400 else
1401 s = p;
1402 while (*s == '_')
1403 s++;
1404 for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
1405 if (*t == '_')
1406 *t = 0;
1407 else
1408 t = 0;
1409 op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
1410 if (pp.test & 0x0400)
1411 error(1, "reserved#1 `%s' %d", s, op);
1412 if (t)
1413 *t = '_';
1414 if (!(key = ppkeyget(pp.symtab, p)))
1415 key = ppkeyset(pp.symtab, NiL);
1416 else if (!(key->sym.flags & SYM_LEX))
1417 {
1418 struct ppsymbol tmp;
1419
1420 tmp = key->sym;
1421 hashlook(pp.symtab, p, HASH_DELETE, NiL);
1422 key = ppkeyset(pp.symtab, NiL);
1423 key->sym.flags = tmp.flags;
1424 key->sym.macro = tmp.macro;
1425 key->sym.value = tmp.value;
1426 key->sym.hidden = tmp.hidden;
1427 }
1428 if (!(key->sym.flags & SYM_KEYWORD))
1429 {
1430 key->sym.flags |= SYM_KEYWORD|SYM_LEX;
1431 key->lex = op;
1432 if (pp.test & 0x0400)
1433 error(1, "reserved#2 `%s' %d", p, op);
1434 }
1435 sfstrclose(sp);
1436 }
1437 break;
1438 case PP_SPACEOUT:
1439 ppset(&pp.state, SPACEOUT, va_arg(ap, int));
1440 break;
1441 case PP_STANDALONE:
1442 if (pp.initialized)
1443 goto before;
1444 pp.standalone = 1;
1445 break;
1446 case PP_STANDARD:
1447 if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
1448 SAVEID(&pp.lastdir->next->id, &st);
1449 for (dp = pp.firstdir; dp; dp = dp->next)
1450 if (dp->name)
1451 for (hp = pp.firstdir; hp != dp; hp = hp->next)
1452 if (hp->name && SAMEID(&hp->id, &dp->id))
1453 {
1454 hp->c = dp->c;
1455 if (dp->type & TYPE_HOSTED)
1456 hp->type |= TYPE_HOSTED;
1457 else
1458 hp->type &= ~TYPE_HOSTED;
1459 }
1460 break;
1461 case PP_STRICT:
1462 if (ppset(&pp.state, STRICT, va_arg(ap, int)))
1463 {
1464 if (ppset(&pp.state, TRANSITION, 0))
1465 pp.flags &= ~PP_transition;
1466 if (pp.state & STRICT)
1467 pp.flags |= PP_strict;
1468 else
1469 pp.flags &= ~PP_strict;
1470 }
1471 break;
1472 case PP_TEST:
1473 if (p = va_arg(ap, char*))
1474 for (;;)
1475 {
1476 while (*p == ' ' || *p == '\t') p++;
1477 for (s = p; n = *s; s++)
1478 if (n == ',' || n == ' ' || n == '\t')
1479 {
1480 *s++ = 0;
1481 break;
1482 }
1483 if (!*p)
1484 break;
1485 n = 0;
1486 if (*p == 'n' && *(p + 1) == 'o')
1487 {
1488 p += 2;
1489 op = 0;
1490 }
1491 else
1492 op = 1;
1493 if (streq(p, "count"))
1494 n = TEST_count;
1495 else if (streq(p, "hashcount"))
1496 n = TEST_hashcount;
1497 else if (streq(p, "hashdump"))
1498 n = TEST_hashdump;
1499 else if (streq(p, "hit"))
1500 n = TEST_hit;
1501 else if (streq(p, "init"))
1502 n = TEST_noinit|TEST_INVERT;
1503 else if (streq(p, "noise"))
1504 n = TEST_nonoise|TEST_INVERT;
1505 else if (streq(p, "proto"))
1506 n = TEST_noproto|TEST_INVERT;
1507 else if (*p >= '0' && *p <= '9')
1508 n = strtoul(p, NiL, 0);
1509 else
1510 {
1511 error(1, "%s: unknown test", p);
1512 break;
1513 }
1514 if (n & TEST_INVERT)
1515 {
1516 n &= ~TEST_INVERT;
1517 op = !op;
1518 }
1519 if (op)
1520 pp.test |= n;
1521 else
1522 pp.test &= ~n;
1523 p = s;
1524 debug((-4, "test = 0%o", pp.test));
1525 }
1526 break;
1527 case PP_TRANSITION:
1528 if (ppset(&pp.state, TRANSITION, va_arg(ap, int)))
1529 {
1530 if (ppset(&pp.state, STRICT, 0))
1531 pp.flags &= ~PP_strict;
1532 if (pp.state & TRANSITION)
1533 pp.flags |= PP_transition;
1534 else
1535 pp.flags &= ~PP_transition;
1536 }
1537 break;
1538 case PP_TRUNCATE:
1539 if (pp.initialized)
1540 goto before;
1541 if ((op = va_arg(ap, int)) < 0)
1542 op = 0;
1543 ppset(&pp.option, TRUNCATE, op);
1544 if (pp.option & TRUNCATE)
1545 {
1546 Hash_bucket_t* b;
1547 Hash_bucket_t* p;
1548 Hash_position_t* pos;
1549 Hash_table_t* tab;
1550
1551 pp.truncate = op;
1552 tab = pp.symtab;
1553 pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
1554 if (tab && (pos = hashscan(tab, 0)))
1555 {
1556 if (p = hashnext(pos))
1557 do
1558 {
1559 b = hashnext(pos);
1560 hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
1561 } while (p = b);
1562 hashdone(pos);
1563 }
1564 }
1565 else
1566 pp.truncate = 0;
1567 break;
1568 case PP_VENDOR:
1569 p = va_arg(ap, char*);
1570 c = va_arg(ap, int) != 0;
1571 if (!p || !*p)
1572 for (dp = pp.firstdir; dp; dp = dp->next)
1573 dp->type &= ~TYPE_VENDOR;
1574 else if (streq(p, "-"))
1575 {
1576 for (dp = pp.firstdir; dp; dp = dp->next)
1577 if (c)
1578 dp->type |= TYPE_VENDOR;
1579 else
1580 dp->type &= ~TYPE_VENDOR;
1581 }
1582 else if (!stat((pathcanon(p, 0, 0), p), &st))
1583 {
1584 c = 0;
1585 for (dp = pp.firstdir; dp; dp = dp->next)
1586 {
1587 if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
1588 c = 1;
1589 if (c)
1590 dp->type |= TYPE_VENDOR;
1591 else
1592 dp->type &= ~TYPE_VENDOR;
1593 }
1594 }
1595 break;
1596 case PP_WARN:
1597 ppset(&pp.state, WARN, va_arg(ap, int));
1598 break;
1599 before:
1600 error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
1601 break;
1602 default:
1603 error(3, "ppop(%d): invalid preprocessor operation", op);
1604 break;
1605 }
1606 va_end(ap);
1607 }
1608