8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libpp / common / ppop.c
blob16c0260cd23ec632f925c24bf5032066dc31cf4d
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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
22 * Glenn Fowler
23 * AT&T Research
25 * preprocessor library control interface
28 #include "pplib.h"
29 #include "pptab.h"
31 #include <ls.h>
33 #define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab)
34 #define REFALL (pp.truncate?pp.dirtab:pp.symtab)
36 #define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
39 * set option value
40 * initialization files have lowest precedence
43 static void
44 set(register long* p, register long op, int val)
46 long* r;
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))
51 if (!pp.initialized && !(pp.mode & INIT))
52 *r |= op;
53 if (val)
54 *p |= op;
55 else
56 *p &= ~op;
58 debug((-7, "set(%s)=%s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*p) : p == &pp.mode ? ppmodestr(*p) : ppoptionstr(*p)));
62 * initialize hash table with keywords from key
65 static void
66 inithash(register Hash_table_t* tab, register struct ppkeyword* key)
68 register char* s;
70 for (; s = key->name; key++)
72 if (!ppisid(*s))
73 s++;
74 hashput(tab, s, key->value);
79 * return ppkeyword table name given value
82 char*
83 ppkeyname(register int value, int dir)
85 register char* s;
86 register struct ppkeyword* p;
88 if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
90 s = (p + (value - p->value))->name;
91 return s + !ppisid(*s);
93 #if DEBUG
94 error(PANIC, "no keyword table name for value=%d", value);
95 #endif
96 return "UNKNOWN";
100 * add to the include maps
103 void
104 ppmapinclude(char* file, register char* s)
106 register int c;
107 register struct ppdirs* dp;
108 int fd;
109 int flags;
110 int index;
111 int token;
112 char* t;
113 char* old_file;
114 long old_state;
115 struct ppfile* fp;
116 struct ppfile* mp;
118 old_file = error_info.file;
119 old_state = pp.state;
120 if (s)
121 PUSH_BUFFER("mapinclude", s, 1);
122 else if (file)
124 if (*file == '-')
126 if (!error_info.file)
128 error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
129 return;
131 s = t = strcopy(pp.tmpbuf, error_info.file);
132 c = *++file;
133 for (;;)
135 if (s <= pp.tmpbuf || *s == '/')
137 s = t;
138 break;
140 else if (*s == c)
141 break;
142 s--;
144 strcpy(s, file);
145 file = pp.tmpbuf;
147 if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
148 return;
149 PUSH_FILE(file, fd);
151 else
152 return;
153 #if CATSTRINGS
154 pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
155 #else
156 pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
157 #endif
158 pp.level++;
159 flags = INC_MAPALL;
160 fp = mp = 0;
161 for (;;)
163 switch (token = pplex())
165 case 0:
166 case T_STRING:
167 case T_HEADER:
168 if (fp)
170 fp->guard = INC_IGNORE;
171 for (dp = pp.firstdir->next; dp; dp = dp->next)
172 if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
174 ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
175 break;
178 if (!token)
179 break;
180 pathcanon(pp.token, 0);
181 fp = ppsetfile(pp.token);
182 if (mp)
184 mp->flags |= flags;
185 if (streq(fp->name, "."))
186 mp->flags |= INC_MAPNOLOCAL;
187 else
188 mp->bound[index] = fp;
190 fp = mp = 0;
192 else
193 index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
194 continue;
195 case '=':
196 if (!(mp = fp))
197 error(3, "%s: \"name\" = \"binding\" expected");
198 fp = 0;
199 continue;
200 case '\n':
201 continue;
202 case T_ID:
203 if (streq(pp.token, "all"))
205 flags = INC_MAPALL;
206 continue;
208 else if (streq(pp.token, "hosted"))
210 flags = INC_MAPHOSTED;
211 continue;
213 else if (streq(pp.token, "nohosted"))
215 flags = INC_MAPNOHOSTED;
216 continue;
218 /*FALLTHROUGH*/
219 default:
220 error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
221 break;
223 break;
225 pp.level--;
226 error_info.file = old_file;
227 pp.state = old_state;
231 * return non-0 if file is identical to fd
234 static int
235 identical(char* file, int fd)
237 struct stat a;
238 struct stat b;
240 return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
244 * compare up to pp.truncate chars
246 * NOTE: __STD* and symbols containing ' ' are not truncated
249 static int
250 trunccomp(register char* a, register char* b)
252 return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
256 * hash up to pp.truncate chars
258 * NOTE: __STD* and symbols containing ' ' are not truncated
261 static unsigned int
262 trunchash(char* a)
264 int n;
266 return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
269 #if DEBUG & TRACE_debug
271 * append context to debug trace
274 static int
275 context(Sfio_t* sp, int level, int flags)
277 static int state;
279 NoP(level);
280 NoP(flags);
281 if (error_info.trace <= -10 && pp.state != state)
283 state = pp.state;
284 sfprintf(sp, " %s", ppstatestr(pp.state));
286 return 1;
288 #endif
291 * reset include guard
294 static int
295 unguard(const char* name, char* v, void* handle)
297 register struct ppfile* fp = (struct ppfile*)v;
299 fp->guard = 0;
300 return 0;
304 * reset macro definition
307 static void
308 undefine(void* p)
310 struct ppmacro* mac = ((struct ppsymbol*)p)->macro;
312 if (mac)
314 if (mac->formals)
315 free(mac->formals);
316 free(mac->value);
317 free(mac);
322 * pp operations
324 * NOTE: PP_INIT must be done before the first pplex() call
325 * PP_DONE must be done after the last pplex() call
326 * PP_INIT-PP_DONE must be done for each new PP_INPUT
329 void
330 ppop(int op, ...)
332 va_list ap;
333 register char* p;
334 register struct ppkeyword* kp;
335 register char* s;
336 int c;
337 long n;
338 char* t;
339 struct ppdirs* dp;
340 struct ppdirs* hp;
341 struct ppsymkey* key;
342 struct oplist* xp;
343 Sfio_t* sp;
344 struct stat st;
345 PPCOMMENT ppcomment;
346 PPLINESYNC pplinesync;
348 static int initialized;
350 va_start(ap, op);
351 switch (op)
353 case PP_ASSERT:
354 case PP_DEFINE:
355 case PP_DIRECTIVE:
356 case PP_OPTION:
357 case PP_READ:
358 case PP_UNDEF:
359 if (pp.initialized)
360 goto before;
361 if ((p = va_arg(ap, char*)) && *p)
363 if (pp.lastop)
364 pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
365 else
366 pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
367 pp.lastop->op = op;
368 pp.lastop->value = p;
370 break;
371 case PP_BUILTIN:
372 pp.builtin = va_arg(ap, PPBUILTIN);
373 break;
374 case PP_CDIR:
375 p = va_arg(ap, char*);
376 c = va_arg(ap, int);
377 pp.cdir.path = 0;
378 if (!p)
379 pp.c = c;
380 else if (streq(p, "-"))
382 pp.c = c;
383 for (dp = pp.firstdir; dp; dp = dp->next)
384 dp->c = c;
386 else if (!pp.c)
388 if (!*p || stat((pathcanon(p, 0), p), &st))
389 pp.c = c;
390 else
392 for (dp = pp.firstdir; dp; dp = dp->next)
394 if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
395 pp.c = 1;
396 dp->c = pp.c == 1;
398 if (!pp.c)
400 pp.cdir.path = p;
401 SAVEID(&pp.cdir.id, &st);
405 break;
406 case PP_CHOP:
407 if (p = va_arg(ap, char*))
409 c = strlen(p);
410 xp = newof(0, struct oplist, 1, c + 1);
411 xp->value = ((char*)xp) + sizeof(struct oplist);
412 s = xp->value;
413 c = *p++;
414 while (*p && *p != c)
415 *s++ = *p++;
416 *s++ = '/';
417 xp->op = s - xp->value;
418 *s++ = 0;
419 if (*p && *++p && *p != c)
421 while (*p && *p != c)
422 *s++ = *p++;
423 *s++ = '/';
425 *s = 0;
426 xp->next = pp.chop;
427 pp.chop = xp;
429 break;
430 case PP_COMMENT:
431 if (pp.comment = va_arg(ap, PPCOMMENT))
432 pp.flags |= PP_comment;
433 else
434 pp.flags &= ~PP_comment;
435 break;
436 case PP_COMPATIBILITY:
437 set(&pp.state, COMPATIBILITY, va_arg(ap, int));
438 #if COMPATIBLE
439 if (pp.initialized)
440 ppfsm(FSM_COMPATIBILITY, NiL);
441 #else
442 if (pp.state & COMPATIBILITY)
443 error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
444 #endif
445 if (pp.state & COMPATIBILITY)
446 pp.flags |= PP_compatibility;
447 else
448 pp.flags &= ~PP_compatibility;
449 break;
450 case PP_COMPILE:
451 if (pp.initialized)
452 goto before;
453 pp.state |= COMPILE;
454 if (!pp.symtab)
455 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
456 if (kp = va_arg(ap, struct ppkeyword*))
457 for (; s = kp->name; kp++)
459 n = SYM_LEX;
460 switch (*s)
462 case '-':
463 s++;
464 break;
465 case '+':
466 s++;
467 if (!(pp.option & PLUSPLUS))
468 break;
469 /*FALLTHROUGH*/
470 default:
471 n |= SYM_KEYWORD;
472 break;
474 if (key = ppkeyset(pp.symtab, s))
476 key->sym.flags = n;
477 key->lex = kp->value;
480 break;
481 case PP_DEBUG:
482 error_info.trace = va_arg(ap, int);
483 break;
484 case PP_DEFAULT:
485 if (p = va_arg(ap, char*))
486 p = strdup(p);
487 if (pp.ppdefault)
488 free(pp.ppdefault);
489 pp.ppdefault = p;
490 break;
491 case PP_DONE:
492 #if CHECKPOINT
493 if (pp.mode & DUMP)
494 ppdump();
495 #endif
496 if (pp.mode & FILEDEPS)
498 sfputc(pp.filedeps.sp, '\n');
499 if (pp.filedeps.sp == sfstdout)
500 sfsync(pp.filedeps.sp);
501 else
502 sfclose(pp.filedeps.sp);
504 if (pp.state & STANDALONE)
506 if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
507 ppputchar('\n');
508 ppflushout();
510 error_info.file = 0;
511 break;
512 case PP_DUMP:
513 set(&pp.mode, DUMP, va_arg(ap, int));
514 #if !CHECKPOINT
515 if (pp.mode & DUMP)
516 error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
517 #endif
518 break;
519 case PP_FILEDEPS:
520 if (n = va_arg(ap, int))
521 pp.filedeps.flags |= n;
522 else
523 pp.filedeps.flags = 0;
524 break;
525 case PP_FILENAME:
526 error_info.file = va_arg(ap, char*);
527 break;
528 case PP_HOSTDIR:
529 if (!(pp.mode & INIT))
530 pp.ro_mode |= HOSTED;
531 else if (pp.ro_mode & HOSTED)
532 break;
533 pp.ro_mode |= INIT;
534 p = va_arg(ap, char*);
535 c = va_arg(ap, int);
536 pp.hostdir.path = 0;
537 if (!p)
538 pp.hosted = c;
539 else if (streq(p, "-"))
541 if (pp.initialized)
542 set(&pp.mode, HOSTED, c);
543 else
545 pp.hosted = c ? 1 : 2;
546 for (dp = pp.firstdir; dp; dp = dp->next)
547 if (pp.hosted == 1)
548 dp->type |= TYPE_HOSTED;
549 else
550 dp->type &= ~TYPE_HOSTED;
553 else if (!pp.hosted)
555 if (!*p || stat((pathcanon(p, 0), p), &st))
556 pp.hosted = 1;
557 else
559 for (dp = pp.firstdir; dp; dp = dp->next)
561 if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
562 pp.hosted = 1;
563 if (pp.hosted == 1)
564 dp->type |= TYPE_HOSTED;
565 else
566 dp->type &= ~TYPE_HOSTED;
568 if (!pp.hosted)
570 pp.hostdir.path = p;
571 SAVEID(&pp.hostdir.id, &st);
575 break;
576 case PP_ID:
577 p = va_arg(ap, char*);
578 c = va_arg(ap, int);
579 if (p)
580 ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
581 break;
582 case PP_IGNORE:
583 if (p = va_arg(ap, char*))
585 pathcanon(p, 0);
586 ppsetfile(p)->guard = INC_IGNORE;
587 message((-3, "%s: ignore", p));
589 break;
590 case PP_IGNORELIST:
591 if (pp.initialized)
592 goto before;
593 pp.ignore = va_arg(ap, char*);
594 break;
595 case PP_INCLUDE:
596 if ((p = va_arg(ap, char*)) && *p)
598 pathcanon(p, 0);
599 if (stat(p, &st))
600 break;
601 for (dp = pp.stddirs; dp = dp->next;)
602 if (dp->name && SAMEID(&dp->id, &st))
603 break;
604 if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
606 pp.cdir.path = 0;
607 pp.c = 1;
609 if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
611 pp.hostdir.path = 0;
612 pp.hosted = 1;
614 if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
615 pp.hosted = 1;
616 c = dp && dp->c || pp.c == 1;
617 n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
618 if (!dp || dp == pp.lastdir->next)
620 if (dp)
622 c = dp->c;
623 n = dp->type & TYPE_HOSTED;
625 dp = newof(0, struct ppdirs, 1, 0);
626 dp->name = p;
627 SAVEID(&dp->id, &st);
628 dp->type |= TYPE_INCLUDE;
629 dp->index = INC_LOCAL + pp.ignoresrc != 0;
630 dp->next = pp.lastdir->next;
631 pp.lastdir = pp.lastdir->next = dp;
633 dp->c = c;
634 if (n)
635 dp->type |= TYPE_HOSTED;
636 else
637 dp->type &= ~TYPE_HOSTED;
639 break;
640 case PP_INCREF:
641 pp.incref = va_arg(ap, PPINCREF);
642 break;
643 case PP_RESET:
644 pp.reset.on = 1;
645 break;
646 case PP_INIT:
647 if (pp.initialized)
649 error_info.errors = 0;
650 error_info.warnings = 0;
652 else
655 * context initialization
658 if (!initialized)
661 * out of malloc is fatal
664 memfatal();
667 * initialize the error message interface
670 error_info.version = (char*)pp.version;
671 #if DEBUG & TRACE_debug
672 error_info.auxilliary = context;
673 pptrace(0);
674 #endif
677 * initialize pplex tables
680 ppfsm(FSM_INIT, NiL);
683 * fixed macro stack size -- room for improvement
686 pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
687 pp.macp->next = pp.macp + 1;
688 pp.maxmac = (char*)pp.macp + DEFMACSTACK;
689 initialized = 1;
692 * initial include/if control stack
695 pp.control = newof(0, long, pp.constack, 0);
696 pp.maxcon = pp.control + pp.constack - 1;
700 * validate modes
703 switch (pp.arg_mode)
705 case 'a':
706 case 'C':
707 ppop(PP_COMPATIBILITY, 0);
708 ppop(PP_TRANSITION, 1);
709 break;
710 case 'A':
711 case 'c':
712 ppop(PP_COMPATIBILITY, 0);
713 ppop(PP_STRICT, 1);
714 break;
715 case 'f':
716 ppop(PP_COMPATIBILITY, 1);
717 ppop(PP_PLUSPLUS, 1);
718 ppop(PP_TRANSITION, 1);
719 break;
720 case 'F':
721 ppop(PP_COMPATIBILITY, 0);
722 ppop(PP_PLUSPLUS, 1);
723 break;
724 case 'k':
725 case 's':
726 ppop(PP_COMPATIBILITY, 1);
727 ppop(PP_STRICT, 1);
728 break;
729 case 'o':
730 case 'O':
731 ppop(PP_COMPATIBILITY, 1);
732 ppop(PP_TRANSITION, 0);
733 break;
734 case 't':
735 ppop(PP_COMPATIBILITY, 1);
736 ppop(PP_TRANSITION, 1);
737 break;
739 if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
740 ppop(PP_PEDANTIC, 1);
741 if (pp.state & PASSTHROUGH)
743 if (pp.state & COMPILE)
745 pp.state &= ~PASSTHROUGH;
746 error(1, "passthrough ignored for compile");
748 else
750 ppop(PP_COMPATIBILITY, 1);
751 ppop(PP_HOSTDIR, "-", 1);
752 ppop(PP_SPACEOUT, 1);
753 set(&pp.state, DISABLE, va_arg(ap, int));
758 * create the hash tables
761 if (!pp.symtab)
762 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
763 if (!pp.dirtab)
765 pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
766 inithash(pp.dirtab, directives);
768 if (!pp.filtab)
769 pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
770 if (!pp.prdtab)
771 pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
772 if (!pp.strtab)
774 pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
775 inithash(pp.strtab, options);
776 inithash(pp.strtab, predicates);
777 inithash(pp.strtab, variables);
779 pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
780 pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
783 * mark macros that are builtin predicates
786 for (kp = predicates; s = kp->name; kp++)
788 if (!ppisid(*s))
789 s++;
790 ppassert(DEFINE, s, 0);
794 * the remaining entry names must be allocated
797 hashset(pp.dirtab, HASH_ALLOCATE);
798 hashset(pp.filtab, HASH_ALLOCATE);
799 hashset(pp.prdtab, HASH_ALLOCATE);
800 hashset(pp.strtab, HASH_ALLOCATE);
801 hashset(pp.symtab, HASH_ALLOCATE);
802 if (pp.test & TEST_nonoise)
804 c = error_info.trace;
805 error_info.trace = 0;
807 #if DEBUG
808 if (!(pp.test & TEST_noinit))
810 #endif
813 * compose, push and read the builtin initialization script
816 if (!(sp = sfstropen()))
817 error(3, "temporary buffer allocation error");
818 sfprintf(sp,
820 #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
821 #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
823 dirname(PRAGMA),
824 pp.pass,
825 keyname(X_MAP),
826 dirname(DEFINE),
827 dirname(PRAGMA),
828 pp.pass,
829 keyname(X_MAP),
830 dirname(UNDEF));
831 if (pp.ppdefault && *pp.ppdefault)
833 if (pp.probe)
835 c = pp.lastdir->next->type;
836 pp.lastdir->next->type = 0;
838 if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
840 free(pp.ppdefault);
841 if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0)))
842 error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
844 if (pp.probe)
845 pp.lastdir->next->type = c;
847 while (pp.firstop)
849 switch (pp.firstop->op)
851 case PP_ASSERT:
852 sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
853 break;
854 case PP_DEFINE:
855 if (*pp.firstop->value == '#')
856 sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
857 else
859 if (s = strchr(pp.firstop->value, '='))
860 sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
861 else
862 sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
864 break;
865 case PP_DIRECTIVE:
866 sfprintf(sp, "#%s\n", pp.firstop->value);
867 break;
868 case PP_OPTION:
869 if (s = strchr(pp.firstop->value, '='))
870 sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
871 else
872 sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
873 break;
874 case PP_READ:
875 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
876 break;
877 case PP_UNDEF:
878 sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
879 break;
881 pp.lastop = pp.firstop;
882 pp.firstop = pp.firstop->next;
883 free(pp.lastop);
885 sfprintf(sp,
887 #%s %s:%s\n\
888 #%s %s:%s\n\
889 #%s !#%s(%s)\n\
890 #%s !#%s(%s) || #%s(%s)\n\
892 , dirname(PRAGMA)
893 , pp.pass
894 , keyname(X_BUILTIN)
895 , dirname(PRAGMA)
896 , pp.pass
897 , keyname(X_PREDEFINED)
898 , dirname(IF)
899 , keyname(X_OPTION)
900 , keyname(X_PLUSPLUS)
901 , dirname(IF)
902 , keyname(X_OPTION)
903 , keyname(X_COMPATIBILITY)
904 , keyname(X_OPTION)
905 , keyname(X_TRANSITION)
907 sfprintf(sp,
909 #%s #%s(%s)\n\
910 #%s %s:%s\n\
911 #%s %s:%s\n\
912 #%s __STRICT__ 1\n\
913 #%s\n\
914 #%s\n\
916 , dirname(IF)
917 , keyname(X_OPTION)
918 , keyname(X_STRICT)
919 , dirname(PRAGMA)
920 , pp.pass
921 , keyname(X_ALLMULTIPLE)
922 , dirname(PRAGMA)
923 , pp.pass
924 , keyname(X_READONLY)
925 , dirname(DEFINE)
926 , dirname(ENDIF)
927 , dirname(ENDIF)
929 for (kp = readonlys; s = kp->name; kp++)
931 if (!ppisid(*s))
932 s++;
933 sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
935 sfprintf(sp,
937 #%s\n\
938 #%s __STDPP__ 1\n\
939 #%s %s:no%s\n\
941 , dirname(ENDIF)
942 , dirname(DEFINE)
943 , dirname(PRAGMA)
944 , pp.pass
945 , keyname(X_PREDEFINED)
947 if (!pp.truncate)
948 sfprintf(sp,
950 #%s __STDPP__directive #(%s)\n\
952 , dirname(DEFINE)
953 , keyname(V_DIRECTIVE)
955 for (kp = variables; s = kp->name; kp++)
956 if (ppisid(*s) || *s++ == '+')
958 t = *s == '_' ? "" : "__";
959 sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
961 sfprintf(sp,
963 #%s %s:no%s\n\
964 #%s %s:no%s\n\
966 , dirname(PRAGMA)
967 , pp.pass
968 , keyname(X_READONLY)
969 , dirname(PRAGMA)
970 , pp.pass
971 , keyname(X_BUILTIN)
973 if (pp.ppdefault && *pp.ppdefault)
974 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
975 sfprintf(sp,
977 #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
978 #%s __STDC__ #(STDC)\n\
979 #%s\n\
981 , dirname(IF)
982 , dirname(DEFINE)
983 , dirname(ENDIF)
985 t = sfstruse(sp);
986 debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
987 ppcomment = pp.comment;
988 pp.comment = 0;
989 pplinesync = pp.linesync;
990 pp.linesync = 0;
991 PUSH_INIT(pp.pass, t);
992 pp.mode |= INIT;
993 while (pplex());
994 pp.mode &= ~INIT;
995 pp.comment = ppcomment;
996 pp.linesync = pplinesync;
997 pp.prefix = 0;
998 sfstrclose(sp);
999 if (error_info.trace)
1000 for (dp = pp.firstdir; dp; dp = dp->next)
1001 message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
1002 #if DEBUG
1004 if (pp.test & TEST_nonoise)
1005 error_info.trace = c;
1006 #endif
1009 * this is sleazy but at least it's
1010 * hidden in the library
1012 #include <preroot.h>
1013 #if FS_PREROOT
1014 struct pplist* preroot;
1016 if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
1017 setpreroot(NiL, preroot->value);
1018 #endif
1020 if (pp.ignoresrc)
1022 if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
1023 error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
1024 pp.lcldirs = pp.lcldirs->next;
1026 if (pp.ignore)
1028 if (*pp.ignore)
1029 ppmapinclude(pp.ignore, NiL);
1030 else
1031 pp.ignore = 0;
1033 if (pp.standalone)
1034 pp.state |= STANDALONE;
1035 #if COMPATIBLE
1036 ppfsm(FSM_COMPATIBILITY, NiL);
1037 #endif
1038 ppfsm(FSM_PLUSPLUS, NiL);
1039 pp.initialized = 1;
1040 if (pp.reset.on)
1042 pp.reset.symtab = pp.symtab;
1043 pp.symtab = 0;
1044 pp.reset.ro_state = pp.ro_state;
1045 pp.reset.ro_mode = pp.ro_mode;
1046 pp.reset.ro_option = pp.ro_option;
1049 if (pp.reset.on)
1051 if (pp.symtab)
1053 hashwalk(pp.filtab, 0, unguard, NiL);
1054 hashfree(pp.symtab);
1056 pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
1057 hashview(pp.symtab, pp.reset.symtab);
1058 pp.ro_state = pp.reset.ro_state;
1059 pp.ro_mode = pp.reset.ro_mode;
1060 pp.ro_option = pp.reset.ro_option;
1062 #if CHECKPOINT
1063 if (pp.mode & DUMP)
1065 if (!pp.pragma)
1066 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
1067 (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
1069 #endif
1070 if (n = pp.filedeps.flags)
1072 if (!(n & PP_deps_file))
1074 pp.state |= NOTEXT;
1075 pp.option |= KEEPNOTEXT;
1076 pp.linesync = 0;
1078 if (n & PP_deps_generated)
1079 pp.mode |= GENDEPS;
1080 if (n & PP_deps_local)
1081 pp.mode &= ~HEADERDEPS;
1082 else if (!(pp.mode & FILEDEPS))
1083 pp.mode |= HEADERDEPS;
1084 pp.mode |= FILEDEPS;
1088 * push the main input file -- special case for hosted mark
1091 if (pp.firstdir->type & TYPE_HOSTED)
1092 pp.mode |= MARKHOSTED;
1093 else
1094 pp.mode &= ~MARKHOSTED;
1095 #if CHECKPOINT
1096 if (!(pp.mode & DUMP))
1097 #endif
1099 if (!(p = error_info.file))
1100 p = "";
1101 else
1103 error_info.file = 0;
1104 if (*p)
1106 pathcanon(p, 0);
1107 p = ppsetfile(p)->name;
1110 PUSH_FILE(p, 0);
1112 if (pp.mode & FILEDEPS)
1114 if (s = strrchr(error_info.file, '/'))
1115 s++;
1116 else
1117 s = error_info.file;
1118 if (!*s)
1119 s = "-";
1120 s = strcpy(pp.tmpbuf, s);
1121 if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
1123 if (c = *++p)
1124 while (*++p == c);
1125 if (*p)
1126 t = 0;
1127 else
1128 t++;
1130 if (!t)
1132 t = s + strlen(s);
1133 *t++ = '.';
1135 *(t + 1) = 0;
1136 if (pp.state & NOTEXT)
1137 pp.filedeps.sp = sfstdout;
1138 else
1140 *t = 'd';
1141 if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
1142 error(ERROR_SYSTEM|3, "%s: cannot create", s);
1144 *t = 'o';
1145 pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
1146 if (*error_info.file)
1147 pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
1149 if (xp = pp.firsttx)
1151 if (!(sp = sfstropen()))
1152 error(3, "temporary buffer allocation error");
1153 while (xp)
1155 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
1156 xp = xp->next;
1158 t = sfstruse(sp);
1159 PUSH_BUFFER("options", t, 1);
1160 sfstrclose(sp);
1162 break;
1163 case PP_INPUT:
1164 #if CHECKPOINT && POOL
1165 if (!(pp.mode & DUMP) || pp.pool.input)
1166 #else
1167 #if CHECKPOINT
1168 if (!(pp.mode & DUMP))
1169 #else
1170 #if POOL
1171 if (pp.pool.input)
1172 #endif
1173 #endif
1174 #endif
1176 p = va_arg(ap, char*);
1177 if (!error_info.file)
1178 error_info.file = p;
1179 close(0);
1180 if (open(p, O_RDONLY) != 0)
1181 error(ERROR_SYSTEM|3, "%s: cannot read", p);
1182 if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
1184 set(&pp.mode, CATLITERAL, 0);
1185 ppop(PP_SPACEOUT, 1);
1187 break;
1189 /*FALLTHROUGH*/
1190 case PP_TEXT:
1191 if (pp.initialized)
1192 goto before;
1193 if ((p = va_arg(ap, char*)) && *p)
1195 if (pp.lasttx)
1196 pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
1197 else
1198 pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
1199 pp.lasttx->op = op;
1200 pp.lasttx->value = p;
1202 break;
1203 case PP_KEYARGS:
1204 if (pp.initialized)
1205 goto before;
1206 set(&pp.option, KEYARGS, va_arg(ap, int));
1207 if (pp.option & KEYARGS)
1208 #if MACKEYARGS
1209 set(&pp.mode, CATLITERAL, 1);
1210 #else
1211 error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1212 #endif
1213 break;
1214 case PP_LINE:
1215 pp.linesync = va_arg(ap, PPLINESYNC);
1216 break;
1217 case PP_LINEBASE:
1218 if (va_arg(ap, int))
1219 pp.flags |= PP_linebase;
1220 else
1221 pp.flags &= ~PP_linebase;
1222 break;
1223 case PP_LINEFILE:
1224 if (va_arg(ap, int))
1225 pp.flags |= PP_linefile;
1226 else
1227 pp.flags &= ~PP_linefile;
1228 break;
1229 case PP_LINEID:
1230 if (!(p = va_arg(ap, char*)))
1231 pp.lineid = "";
1232 else if (*p != '-')
1233 pp.lineid = strdup(p);
1234 else
1235 pp.option |= IGNORELINE;
1236 break;
1237 case PP_LINETYPE:
1238 if ((n = va_arg(ap, int)) >= 1)
1239 pp.flags |= PP_linetype;
1240 else
1241 pp.flags &= ~PP_linetype;
1242 if (n >= 2)
1243 pp.flags |= PP_linehosted;
1244 else
1245 pp.flags &= ~PP_linehosted;
1246 break;
1247 case PP_LOCAL:
1248 if (pp.initialized)
1249 goto before;
1250 pp.ignoresrc++;
1251 pp.stddirs = pp.lastdir;
1252 if (!(pp.ro_option & PREFIX))
1253 pp.option &= ~PREFIX;
1254 break;
1255 case PP_MACREF:
1256 pp.macref = va_arg(ap, PPMACREF);
1257 break;
1258 case PP_MULTIPLE:
1259 set(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
1260 break;
1261 case PP_NOHASH:
1262 set(&pp.option, NOHASH, va_arg(ap, int));
1263 break;
1264 case PP_NOISE:
1265 op = va_arg(ap, int);
1266 set(&pp.option, NOISE, op);
1267 set(&pp.option, NOISEFILTER, op < 0);
1268 break;
1269 case PP_OPTARG:
1270 pp.optarg = va_arg(ap, PPOPTARG);
1271 break;
1272 case PP_OUTPUT:
1273 pp.outfile = va_arg(ap, char*);
1274 if (identical(pp.outfile, 0))
1275 error(3, "%s: identical to input", pp.outfile);
1276 close(1);
1277 if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
1278 error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
1279 break;
1280 case PP_PASSTHROUGH:
1281 if (!(pp.state & COMPILE))
1282 set(&pp.state, PASSTHROUGH, va_arg(ap, int));
1283 break;
1284 case PP_PEDANTIC:
1285 set(&pp.mode, PEDANTIC, va_arg(ap, int));
1286 break;
1287 case PP_PLUSCOMMENT:
1288 set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
1289 if (pp.initialized)
1290 ppfsm(FSM_PLUSPLUS, NiL);
1291 break;
1292 case PP_PLUSPLUS:
1293 set(&pp.option, PLUSPLUS, va_arg(ap, int));
1294 set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
1295 if (pp.initialized)
1296 ppfsm(FSM_PLUSPLUS, NiL);
1297 break;
1298 case PP_POOL:
1299 if (pp.initialized)
1300 goto before;
1301 if (va_arg(ap, int))
1303 #if POOL
1304 pp.pool.input = dup(0);
1305 pp.pool.output = dup(1);
1306 p = "/dev/null";
1307 if (!identical(p, 0))
1309 if (!identical(p, 1))
1310 ppop(PP_OUTPUT, p);
1311 ppop(PP_INPUT, p);
1313 #else
1314 error(3, "preprocessor not compiled with input pool enabled [POOL]");
1315 #endif
1317 break;
1318 case PP_PRAGMA:
1319 pp.pragma = va_arg(ap, PPPRAGMA);
1320 break;
1321 case PP_PRAGMAFLAGS:
1322 if (p = va_arg(ap, char*))
1324 n = OPT_GLOBAL;
1325 if (*p == '-')
1326 p++;
1327 else
1328 n |= OPT_PASS;
1329 if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
1330 pp.optflags[c] = n;
1332 break;
1333 case PP_PROBE:
1334 pp.probe = va_arg(ap, char*);
1335 break;
1336 case PP_QUOTE:
1337 p = va_arg(ap, char*);
1338 c = va_arg(ap, int);
1339 if (p)
1340 ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
1341 break;
1342 case PP_REGUARD:
1343 set(&pp.option, REGUARD, va_arg(ap, int));
1344 break;
1345 case PP_RESERVED:
1346 if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
1348 if (!(sp = sfstropen()))
1349 error(3, "temporary buffer allocation error");
1350 sfputr(sp, p, -1);
1351 p = sfstruse(sp);
1352 if (s = strchr(p, '='))
1353 *s++ = 0;
1354 else
1355 s = p;
1356 while (*s == '_')
1357 s++;
1358 for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
1359 if (*t == '_')
1360 *t = 0;
1361 else
1362 t = 0;
1363 op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
1364 if (pp.test & 0x0400)
1365 error(1, "reserved#1 `%s' %d", s, op);
1366 if (t)
1367 *t = '_';
1368 if (!(key = ppkeyget(pp.symtab, p)))
1369 key = ppkeyset(pp.symtab, NiL);
1370 else if (!(key->sym.flags & SYM_LEX))
1372 struct ppsymbol tmp;
1374 tmp = key->sym;
1375 hashlook(pp.symtab, p, HASH_DELETE, NiL);
1376 key = ppkeyset(pp.symtab, NiL);
1377 key->sym.flags = tmp.flags;
1378 key->sym.macro = tmp.macro;
1379 key->sym.value = tmp.value;
1380 key->sym.hidden = tmp.hidden;
1382 if (!(key->sym.flags & SYM_KEYWORD))
1384 key->sym.flags |= SYM_KEYWORD|SYM_LEX;
1385 key->lex = op;
1386 if (pp.test & 0x0400)
1387 error(1, "reserved#2 `%s' %d", p, op);
1389 sfstrclose(sp);
1391 break;
1392 case PP_SPACEOUT:
1393 set(&pp.state, SPACEOUT, va_arg(ap, int));
1394 break;
1395 case PP_STANDALONE:
1396 if (pp.initialized)
1397 goto before;
1398 pp.standalone = 1;
1399 break;
1400 case PP_STANDARD:
1401 if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
1402 SAVEID(&pp.lastdir->next->id, &st);
1403 for (dp = pp.firstdir; dp; dp = dp->next)
1404 if (dp->name)
1405 for (hp = pp.firstdir; hp != dp; hp = hp->next)
1406 if (hp->name && SAMEID(&hp->id, &dp->id))
1408 hp->c = dp->c;
1409 if (dp->type & TYPE_HOSTED)
1410 hp->type |= TYPE_HOSTED;
1411 else
1412 hp->type &= ~TYPE_HOSTED;
1414 break;
1415 case PP_STRICT:
1416 set(&pp.state, TRANSITION, 0);
1417 pp.flags &= ~PP_transition;
1418 set(&pp.state, STRICT, va_arg(ap, int));
1419 if (pp.state & STRICT)
1420 pp.flags |= PP_strict;
1421 else
1422 pp.flags &= ~PP_strict;
1423 break;
1424 case PP_TEST:
1425 if (p = va_arg(ap, char*))
1426 for (;;)
1428 while (*p == ' ' || *p == '\t') p++;
1429 for (s = p; n = *s; s++)
1430 if (n == ',' || n == ' ' || n == '\t')
1432 *s++ = 0;
1433 break;
1435 if (!*p)
1436 break;
1437 n = 0;
1438 if (*p == 'n' && *(p + 1) == 'o')
1440 p += 2;
1441 op = 0;
1443 else
1444 op = 1;
1445 if (streq(p, "count"))
1446 n = TEST_count;
1447 else if (streq(p, "hashcount"))
1448 n = TEST_hashcount;
1449 else if (streq(p, "hashdump"))
1450 n = TEST_hashdump;
1451 else if (streq(p, "hit"))
1452 n = TEST_hit;
1453 else if (streq(p, "init"))
1454 n = TEST_noinit|TEST_INVERT;
1455 else if (streq(p, "noise"))
1456 n = TEST_nonoise|TEST_INVERT;
1457 else if (streq(p, "proto"))
1458 n = TEST_noproto|TEST_INVERT;
1459 else if (*p >= '0' && *p <= '9')
1460 n = strtoul(p, NiL, 0);
1461 else
1463 error(1, "%s: unknown test", p);
1464 break;
1466 if (n & TEST_INVERT)
1468 n &= ~TEST_INVERT;
1469 op = !op;
1471 if (op)
1472 pp.test |= n;
1473 else
1474 pp.test &= ~n;
1475 p = s;
1476 debug((-4, "test = 0%o", pp.test));
1478 break;
1479 case PP_TRANSITION:
1480 set(&pp.state, STRICT, 0);
1481 pp.flags &= ~PP_strict;
1482 set(&pp.state, TRANSITION, va_arg(ap, int));
1483 if (pp.state & TRANSITION)
1484 pp.flags |= PP_transition;
1485 else
1486 pp.flags &= ~PP_transition;
1487 break;
1488 case PP_TRUNCATE:
1489 if (pp.initialized)
1490 goto before;
1491 if ((op = va_arg(ap, int)) < 0)
1492 op = 0;
1493 set(&pp.option, TRUNCATE, op);
1494 if (pp.option & TRUNCATE)
1496 Hash_bucket_t* b;
1497 Hash_bucket_t* p;
1498 Hash_position_t* pos;
1499 Hash_table_t* tab;
1501 pp.truncate = op;
1502 tab = pp.symtab;
1503 pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
1504 if (tab && (pos = hashscan(tab, 0)))
1506 if (p = hashnext(pos))
1509 b = hashnext(pos);
1510 hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
1511 } while (p = b);
1512 hashdone(pos);
1515 else
1516 pp.truncate = 0;
1517 break;
1518 case PP_VENDOR:
1519 p = va_arg(ap, char*);
1520 c = va_arg(ap, int) != 0;
1521 if (!p || !*p)
1522 for (dp = pp.firstdir; dp; dp = dp->next)
1523 dp->type &= ~TYPE_VENDOR;
1524 else if (streq(p, "-"))
1526 for (dp = pp.firstdir; dp; dp = dp->next)
1527 if (c)
1528 dp->type |= TYPE_VENDOR;
1529 else
1530 dp->type &= ~TYPE_VENDOR;
1532 else if (!stat((pathcanon(p, 0), p), &st))
1534 c = 0;
1535 for (dp = pp.firstdir; dp; dp = dp->next)
1537 if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
1538 c = 1;
1539 if (c)
1540 dp->type |= TYPE_VENDOR;
1541 else
1542 dp->type &= ~TYPE_VENDOR;
1545 break;
1546 case PP_WARN:
1547 set(&pp.state, WARN, va_arg(ap, int));
1548 break;
1549 before:
1550 error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
1551 break;
1552 default:
1553 error(3, "ppop(%d): invalid preprocessor operation", op);
1554 break;
1556 va_end(ap);