14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1986-2009 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * Glenn Fowler
234887Schin * AT&T Research
244887Schin *
254887Schin * preprocessor library control interface
264887Schin */
274887Schin
284887Schin #include "pplib.h"
294887Schin #include "pptab.h"
304887Schin
314887Schin #include <ls.h>
324887Schin
334887Schin #define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab)
344887Schin #define REFALL (pp.truncate?pp.dirtab:pp.symtab)
354887Schin
364887Schin #define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
374887Schin
384887Schin /*
394887Schin * set option value
404887Schin * initialization files have lowest precedence
414887Schin */
424887Schin
434887Schin static void
set(register long * p,register long op,int val)444887Schin set(register long* p, register long op, int val)
454887Schin {
464887Schin long* r;
474887Schin
484887Schin r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
494887Schin if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op))
504887Schin {
514887Schin if (!pp.initialized && !(pp.mode & INIT))
524887Schin *r |= op;
534887Schin if (val)
544887Schin *p |= op;
554887Schin else
564887Schin *p &= ~op;
574887Schin }
584887Schin 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)));
594887Schin }
604887Schin
614887Schin /*
624887Schin * initialize hash table with keywords from key
634887Schin */
644887Schin
654887Schin static void
inithash(register Hash_table_t * tab,register struct ppkeyword * key)664887Schin inithash(register Hash_table_t* tab, register struct ppkeyword* key)
674887Schin {
684887Schin register char* s;
694887Schin
704887Schin for (; s = key->name; key++)
714887Schin {
724887Schin if (!ppisid(*s))
734887Schin s++;
744887Schin hashput(tab, s, key->value);
754887Schin }
764887Schin }
774887Schin
784887Schin /*
794887Schin * return ppkeyword table name given value
804887Schin */
814887Schin
824887Schin char*
ppkeyname(register int value,int dir)834887Schin ppkeyname(register int value, int dir)
844887Schin {
854887Schin register char* s;
864887Schin register struct ppkeyword* p;
874887Schin
884887Schin if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
894887Schin {
904887Schin s = (p + (value - p->value))->name;
914887Schin return s + !ppisid(*s);
924887Schin }
934887Schin #if DEBUG
944887Schin error(PANIC, "no keyword table name for value=%d", value);
954887Schin #endif
964887Schin return "UNKNOWN";
974887Schin }
984887Schin
994887Schin /*
1004887Schin * add to the include maps
1014887Schin */
1024887Schin
1034887Schin void
ppmapinclude(char * file,register char * s)1044887Schin ppmapinclude(char* file, register char* s)
1054887Schin {
1064887Schin register int c;
1074887Schin register struct ppdirs* dp;
1084887Schin int fd;
1094887Schin int flags;
1104887Schin int index;
1114887Schin int token;
1124887Schin char* t;
1134887Schin char* old_file;
1144887Schin long old_state;
1154887Schin struct ppfile* fp;
1164887Schin struct ppfile* mp;
1174887Schin
1184887Schin old_file = error_info.file;
1194887Schin old_state = pp.state;
1204887Schin if (s)
1214887Schin PUSH_BUFFER("mapinclude", s, 1);
1224887Schin else if (file)
1234887Schin {
1244887Schin if (*file == '-')
1254887Schin {
1264887Schin if (!error_info.file)
1274887Schin {
1284887Schin error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
1294887Schin return;
1304887Schin }
1314887Schin s = t = strcopy(pp.tmpbuf, error_info.file);
1324887Schin c = *++file;
1334887Schin for (;;)
1344887Schin {
1354887Schin if (s <= pp.tmpbuf || *s == '/')
1364887Schin {
1374887Schin s = t;
1384887Schin break;
1394887Schin }
1404887Schin else if (*s == c)
1414887Schin break;
1424887Schin s--;
1434887Schin }
1444887Schin strcpy(s, file);
1454887Schin file = pp.tmpbuf;
1464887Schin }
1474887Schin if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
1484887Schin return;
1494887Schin PUSH_FILE(file, fd);
1504887Schin }
1514887Schin else
1524887Schin return;
1534887Schin #if CATSTRINGS
1544887Schin pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
1554887Schin #else
1564887Schin pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
1574887Schin #endif
1584887Schin pp.level++;
1594887Schin flags = INC_MAPALL;
1604887Schin fp = mp = 0;
1614887Schin for (;;)
1624887Schin {
1634887Schin switch (token = pplex())
1644887Schin {
1654887Schin case 0:
1664887Schin case T_STRING:
1674887Schin case T_HEADER:
1684887Schin if (fp)
1694887Schin {
1704887Schin fp->guard = INC_IGNORE;
1714887Schin for (dp = pp.firstdir->next; dp; dp = dp->next)
1724887Schin if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
1734887Schin {
1744887Schin ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
1754887Schin break;
1764887Schin }
1774887Schin }
1784887Schin if (!token)
1794887Schin break;
1804887Schin pathcanon(pp.token, 0);
1814887Schin fp = ppsetfile(pp.token);
1824887Schin if (mp)
1834887Schin {
1844887Schin mp->flags |= flags;
1854887Schin if (streq(fp->name, "."))
1864887Schin mp->flags |= INC_MAPNOLOCAL;
1874887Schin else
1884887Schin mp->bound[index] = fp;
1894887Schin
1904887Schin fp = mp = 0;
1914887Schin }
1924887Schin else
1934887Schin index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
1944887Schin continue;
1954887Schin case '=':
1964887Schin if (!(mp = fp))
1974887Schin error(3, "%s: \"name\" = \"binding\" expected");
1984887Schin fp = 0;
1994887Schin continue;
2004887Schin case '\n':
2014887Schin continue;
2024887Schin case T_ID:
2034887Schin if (streq(pp.token, "all"))
2044887Schin {
2054887Schin flags = INC_MAPALL;
2064887Schin continue;
2074887Schin }
2084887Schin else if (streq(pp.token, "hosted"))
2094887Schin {
2104887Schin flags = INC_MAPHOSTED;
2114887Schin continue;
2124887Schin }
2134887Schin else if (streq(pp.token, "nohosted"))
2144887Schin {
2154887Schin flags = INC_MAPNOHOSTED;
2164887Schin continue;
2174887Schin }
2184887Schin /*FALLTHROUGH*/
2194887Schin default:
2204887Schin error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
2214887Schin break;
2224887Schin }
2234887Schin break;
2244887Schin }
2254887Schin pp.level--;
2264887Schin error_info.file = old_file;
2274887Schin pp.state = old_state;
2284887Schin }
2294887Schin
2304887Schin /*
2314887Schin * return non-0 if file is identical to fd
2324887Schin */
2334887Schin
2344887Schin static int
identical(char * file,int fd)2354887Schin identical(char* file, int fd)
2364887Schin {
2374887Schin struct stat a;
2384887Schin struct stat b;
2394887Schin
2404887Schin return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
2414887Schin }
2424887Schin
2434887Schin /*
2444887Schin * compare up to pp.truncate chars
2454887Schin *
2464887Schin * NOTE: __STD* and symbols containing ' ' are not truncated
2474887Schin */
2484887Schin
2494887Schin static int
trunccomp(register char * a,register char * b)2504887Schin trunccomp(register char* a, register char* b)
2514887Schin {
2524887Schin return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
2534887Schin }
2544887Schin
2554887Schin /*
2564887Schin * hash up to pp.truncate chars
2574887Schin *
2584887Schin * NOTE: __STD* and symbols containing ' ' are not truncated
2594887Schin */
2604887Schin
2614887Schin static unsigned int
trunchash(char * a)2624887Schin trunchash(char* a)
2634887Schin {
2644887Schin int n;
2654887Schin
2664887Schin return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
2674887Schin }
2684887Schin
2694887Schin #if DEBUG & TRACE_debug
2704887Schin /*
2714887Schin * append context to debug trace
2724887Schin */
2734887Schin
2744887Schin static int
context(Sfio_t * sp,int level,int flags)2754887Schin context(Sfio_t* sp, int level, int flags)
2764887Schin {
2774887Schin static int state;
2784887Schin
2794887Schin NoP(level);
2804887Schin NoP(flags);
2814887Schin if (error_info.trace <= -10 && pp.state != state)
2824887Schin {
2834887Schin state = pp.state;
2844887Schin sfprintf(sp, " %s", ppstatestr(pp.state));
2854887Schin }
2864887Schin return 1;
2874887Schin }
2884887Schin #endif
2894887Schin
2904887Schin /*
2914887Schin * reset include guard
2924887Schin */
2934887Schin
2944887Schin static int
unguard(const char * name,char * v,void * handle)2954887Schin unguard(const char* name, char* v, void* handle)
2964887Schin {
2974887Schin register struct ppfile* fp = (struct ppfile*)v;
2984887Schin
2994887Schin fp->guard = 0;
3004887Schin return 0;
3014887Schin }
3024887Schin
3034887Schin /*
3044887Schin * reset macro definition
3054887Schin */
3064887Schin
3074887Schin static void
undefine(void * p)3084887Schin undefine(void* p)
3094887Schin {
3104887Schin struct ppmacro* mac = ((struct ppsymbol*)p)->macro;
3114887Schin
3124887Schin if (mac)
3134887Schin {
3144887Schin if (mac->formals)
3154887Schin free(mac->formals);
3164887Schin free(mac->value);
3174887Schin free(mac);
3184887Schin }
3194887Schin }
3204887Schin
3214887Schin /*
3224887Schin * pp operations
3234887Schin *
3244887Schin * NOTE: PP_INIT must be done before the first pplex() call
3254887Schin * PP_DONE must be done after the last pplex() call
3264887Schin * PP_INIT-PP_DONE must be done for each new PP_INPUT
3274887Schin */
3284887Schin
3294887Schin void
ppop(int op,...)3304887Schin ppop(int op, ...)
3314887Schin {
3324887Schin va_list ap;
3334887Schin register char* p;
3344887Schin register struct ppkeyword* kp;
3354887Schin register char* s;
3364887Schin int c;
3374887Schin long n;
3384887Schin char* t;
3394887Schin struct ppdirs* dp;
3404887Schin struct ppdirs* hp;
3414887Schin struct ppsymkey* key;
3424887Schin struct oplist* xp;
3434887Schin Sfio_t* sp;
3444887Schin struct stat st;
3454887Schin PPCOMMENT ppcomment;
3464887Schin PPLINESYNC pplinesync;
3474887Schin
3484887Schin static int initialized;
3494887Schin
3504887Schin va_start(ap, op);
3514887Schin switch (op)
3524887Schin {
3534887Schin case PP_ASSERT:
3544887Schin case PP_DEFINE:
3554887Schin case PP_DIRECTIVE:
3564887Schin case PP_OPTION:
3574887Schin case PP_READ:
3584887Schin case PP_UNDEF:
3594887Schin if (pp.initialized)
3604887Schin goto before;
3614887Schin if ((p = va_arg(ap, char*)) && *p)
3624887Schin {
3634887Schin if (pp.lastop)
3644887Schin pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
3654887Schin else
3664887Schin pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
3674887Schin pp.lastop->op = op;
3684887Schin pp.lastop->value = p;
3694887Schin }
3704887Schin break;
3714887Schin case PP_BUILTIN:
3724887Schin pp.builtin = va_arg(ap, PPBUILTIN);
3734887Schin break;
3744887Schin case PP_CDIR:
3754887Schin p = va_arg(ap, char*);
3764887Schin c = va_arg(ap, int);
3774887Schin pp.cdir.path = 0;
3784887Schin if (!p)
3794887Schin pp.c = c;
3804887Schin else if (streq(p, "-"))
3814887Schin {
3824887Schin pp.c = c;
3834887Schin for (dp = pp.firstdir; dp; dp = dp->next)
3844887Schin dp->c = c;
3854887Schin }
3864887Schin else if (!pp.c)
3874887Schin {
3884887Schin if (!*p || stat((pathcanon(p, 0), p), &st))
3894887Schin pp.c = c;
3904887Schin else
3914887Schin {
3924887Schin for (dp = pp.firstdir; dp; dp = dp->next)
3934887Schin {
3944887Schin if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
3954887Schin pp.c = 1;
3964887Schin dp->c = pp.c == 1;
3974887Schin }
3984887Schin if (!pp.c)
3994887Schin {
4004887Schin pp.cdir.path = p;
4014887Schin SAVEID(&pp.cdir.id, &st);
4024887Schin }
4034887Schin }
4044887Schin }
4054887Schin break;
4064887Schin case PP_CHOP:
4074887Schin if (p = va_arg(ap, char*))
4084887Schin {
4094887Schin c = strlen(p);
4104887Schin xp = newof(0, struct oplist, 1, c + 1);
4114887Schin xp->value = ((char*)xp) + sizeof(struct oplist);
4124887Schin s = xp->value;
4134887Schin c = *p++;
4144887Schin while (*p && *p != c)
4154887Schin *s++ = *p++;
4164887Schin *s++ = '/';
4174887Schin xp->op = s - xp->value;
4184887Schin *s++ = 0;
4194887Schin if (*p && *++p && *p != c)
4204887Schin {
4214887Schin while (*p && *p != c)
4224887Schin *s++ = *p++;
4234887Schin *s++ = '/';
4244887Schin }
4254887Schin *s = 0;
4264887Schin xp->next = pp.chop;
4274887Schin pp.chop = xp;
4284887Schin }
4294887Schin break;
4304887Schin case PP_COMMENT:
4314887Schin if (pp.comment = va_arg(ap, PPCOMMENT))
4324887Schin pp.flags |= PP_comment;
4334887Schin else
4344887Schin pp.flags &= ~PP_comment;
4354887Schin break;
4364887Schin case PP_COMPATIBILITY:
4374887Schin set(&pp.state, COMPATIBILITY, va_arg(ap, int));
4384887Schin #if COMPATIBLE
4394887Schin if (pp.initialized)
4404887Schin ppfsm(FSM_COMPATIBILITY, NiL);
4414887Schin #else
4424887Schin if (pp.state & COMPATIBILITY)
4434887Schin error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
4444887Schin #endif
4454887Schin if (pp.state & COMPATIBILITY)
4464887Schin pp.flags |= PP_compatibility;
4474887Schin else
4484887Schin pp.flags &= ~PP_compatibility;
4494887Schin break;
4504887Schin case PP_COMPILE:
4514887Schin if (pp.initialized)
4524887Schin goto before;
4534887Schin pp.state |= COMPILE;
4544887Schin if (!pp.symtab)
4554887Schin pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
4564887Schin if (kp = va_arg(ap, struct ppkeyword*))
4574887Schin for (; s = kp->name; kp++)
4584887Schin {
4594887Schin n = SYM_LEX;
4604887Schin switch (*s)
4614887Schin {
4624887Schin case '-':
4634887Schin s++;
4644887Schin break;
4654887Schin case '+':
4664887Schin s++;
4674887Schin if (!(pp.option & PLUSPLUS))
4684887Schin break;
4694887Schin /*FALLTHROUGH*/
4704887Schin default:
4714887Schin n |= SYM_KEYWORD;
4724887Schin break;
4734887Schin }
4744887Schin if (key = ppkeyset(pp.symtab, s))
4754887Schin {
4764887Schin key->sym.flags = n;
4774887Schin key->lex = kp->value;
4784887Schin }
4794887Schin }
4804887Schin break;
4814887Schin case PP_DEBUG:
4824887Schin error_info.trace = va_arg(ap, int);
4834887Schin break;
4844887Schin case PP_DEFAULT:
4854887Schin if (p = va_arg(ap, char*))
4864887Schin p = strdup(p);
4874887Schin if (pp.ppdefault)
4884887Schin free(pp.ppdefault);
4894887Schin pp.ppdefault = p;
4904887Schin break;
4914887Schin case PP_DONE:
4924887Schin #if CHECKPOINT
4934887Schin if (pp.mode & DUMP)
4944887Schin ppdump();
4954887Schin #endif
4964887Schin if (pp.mode & FILEDEPS)
4974887Schin {
4984887Schin sfputc(pp.filedeps.sp, '\n');
4994887Schin if (pp.filedeps.sp == sfstdout)
5004887Schin sfsync(pp.filedeps.sp);
5014887Schin else
5024887Schin sfclose(pp.filedeps.sp);
5034887Schin }
5044887Schin if (pp.state & STANDALONE)
5054887Schin {
5064887Schin if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
5074887Schin ppputchar('\n');
5084887Schin ppflushout();
5094887Schin }
5104887Schin error_info.file = 0;
5114887Schin break;
5124887Schin case PP_DUMP:
5134887Schin set(&pp.mode, DUMP, va_arg(ap, int));
5144887Schin #if !CHECKPOINT
5154887Schin if (pp.mode & DUMP)
5164887Schin error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
5174887Schin #endif
5184887Schin break;
5194887Schin case PP_FILEDEPS:
5204887Schin if (n = va_arg(ap, int))
5214887Schin pp.filedeps.flags |= n;
5224887Schin else
5234887Schin pp.filedeps.flags = 0;
5244887Schin break;
5254887Schin case PP_FILENAME:
5264887Schin error_info.file = va_arg(ap, char*);
5274887Schin break;
5284887Schin case PP_HOSTDIR:
5294887Schin if (!(pp.mode & INIT))
5304887Schin pp.ro_mode |= HOSTED;
5314887Schin else if (pp.ro_mode & HOSTED)
5324887Schin break;
5334887Schin pp.ro_mode |= INIT;
5344887Schin p = va_arg(ap, char*);
5354887Schin c = va_arg(ap, int);
5364887Schin pp.hostdir.path = 0;
5374887Schin if (!p)
5384887Schin pp.hosted = c;
5394887Schin else if (streq(p, "-"))
5404887Schin {
5414887Schin if (pp.initialized)
5424887Schin set(&pp.mode, HOSTED, c);
5434887Schin else
5444887Schin {
5454887Schin pp.hosted = c ? 1 : 2;
5464887Schin for (dp = pp.firstdir; dp; dp = dp->next)
5474887Schin if (pp.hosted == 1)
5484887Schin dp->type |= TYPE_HOSTED;
5494887Schin else
5504887Schin dp->type &= ~TYPE_HOSTED;
5514887Schin }
5524887Schin }
5534887Schin else if (!pp.hosted)
5544887Schin {
5554887Schin if (!*p || stat((pathcanon(p, 0), p), &st))
5564887Schin pp.hosted = 1;
5574887Schin else
5584887Schin {
5594887Schin for (dp = pp.firstdir; dp; dp = dp->next)
5604887Schin {
5614887Schin if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
5624887Schin pp.hosted = 1;
5634887Schin if (pp.hosted == 1)
5644887Schin dp->type |= TYPE_HOSTED;
5654887Schin else
5664887Schin dp->type &= ~TYPE_HOSTED;
5674887Schin }
5684887Schin if (!pp.hosted)
5694887Schin {
5704887Schin pp.hostdir.path = p;
5714887Schin SAVEID(&pp.hostdir.id, &st);
5724887Schin }
5734887Schin }
5744887Schin }
5754887Schin break;
5764887Schin case PP_ID:
5774887Schin p = va_arg(ap, char*);
5784887Schin c = va_arg(ap, int);
5794887Schin if (p)
5804887Schin ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
5814887Schin break;
5824887Schin case PP_IGNORE:
5834887Schin if (p = va_arg(ap, char*))
5844887Schin {
5854887Schin pathcanon(p, 0);
5864887Schin ppsetfile(p)->guard = INC_IGNORE;
5874887Schin message((-3, "%s: ignore", p));
5884887Schin }
5894887Schin break;
5904887Schin case PP_IGNORELIST:
5914887Schin if (pp.initialized)
5924887Schin goto before;
5934887Schin pp.ignore = va_arg(ap, char*);
5944887Schin break;
5954887Schin case PP_INCLUDE:
5964887Schin if ((p = va_arg(ap, char*)) && *p)
5974887Schin {
5984887Schin pathcanon(p, 0);
5994887Schin if (stat(p, &st))
6004887Schin break;
6014887Schin for (dp = pp.stddirs; dp = dp->next;)
6024887Schin if (dp->name && SAMEID(&dp->id, &st))
6034887Schin break;
6044887Schin if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
6054887Schin {
6064887Schin pp.cdir.path = 0;
6074887Schin pp.c = 1;
6084887Schin }
6094887Schin if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
6104887Schin {
6114887Schin pp.hostdir.path = 0;
6124887Schin pp.hosted = 1;
6134887Schin }
6144887Schin if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
6154887Schin pp.hosted = 1;
6164887Schin c = dp && dp->c || pp.c == 1;
6174887Schin n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
6184887Schin if (!dp || dp == pp.lastdir->next)
6194887Schin {
6204887Schin if (dp)
6214887Schin {
6224887Schin c = dp->c;
6234887Schin n = dp->type & TYPE_HOSTED;
6244887Schin }
6254887Schin dp = newof(0, struct ppdirs, 1, 0);
6264887Schin dp->name = p;
6274887Schin SAVEID(&dp->id, &st);
6284887Schin dp->type |= TYPE_INCLUDE;
6294887Schin dp->index = INC_LOCAL + pp.ignoresrc != 0;
6304887Schin dp->next = pp.lastdir->next;
6314887Schin pp.lastdir = pp.lastdir->next = dp;
6324887Schin }
6334887Schin dp->c = c;
6344887Schin if (n)
6354887Schin dp->type |= TYPE_HOSTED;
6364887Schin else
6374887Schin dp->type &= ~TYPE_HOSTED;
6384887Schin }
6394887Schin break;
6404887Schin case PP_INCREF:
6414887Schin pp.incref = va_arg(ap, PPINCREF);
6424887Schin break;
6434887Schin case PP_RESET:
6444887Schin pp.reset.on = 1;
6454887Schin break;
6464887Schin case PP_INIT:
6474887Schin if (pp.initialized)
6484887Schin {
6494887Schin error_info.errors = 0;
6504887Schin error_info.warnings = 0;
6514887Schin }
6524887Schin else
6534887Schin {
6544887Schin /*
6554887Schin * context initialization
6564887Schin */
6574887Schin
6584887Schin if (!initialized)
6594887Schin {
6604887Schin /*
6614887Schin * out of malloc is fatal
6624887Schin */
6634887Schin
6644887Schin memfatal();
6654887Schin
6664887Schin /*
6674887Schin * initialize the error message interface
6684887Schin */
6694887Schin
6704887Schin error_info.version = (char*)pp.version;
6714887Schin #if DEBUG & TRACE_debug
6724887Schin error_info.auxilliary = context;
6734887Schin pptrace(0);
6744887Schin #endif
6754887Schin
6764887Schin /*
6774887Schin * initialize pplex tables
6784887Schin */
6794887Schin
6804887Schin ppfsm(FSM_INIT, NiL);
6814887Schin
6824887Schin /*
6834887Schin * fixed macro stack size -- room for improvement
6844887Schin */
6854887Schin
6864887Schin pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
6874887Schin pp.macp->next = pp.macp + 1;
6884887Schin pp.maxmac = (char*)pp.macp + DEFMACSTACK;
6894887Schin initialized = 1;
6904887Schin
6914887Schin /*
6924887Schin * initial include/if control stack
6934887Schin */
6944887Schin
6954887Schin pp.control = newof(0, long, pp.constack, 0);
6964887Schin pp.maxcon = pp.control + pp.constack - 1;
6974887Schin }
6984887Schin
6994887Schin /*
7004887Schin * validate modes
7014887Schin */
7024887Schin
7034887Schin switch (pp.arg_mode)
7044887Schin {
7054887Schin case 'a':
7064887Schin case 'C':
7074887Schin ppop(PP_COMPATIBILITY, 0);
7084887Schin ppop(PP_TRANSITION, 1);
7094887Schin break;
7104887Schin case 'A':
7114887Schin case 'c':
7124887Schin ppop(PP_COMPATIBILITY, 0);
7134887Schin ppop(PP_STRICT, 1);
7144887Schin break;
7154887Schin case 'f':
7164887Schin ppop(PP_COMPATIBILITY, 1);
7174887Schin ppop(PP_PLUSPLUS, 1);
7184887Schin ppop(PP_TRANSITION, 1);
7194887Schin break;
7204887Schin case 'F':
7214887Schin ppop(PP_COMPATIBILITY, 0);
7224887Schin ppop(PP_PLUSPLUS, 1);
7234887Schin break;
7244887Schin case 'k':
7254887Schin case 's':
7264887Schin ppop(PP_COMPATIBILITY, 1);
7274887Schin ppop(PP_STRICT, 1);
7284887Schin break;
7294887Schin case 'o':
7304887Schin case 'O':
7314887Schin ppop(PP_COMPATIBILITY, 1);
7324887Schin ppop(PP_TRANSITION, 0);
7334887Schin break;
7344887Schin case 't':
7354887Schin ppop(PP_COMPATIBILITY, 1);
7364887Schin ppop(PP_TRANSITION, 1);
7374887Schin break;
7384887Schin }
7398462SApril.Chin@Sun.COM if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
7404887Schin ppop(PP_PEDANTIC, 1);
7414887Schin if (pp.state & PASSTHROUGH)
7424887Schin {
7434887Schin if (pp.state & COMPILE)
7444887Schin {
7454887Schin pp.state &= ~PASSTHROUGH;
7464887Schin error(1, "passthrough ignored for compile");
7474887Schin }
7484887Schin else
7494887Schin {
7504887Schin ppop(PP_COMPATIBILITY, 1);
7514887Schin ppop(PP_HOSTDIR, "-", 1);
7524887Schin ppop(PP_SPACEOUT, 1);
7534887Schin set(&pp.state, DISABLE, va_arg(ap, int));
7544887Schin }
7554887Schin }
7564887Schin
7574887Schin /*
7584887Schin * create the hash tables
7594887Schin */
7604887Schin
7614887Schin if (!pp.symtab)
7624887Schin pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
7634887Schin if (!pp.dirtab)
7644887Schin {
7654887Schin pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
7664887Schin inithash(pp.dirtab, directives);
7674887Schin }
7684887Schin if (!pp.filtab)
7694887Schin pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
7704887Schin if (!pp.prdtab)
7714887Schin pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
7724887Schin if (!pp.strtab)
7734887Schin {
7744887Schin pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
7754887Schin inithash(pp.strtab, options);
7764887Schin inithash(pp.strtab, predicates);
7774887Schin inithash(pp.strtab, variables);
7784887Schin }
7794887Schin pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
7804887Schin pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
7814887Schin
7824887Schin /*
7834887Schin * mark macros that are builtin predicates
7844887Schin */
7854887Schin
7864887Schin for (kp = predicates; s = kp->name; kp++)
7874887Schin {
7884887Schin if (!ppisid(*s))
7894887Schin s++;
7904887Schin ppassert(DEFINE, s, 0);
7914887Schin }
7924887Schin
7934887Schin /*
7944887Schin * the remaining entry names must be allocated
7954887Schin */
7964887Schin
7974887Schin hashset(pp.dirtab, HASH_ALLOCATE);
7984887Schin hashset(pp.filtab, HASH_ALLOCATE);
7994887Schin hashset(pp.prdtab, HASH_ALLOCATE);
8004887Schin hashset(pp.strtab, HASH_ALLOCATE);
8014887Schin hashset(pp.symtab, HASH_ALLOCATE);
8024887Schin if (pp.test & TEST_nonoise)
8034887Schin {
8044887Schin c = error_info.trace;
8054887Schin error_info.trace = 0;
8064887Schin }
8074887Schin #if DEBUG
8084887Schin if (!(pp.test & TEST_noinit))
8094887Schin {
8104887Schin #endif
8114887Schin
8124887Schin /*
8134887Schin * compose, push and read the builtin initialization script
8144887Schin */
8154887Schin
8164887Schin if (!(sp = sfstropen()))
8174887Schin error(3, "temporary buffer allocation error");
8184887Schin sfprintf(sp,
8194887Schin "\
8204887Schin #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
8214887Schin #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
8224887Schin ",
8234887Schin dirname(PRAGMA),
8244887Schin pp.pass,
8254887Schin keyname(X_MAP),
8264887Schin dirname(DEFINE),
8274887Schin dirname(PRAGMA),
8284887Schin pp.pass,
8294887Schin keyname(X_MAP),
8304887Schin dirname(UNDEF));
8314887Schin if (pp.ppdefault && *pp.ppdefault)
8324887Schin {
8334887Schin if (pp.probe)
8344887Schin {
8354887Schin c = pp.lastdir->next->type;
8364887Schin pp.lastdir->next->type = 0;
8374887Schin }
8384887Schin if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
8394887Schin {
8404887Schin free(pp.ppdefault);
8414887Schin if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0)))
8424887Schin error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
8434887Schin }
8444887Schin if (pp.probe)
8454887Schin pp.lastdir->next->type = c;
8464887Schin }
8474887Schin while (pp.firstop)
8484887Schin {
8494887Schin switch (pp.firstop->op)
8504887Schin {
8514887Schin case PP_ASSERT:
8524887Schin sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
8534887Schin break;
8544887Schin case PP_DEFINE:
8554887Schin if (*pp.firstop->value == '#')
8564887Schin sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
8574887Schin else
8584887Schin {
8594887Schin if (s = strchr(pp.firstop->value, '='))
8604887Schin sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
8614887Schin else
8624887Schin sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
8634887Schin }
8644887Schin break;
8654887Schin case PP_DIRECTIVE:
8664887Schin sfprintf(sp, "#%s\n", pp.firstop->value);
8674887Schin break;
8684887Schin case PP_OPTION:
8694887Schin if (s = strchr(pp.firstop->value, '='))
8704887Schin sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
8714887Schin else
8724887Schin sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
8734887Schin break;
8744887Schin case PP_READ:
8754887Schin sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
8764887Schin break;
8774887Schin case PP_UNDEF:
8784887Schin sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
8794887Schin break;
8804887Schin }
8814887Schin pp.lastop = pp.firstop;
8824887Schin pp.firstop = pp.firstop->next;
8834887Schin free(pp.lastop);
8844887Schin }
8854887Schin sfprintf(sp,
8864887Schin "\
8874887Schin #%s %s:%s\n\
8884887Schin #%s %s:%s\n\
8894887Schin #%s !#%s(%s)\n\
8904887Schin #%s !#%s(%s) || #%s(%s)\n\
8914887Schin "
8924887Schin , dirname(PRAGMA)
8934887Schin , pp.pass
8944887Schin , keyname(X_BUILTIN)
8954887Schin , dirname(PRAGMA)
8964887Schin , pp.pass
8974887Schin , keyname(X_PREDEFINED)
8984887Schin , dirname(IF)
8994887Schin , keyname(X_OPTION)
9004887Schin , keyname(X_PLUSPLUS)
9014887Schin , dirname(IF)
9024887Schin , keyname(X_OPTION)
9034887Schin , keyname(X_COMPATIBILITY)
9044887Schin , keyname(X_OPTION)
9054887Schin , keyname(X_TRANSITION)
9064887Schin );
9074887Schin sfprintf(sp,
9084887Schin "\
9094887Schin #%s #%s(%s)\n\
9104887Schin #%s %s:%s\n\
9114887Schin #%s %s:%s\n\
9124887Schin #%s __STRICT__ 1\n\
9134887Schin #%s\n\
9144887Schin #%s\n\
9154887Schin "
9164887Schin , dirname(IF)
9174887Schin , keyname(X_OPTION)
9184887Schin , keyname(X_STRICT)
9194887Schin , dirname(PRAGMA)
9204887Schin , pp.pass
9214887Schin , keyname(X_ALLMULTIPLE)
9224887Schin , dirname(PRAGMA)
9234887Schin , pp.pass
9244887Schin , keyname(X_READONLY)
9254887Schin , dirname(DEFINE)
9264887Schin , dirname(ENDIF)
9274887Schin , dirname(ENDIF)
9284887Schin );
9294887Schin for (kp = readonlys; s = kp->name; kp++)
9304887Schin {
9314887Schin if (!ppisid(*s))
9324887Schin s++;
9334887Schin sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
9344887Schin }
9354887Schin sfprintf(sp,
9364887Schin "\
9374887Schin #%s\n\
9384887Schin #%s __STDPP__ 1\n\
9394887Schin #%s %s:no%s\n\
9404887Schin "
9414887Schin , dirname(ENDIF)
9424887Schin , dirname(DEFINE)
9434887Schin , dirname(PRAGMA)
9444887Schin , pp.pass
9454887Schin , keyname(X_PREDEFINED)
9464887Schin );
9474887Schin if (!pp.truncate)
9484887Schin sfprintf(sp,
9494887Schin "\
9504887Schin #%s __STDPP__directive #(%s)\n\
9514887Schin "
9524887Schin , dirname(DEFINE)
9534887Schin , keyname(V_DIRECTIVE)
9544887Schin );
9554887Schin for (kp = variables; s = kp->name; kp++)
9564887Schin if (ppisid(*s) || *s++ == '+')
9574887Schin {
9584887Schin t = *s == '_' ? "" : "__";
9594887Schin sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
9604887Schin }
9614887Schin sfprintf(sp,
9624887Schin "\
9634887Schin #%s %s:no%s\n\
9644887Schin #%s %s:no%s\n\
9654887Schin "
9664887Schin , dirname(PRAGMA)
9674887Schin , pp.pass
9684887Schin , keyname(X_READONLY)
9694887Schin , dirname(PRAGMA)
9704887Schin , pp.pass
9714887Schin , keyname(X_BUILTIN)
9724887Schin );
973*10898Sroland.mainz@nrubsig.org if (pp.ppdefault && *pp.ppdefault)
974*10898Sroland.mainz@nrubsig.org sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
975*10898Sroland.mainz@nrubsig.org sfprintf(sp,
976*10898Sroland.mainz@nrubsig.org "\
977*10898Sroland.mainz@nrubsig.org #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
978*10898Sroland.mainz@nrubsig.org #%s __STDC__ #(STDC)\n\
979*10898Sroland.mainz@nrubsig.org #%s\n\
980*10898Sroland.mainz@nrubsig.org "
981*10898Sroland.mainz@nrubsig.org , dirname(IF)
982*10898Sroland.mainz@nrubsig.org , dirname(DEFINE)
983*10898Sroland.mainz@nrubsig.org , dirname(ENDIF)
984*10898Sroland.mainz@nrubsig.org );
9854887Schin t = sfstruse(sp);
9864887Schin debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
9874887Schin ppcomment = pp.comment;
9884887Schin pp.comment = 0;
9894887Schin pplinesync = pp.linesync;
9904887Schin pp.linesync = 0;
9914887Schin PUSH_INIT(pp.pass, t);
9924887Schin pp.mode |= INIT;
9934887Schin while (pplex());
9944887Schin pp.mode &= ~INIT;
9954887Schin pp.comment = ppcomment;
9964887Schin pp.linesync = pplinesync;
9974887Schin pp.prefix = 0;
9984887Schin sfstrclose(sp);
9994887Schin if (error_info.trace)
10004887Schin for (dp = pp.firstdir; dp; dp = dp->next)
10014887Schin message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
10024887Schin #if DEBUG
10034887Schin }
10044887Schin if (pp.test & TEST_nonoise)
10054887Schin error_info.trace = c;
10064887Schin #endif
10074887Schin {
10084887Schin /*
10094887Schin * this is sleazy but at least it's
10104887Schin * hidden in the library
10114887Schin */
10124887Schin #include <preroot.h>
10134887Schin #if FS_PREROOT
10144887Schin struct pplist* preroot;
10154887Schin
10164887Schin if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
10174887Schin setpreroot(NiL, preroot->value);
10184887Schin #endif
10194887Schin }
10204887Schin if (pp.ignoresrc)
10214887Schin {
10224887Schin if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
10234887Schin error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
10244887Schin pp.lcldirs = pp.lcldirs->next;
10254887Schin }
10264887Schin if (pp.ignore)
10274887Schin {
10284887Schin if (*pp.ignore)
10294887Schin ppmapinclude(pp.ignore, NiL);
10304887Schin else
10314887Schin pp.ignore = 0;
10324887Schin }
10334887Schin if (pp.standalone)
10344887Schin pp.state |= STANDALONE;
10354887Schin #if COMPATIBLE
10364887Schin ppfsm(FSM_COMPATIBILITY, NiL);
10374887Schin #endif
10384887Schin ppfsm(FSM_PLUSPLUS, NiL);
10394887Schin pp.initialized = 1;
10404887Schin if (pp.reset.on)
10414887Schin {
10424887Schin pp.reset.symtab = pp.symtab;
10434887Schin pp.symtab = 0;
10444887Schin pp.reset.ro_state = pp.ro_state;
10454887Schin pp.reset.ro_mode = pp.ro_mode;
10464887Schin pp.reset.ro_option = pp.ro_option;
10474887Schin }
10484887Schin }
10494887Schin if (pp.reset.on)
10504887Schin {
10514887Schin if (pp.symtab)
10524887Schin {
10534887Schin hashwalk(pp.filtab, 0, unguard, NiL);
10544887Schin hashfree(pp.symtab);
10554887Schin }
10564887Schin pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
10574887Schin hashview(pp.symtab, pp.reset.symtab);
10584887Schin pp.ro_state = pp.reset.ro_state;
10594887Schin pp.ro_mode = pp.reset.ro_mode;
10604887Schin pp.ro_option = pp.reset.ro_option;
10614887Schin }
10624887Schin #if CHECKPOINT
10634887Schin if (pp.mode & DUMP)
10644887Schin {
10654887Schin if (!pp.pragma)
10664887Schin error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
10674887Schin (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
10684887Schin }
10694887Schin #endif
10704887Schin if (n = pp.filedeps.flags)
10714887Schin {
10724887Schin if (!(n & PP_deps_file))
10734887Schin {
10744887Schin pp.state |= NOTEXT;
10754887Schin pp.option |= KEEPNOTEXT;
10764887Schin pp.linesync = 0;
10774887Schin }
10784887Schin if (n & PP_deps_generated)
10794887Schin pp.mode |= GENDEPS;
10804887Schin if (n & PP_deps_local)
10814887Schin pp.mode &= ~HEADERDEPS;
10824887Schin else if (!(pp.mode & FILEDEPS))
10834887Schin pp.mode |= HEADERDEPS;
10844887Schin pp.mode |= FILEDEPS;
10854887Schin }
10864887Schin
10874887Schin /*
10884887Schin * push the main input file -- special case for hosted mark
10894887Schin */
10904887Schin
10914887Schin if (pp.firstdir->type & TYPE_HOSTED)
10924887Schin pp.mode |= MARKHOSTED;
10934887Schin else
10944887Schin pp.mode &= ~MARKHOSTED;
10954887Schin #if CHECKPOINT
10964887Schin if (!(pp.mode & DUMP))
10974887Schin #endif
10984887Schin {
10994887Schin if (!(p = error_info.file))
11004887Schin p = "";
11014887Schin else
11024887Schin {
11034887Schin error_info.file = 0;
11044887Schin if (*p)
11054887Schin {
11064887Schin pathcanon(p, 0);
11074887Schin p = ppsetfile(p)->name;
11084887Schin }
11094887Schin }
11104887Schin PUSH_FILE(p, 0);
11114887Schin }
11124887Schin if (pp.mode & FILEDEPS)
11134887Schin {
11144887Schin if (s = strrchr(error_info.file, '/'))
11154887Schin s++;
11164887Schin else
11174887Schin s = error_info.file;
11184887Schin if (!*s)
11194887Schin s = "-";
11204887Schin s = strcpy(pp.tmpbuf, s);
11214887Schin if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
11224887Schin {
11234887Schin if (c = *++p)
11244887Schin while (*++p == c);
11254887Schin if (*p)
11264887Schin t = 0;
11274887Schin else
11284887Schin t++;
11294887Schin }
11304887Schin if (!t)
11314887Schin {
11324887Schin t = s + strlen(s);
11334887Schin *t++ = '.';
11344887Schin }
11354887Schin *(t + 1) = 0;
11364887Schin if (pp.state & NOTEXT)
11374887Schin pp.filedeps.sp = sfstdout;
11384887Schin else
11394887Schin {
11404887Schin *t = 'd';
11414887Schin if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
11424887Schin error(ERROR_SYSTEM|3, "%s: cannot create", s);
11434887Schin }
11444887Schin *t = 'o';
11454887Schin pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
11464887Schin if (*error_info.file)
11474887Schin pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
11484887Schin }
11494887Schin if (xp = pp.firsttx)
11504887Schin {
11514887Schin if (!(sp = sfstropen()))
11524887Schin error(3, "temporary buffer allocation error");
11534887Schin while (xp)
11544887Schin {
11554887Schin sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
11564887Schin xp = xp->next;
11574887Schin }
11584887Schin t = sfstruse(sp);
11594887Schin PUSH_BUFFER("options", t, 1);
11604887Schin sfstrclose(sp);
11614887Schin }
11624887Schin break;
11634887Schin case PP_INPUT:
11644887Schin #if CHECKPOINT && POOL
11654887Schin if (!(pp.mode & DUMP) || pp.pool.input)
11664887Schin #else
11674887Schin #if CHECKPOINT
11684887Schin if (!(pp.mode & DUMP))
11694887Schin #else
11704887Schin #if POOL
11714887Schin if (pp.pool.input)
11724887Schin #endif
11734887Schin #endif
11744887Schin #endif
11754887Schin {
11764887Schin p = va_arg(ap, char*);
11774887Schin if (!error_info.file)
11784887Schin error_info.file = p;
11794887Schin close(0);
11804887Schin if (open(p, O_RDONLY) != 0)
11814887Schin error(ERROR_SYSTEM|3, "%s: cannot read", p);
11824887Schin if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
11834887Schin {
11844887Schin set(&pp.mode, CATLITERAL, 0);
11854887Schin ppop(PP_SPACEOUT, 1);
11864887Schin }
11874887Schin break;
11884887Schin }
11894887Schin /*FALLTHROUGH*/
11904887Schin case PP_TEXT:
11914887Schin if (pp.initialized)
11924887Schin goto before;
11934887Schin if ((p = va_arg(ap, char*)) && *p)
11944887Schin {
11954887Schin if (pp.lasttx)
11964887Schin pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
11974887Schin else
11984887Schin pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
11994887Schin pp.lasttx->op = op;
12004887Schin pp.lasttx->value = p;
12014887Schin }
12024887Schin break;
12034887Schin case PP_KEYARGS:
12044887Schin if (pp.initialized)
12054887Schin goto before;
12064887Schin set(&pp.option, KEYARGS, va_arg(ap, int));
12074887Schin if (pp.option & KEYARGS)
12084887Schin #if MACKEYARGS
12094887Schin set(&pp.mode, CATLITERAL, 1);
12104887Schin #else
12114887Schin error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
12124887Schin #endif
12134887Schin break;
12144887Schin case PP_LINE:
12154887Schin pp.linesync = va_arg(ap, PPLINESYNC);
12164887Schin break;
12174887Schin case PP_LINEBASE:
12184887Schin if (va_arg(ap, int))
12194887Schin pp.flags |= PP_linebase;
12204887Schin else
12214887Schin pp.flags &= ~PP_linebase;
12224887Schin break;
12234887Schin case PP_LINEFILE:
12244887Schin if (va_arg(ap, int))
12254887Schin pp.flags |= PP_linefile;
12264887Schin else
12274887Schin pp.flags &= ~PP_linefile;
12284887Schin break;
12294887Schin case PP_LINEID:
12304887Schin if (!(p = va_arg(ap, char*)))
12314887Schin pp.lineid = "";
12324887Schin else if (*p != '-')
12334887Schin pp.lineid = strdup(p);
12344887Schin else
12354887Schin pp.option |= IGNORELINE;
12364887Schin break;
12374887Schin case PP_LINETYPE:
12384887Schin if ((n = va_arg(ap, int)) >= 1)
12394887Schin pp.flags |= PP_linetype;
12404887Schin else
12414887Schin pp.flags &= ~PP_linetype;
12424887Schin if (n >= 2)
12434887Schin pp.flags |= PP_linehosted;
12444887Schin else
12454887Schin pp.flags &= ~PP_linehosted;
12464887Schin break;
12474887Schin case PP_LOCAL:
12484887Schin if (pp.initialized)
12494887Schin goto before;
12504887Schin pp.ignoresrc++;
12514887Schin pp.stddirs = pp.lastdir;
12524887Schin if (!(pp.ro_option & PREFIX))
12534887Schin pp.option &= ~PREFIX;
12544887Schin break;
12554887Schin case PP_MACREF:
12564887Schin pp.macref = va_arg(ap, PPMACREF);
12574887Schin break;
12584887Schin case PP_MULTIPLE:
12594887Schin set(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
12604887Schin break;
12614887Schin case PP_NOHASH:
12624887Schin set(&pp.option, NOHASH, va_arg(ap, int));
12634887Schin break;
12644887Schin case PP_NOISE:
12654887Schin op = va_arg(ap, int);
12664887Schin set(&pp.option, NOISE, op);
12674887Schin set(&pp.option, NOISEFILTER, op < 0);
12684887Schin break;
12694887Schin case PP_OPTARG:
12704887Schin pp.optarg = va_arg(ap, PPOPTARG);
12714887Schin break;
12724887Schin case PP_OUTPUT:
12734887Schin pp.outfile = va_arg(ap, char*);
12744887Schin if (identical(pp.outfile, 0))
12754887Schin error(3, "%s: identical to input", pp.outfile);
12764887Schin close(1);
12774887Schin if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
12784887Schin error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
12794887Schin break;
12804887Schin case PP_PASSTHROUGH:
12814887Schin if (!(pp.state & COMPILE))
12824887Schin set(&pp.state, PASSTHROUGH, va_arg(ap, int));
12834887Schin break;
12844887Schin case PP_PEDANTIC:
12854887Schin set(&pp.mode, PEDANTIC, va_arg(ap, int));
12864887Schin break;
12874887Schin case PP_PLUSCOMMENT:
12884887Schin set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
12894887Schin if (pp.initialized)
12904887Schin ppfsm(FSM_PLUSPLUS, NiL);
12914887Schin break;
12924887Schin case PP_PLUSPLUS:
12934887Schin set(&pp.option, PLUSPLUS, va_arg(ap, int));
12944887Schin set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
12954887Schin if (pp.initialized)
12964887Schin ppfsm(FSM_PLUSPLUS, NiL);
12974887Schin break;
12984887Schin case PP_POOL:
12994887Schin if (pp.initialized)
13004887Schin goto before;
13014887Schin if (va_arg(ap, int))
13024887Schin {
13034887Schin #if POOL
13044887Schin pp.pool.input = dup(0);
13054887Schin pp.pool.output = dup(1);
13064887Schin p = "/dev/null";
13074887Schin if (!identical(p, 0))
13084887Schin {
13094887Schin if (!identical(p, 1))
13104887Schin ppop(PP_OUTPUT, p);
13114887Schin ppop(PP_INPUT, p);
13124887Schin }
13134887Schin #else
13144887Schin error(3, "preprocessor not compiled with input pool enabled [POOL]");
13154887Schin #endif
13164887Schin }
13174887Schin break;
13184887Schin case PP_PRAGMA:
13194887Schin pp.pragma = va_arg(ap, PPPRAGMA);
13204887Schin break;
13214887Schin case PP_PRAGMAFLAGS:
13224887Schin if (p = va_arg(ap, char*))
13234887Schin {
13244887Schin n = OPT_GLOBAL;
13254887Schin if (*p == '-')
13264887Schin p++;
13274887Schin else
13284887Schin n |= OPT_PASS;
13294887Schin if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
13304887Schin pp.optflags[c] = n;
13314887Schin }
13324887Schin break;
13334887Schin case PP_PROBE:
13344887Schin pp.probe = va_arg(ap, char*);
13354887Schin break;
13364887Schin case PP_QUOTE:
13374887Schin p = va_arg(ap, char*);
13384887Schin c = va_arg(ap, int);
13394887Schin if (p)
13404887Schin ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
13414887Schin break;
13424887Schin case PP_REGUARD:
13434887Schin set(&pp.option, REGUARD, va_arg(ap, int));
13444887Schin break;
13454887Schin case PP_RESERVED:
13464887Schin if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
13474887Schin {
13484887Schin if (!(sp = sfstropen()))
13494887Schin error(3, "temporary buffer allocation error");
13504887Schin sfputr(sp, p, -1);
13514887Schin p = sfstruse(sp);
13524887Schin if (s = strchr(p, '='))
13534887Schin *s++ = 0;
13544887Schin else
13554887Schin s = p;
13564887Schin while (*s == '_')
13574887Schin s++;
13584887Schin for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
13594887Schin if (*t == '_')
13604887Schin *t = 0;
13614887Schin else
13624887Schin t = 0;
13634887Schin op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
13644887Schin if (pp.test & 0x0400)
13654887Schin error(1, "reserved#1 `%s' %d", s, op);
13664887Schin if (t)
13674887Schin *t = '_';
13684887Schin if (!(key = ppkeyget(pp.symtab, p)))
13694887Schin key = ppkeyset(pp.symtab, NiL);
13704887Schin else if (!(key->sym.flags & SYM_LEX))
13714887Schin {
13724887Schin struct ppsymbol tmp;
13734887Schin
13744887Schin tmp = key->sym;
13754887Schin hashlook(pp.symtab, p, HASH_DELETE, NiL);
13764887Schin key = ppkeyset(pp.symtab, NiL);
13774887Schin key->sym.flags = tmp.flags;
13784887Schin key->sym.macro = tmp.macro;
13794887Schin key->sym.value = tmp.value;
13804887Schin key->sym.hidden = tmp.hidden;
13814887Schin }
13824887Schin if (!(key->sym.flags & SYM_KEYWORD))
13834887Schin {
13844887Schin key->sym.flags |= SYM_KEYWORD|SYM_LEX;
13854887Schin key->lex = op;
13864887Schin if (pp.test & 0x0400)
13874887Schin error(1, "reserved#2 `%s' %d", p, op);
13884887Schin }
13894887Schin sfstrclose(sp);
13904887Schin }
13914887Schin break;
13924887Schin case PP_SPACEOUT:
13934887Schin set(&pp.state, SPACEOUT, va_arg(ap, int));
13944887Schin break;
13954887Schin case PP_STANDALONE:
13964887Schin if (pp.initialized)
13974887Schin goto before;
13984887Schin pp.standalone = 1;
13994887Schin break;
14004887Schin case PP_STANDARD:
14014887Schin if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
14024887Schin SAVEID(&pp.lastdir->next->id, &st);
14034887Schin for (dp = pp.firstdir; dp; dp = dp->next)
14044887Schin if (dp->name)
14054887Schin for (hp = pp.firstdir; hp != dp; hp = hp->next)
14064887Schin if (hp->name && SAMEID(&hp->id, &dp->id))
14074887Schin {
14084887Schin hp->c = dp->c;
14094887Schin if (dp->type & TYPE_HOSTED)
14104887Schin hp->type |= TYPE_HOSTED;
14114887Schin else
14124887Schin hp->type &= ~TYPE_HOSTED;
14134887Schin }
14144887Schin break;
14154887Schin case PP_STRICT:
14164887Schin set(&pp.state, TRANSITION, 0);
14174887Schin pp.flags &= ~PP_transition;
14184887Schin set(&pp.state, STRICT, va_arg(ap, int));
14194887Schin if (pp.state & STRICT)
14204887Schin pp.flags |= PP_strict;
14214887Schin else
14224887Schin pp.flags &= ~PP_strict;
14234887Schin break;
14244887Schin case PP_TEST:
14254887Schin if (p = va_arg(ap, char*))
14264887Schin for (;;)
14274887Schin {
14284887Schin while (*p == ' ' || *p == '\t') p++;
14294887Schin for (s = p; n = *s; s++)
14304887Schin if (n == ',' || n == ' ' || n == '\t')
14314887Schin {
14324887Schin *s++ = 0;
14334887Schin break;
14344887Schin }
14354887Schin if (!*p)
14364887Schin break;
14374887Schin n = 0;
14384887Schin if (*p == 'n' && *(p + 1) == 'o')
14394887Schin {
14404887Schin p += 2;
14414887Schin op = 0;
14424887Schin }
14434887Schin else
14444887Schin op = 1;
14454887Schin if (streq(p, "count"))
14464887Schin n = TEST_count;
14474887Schin else if (streq(p, "hashcount"))
14484887Schin n = TEST_hashcount;
14494887Schin else if (streq(p, "hashdump"))
14504887Schin n = TEST_hashdump;
14514887Schin else if (streq(p, "hit"))
14524887Schin n = TEST_hit;
14534887Schin else if (streq(p, "init"))
14544887Schin n = TEST_noinit|TEST_INVERT;
14554887Schin else if (streq(p, "noise"))
14564887Schin n = TEST_nonoise|TEST_INVERT;
14574887Schin else if (streq(p, "proto"))
14584887Schin n = TEST_noproto|TEST_INVERT;
14594887Schin else if (*p >= '0' && *p <= '9')
14604887Schin n = strtoul(p, NiL, 0);
14614887Schin else
14624887Schin {
14634887Schin error(1, "%s: unknown test", p);
14644887Schin break;
14654887Schin }
14664887Schin if (n & TEST_INVERT)
14674887Schin {
14684887Schin n &= ~TEST_INVERT;
14694887Schin op = !op;
14704887Schin }
14714887Schin if (op)
14724887Schin pp.test |= n;
14734887Schin else
14744887Schin pp.test &= ~n;
14754887Schin p = s;
14764887Schin debug((-4, "test = 0%o", pp.test));
14774887Schin }
14784887Schin break;
14794887Schin case PP_TRANSITION:
14804887Schin set(&pp.state, STRICT, 0);
14814887Schin pp.flags &= ~PP_strict;
14824887Schin set(&pp.state, TRANSITION, va_arg(ap, int));
14834887Schin if (pp.state & TRANSITION)
14844887Schin pp.flags |= PP_transition;
14854887Schin else
14864887Schin pp.flags &= ~PP_transition;
14874887Schin break;
14884887Schin case PP_TRUNCATE:
14894887Schin if (pp.initialized)
14904887Schin goto before;
14914887Schin if ((op = va_arg(ap, int)) < 0)
14924887Schin op = 0;
14934887Schin set(&pp.option, TRUNCATE, op);
14944887Schin if (pp.option & TRUNCATE)
14954887Schin {
14964887Schin Hash_bucket_t* b;
14974887Schin Hash_bucket_t* p;
14984887Schin Hash_position_t* pos;
14994887Schin Hash_table_t* tab;
15004887Schin
15014887Schin pp.truncate = op;
15024887Schin tab = pp.symtab;
15034887Schin pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
15044887Schin if (tab && (pos = hashscan(tab, 0)))
15054887Schin {
15064887Schin if (p = hashnext(pos))
15074887Schin do
15084887Schin {
15094887Schin b = hashnext(pos);
15104887Schin hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
15114887Schin } while (p = b);
15124887Schin hashdone(pos);
15134887Schin }
15144887Schin }
15154887Schin else
15164887Schin pp.truncate = 0;
15174887Schin break;
15184887Schin case PP_VENDOR:
15194887Schin p = va_arg(ap, char*);
15204887Schin c = va_arg(ap, int) != 0;
15214887Schin if (!p || !*p)
15224887Schin for (dp = pp.firstdir; dp; dp = dp->next)
15234887Schin dp->type &= ~TYPE_VENDOR;
15244887Schin else if (streq(p, "-"))
15254887Schin {
15264887Schin for (dp = pp.firstdir; dp; dp = dp->next)
15274887Schin if (c)
15284887Schin dp->type |= TYPE_VENDOR;
15294887Schin else
15304887Schin dp->type &= ~TYPE_VENDOR;
15314887Schin }
15324887Schin else if (!stat((pathcanon(p, 0), p), &st))
15334887Schin {
15344887Schin c = 0;
15354887Schin for (dp = pp.firstdir; dp; dp = dp->next)
15364887Schin {
15374887Schin if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
15384887Schin c = 1;
15394887Schin if (c)
15404887Schin dp->type |= TYPE_VENDOR;
15414887Schin else
15424887Schin dp->type &= ~TYPE_VENDOR;
15434887Schin }
15444887Schin }
15454887Schin break;
15464887Schin case PP_WARN:
15474887Schin set(&pp.state, WARN, va_arg(ap, int));
15484887Schin break;
15494887Schin before:
15504887Schin error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
15514887Schin break;
15524887Schin default:
15534887Schin error(3, "ppop(%d): invalid preprocessor operation", op);
15544887Schin break;
15554887Schin }
15564887Schin va_end(ap);
15574887Schin }
1558