diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libpp/common/ppop.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libpp/common/ppop.c')
-rw-r--r-- | usr/src/lib/libpp/common/ppop.c | 1553 |
1 files changed, 1553 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/common/ppop.c b/usr/src/lib/libpp/common/ppop.c new file mode 100644 index 0000000000..86e3651864 --- /dev/null +++ b/usr/src/lib/libpp/common/ppop.c @@ -0,0 +1,1553 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor library control interface + */ + +#include "pplib.h" +#include "pptab.h" + +#include <ls.h> + +#define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab) +#define REFALL (pp.truncate?pp.dirtab:pp.symtab) + +#define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value) + +/* + * set option value + * initialization files have lowest precedence + */ + +static void +set(register long* p, register long op, int val) +{ + long* r; + + r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option; + if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op)) + { + if (!pp.initialized && !(pp.mode & INIT)) + *r |= op; + if (val) + *p |= op; + else + *p &= ~op; + } + 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))); +} + +/* + * initialize hash table with keywords from key + */ + +static void +inithash(register Hash_table_t* tab, register struct ppkeyword* key) +{ + register char* s; + + for (; s = key->name; key++) + { + if (!ppisid(*s)) + s++; + hashput(tab, s, key->value); + } +} + +/* + * return ppkeyword table name given value + */ + +char* +ppkeyname(register int value, int dir) +{ + register char* s; + register struct ppkeyword* p; + + if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p))) + { + s = (p + (value - p->value))->name; + return s + !ppisid(*s); + } +#if DEBUG + error(PANIC, "no keyword table name for value=%d", value); +#endif + return "UNKNOWN"; +} + +/* + * add to the include maps + */ + +void +ppmapinclude(char* file, register char* s) +{ + register int c; + register struct ppdirs* dp; + int fd; + int flags; + int index; + int token; + char* t; + char* old_file; + long old_state; + struct ppfile* fp; + struct ppfile* mp; + + old_file = error_info.file; + old_state = pp.state; + if (s) + PUSH_BUFFER("mapinclude", s, 1); + else if (file) + { + if (*file == '-') + { + if (!error_info.file) + { + error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE)); + return; + } + s = t = strcopy(pp.tmpbuf, error_info.file); + c = *++file; + for (;;) + { + if (s <= pp.tmpbuf || *s == '/') + { + s = t; + break; + } + else if (*s == c) + break; + s--; + } + strcpy(s, file); + file = pp.tmpbuf; + } + if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0) + return; + PUSH_FILE(file, fd); + } + else + return; +#if CATSTRINGS + pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF); +#else + pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF); +#endif + pp.level++; + flags = INC_MAPALL; + fp = mp = 0; + for (;;) + { + switch (token = pplex()) + { + case 0: + case T_STRING: + case T_HEADER: + if (fp) + { + fp->guard = INC_IGNORE; + for (dp = pp.firstdir->next; dp; dp = dp->next) + if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/') + { + ppsetfile(fp->name + c + 1)->guard = INC_IGNORE; + break; + } + } + if (!token) + break; + pathcanon(pp.token, 0); + fp = ppsetfile(pp.token); + if (mp) + { + mp->flags |= flags; + if (streq(fp->name, ".")) + mp->flags |= INC_MAPNOLOCAL; + else + mp->bound[index] = fp; + + fp = mp = 0; + } + else + index = token == T_HEADER ? INC_STANDARD : INC_LOCAL; + continue; + case '=': + if (!(mp = fp)) + error(3, "%s: \"name\" = \"binding\" expected"); + fp = 0; + continue; + case '\n': + continue; + case T_ID: + if (streq(pp.token, "all")) + { + flags = INC_MAPALL; + continue; + } + else if (streq(pp.token, "hosted")) + { + flags = INC_MAPHOSTED; + continue; + } + else if (streq(pp.token, "nohosted")) + { + flags = INC_MAPNOHOSTED; + continue; + } + /*FALLTHROUGH*/ + default: + error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE)); + break; + } + break; + } + pp.level--; + error_info.file = old_file; + pp.state = old_state; +} + +/* + * return non-0 if file is identical to fd + */ + +static int +identical(char* file, int fd) +{ + struct stat a; + struct stat b; + + return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino; +} + +/* + * compare up to pp.truncate chars + * + * NOTE: __STD* and symbols containing ' ' are not truncated + */ + +static int +trunccomp(register char* a, register char* b) +{ + return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b); +} + +/* + * hash up to pp.truncate chars + * + * NOTE: __STD* and symbols containing ' ' are not truncated + */ + +static unsigned int +trunchash(char* a) +{ + int n; + + return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n); +} + +#if DEBUG & TRACE_debug +/* + * append context to debug trace + */ + +static int +context(Sfio_t* sp, int level, int flags) +{ + static int state; + + NoP(level); + NoP(flags); + if (error_info.trace <= -10 && pp.state != state) + { + state = pp.state; + sfprintf(sp, " %s", ppstatestr(pp.state)); + } + return 1; +} +#endif + +/* + * reset include guard + */ + +static int +unguard(const char* name, char* v, void* handle) +{ + register struct ppfile* fp = (struct ppfile*)v; + + fp->guard = 0; + return 0; +} + +/* + * reset macro definition + */ + +static void +undefine(void* p) +{ + struct ppmacro* mac = ((struct ppsymbol*)p)->macro; + + if (mac) + { + if (mac->formals) + free(mac->formals); + free(mac->value); + free(mac); + } +} + +/* + * pp operations + * + * NOTE: PP_INIT must be done before the first pplex() call + * PP_DONE must be done after the last pplex() call + * PP_INIT-PP_DONE must be done for each new PP_INPUT + */ + +void +ppop(int op, ...) +{ + va_list ap; + register char* p; + register struct ppkeyword* kp; + register char* s; + int c; + long n; + char* t; + struct ppdirs* dp; + struct ppdirs* hp; + struct ppsymkey* key; + struct oplist* xp; + Sfio_t* sp; + struct stat st; + PPCOMMENT ppcomment; + PPLINESYNC pplinesync; + + static int initialized; + + va_start(ap, op); + switch (op) + { + case PP_ASSERT: + case PP_DEFINE: + case PP_DIRECTIVE: + case PP_OPTION: + case PP_READ: + case PP_UNDEF: + if (pp.initialized) + goto before; + if ((p = va_arg(ap, char*)) && *p) + { + if (pp.lastop) + pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0)); + else + pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0); + pp.lastop->op = op; + pp.lastop->value = p; + } + break; + case PP_BUILTIN: + pp.builtin = va_arg(ap, PPBUILTIN); + break; + case PP_CDIR: + p = va_arg(ap, char*); + c = va_arg(ap, int); + pp.cdir.path = 0; + if (!p) + pp.c = c; + else if (streq(p, "-")) + { + pp.c = c; + for (dp = pp.firstdir; dp; dp = dp->next) + dp->c = c; + } + else if (!pp.c) + { + if (!*p || stat((pathcanon(p, 0), p), &st)) + pp.c = c; + else + { + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st))) + pp.c = 1; + dp->c = pp.c == 1; + } + if (!pp.c) + { + pp.cdir.path = p; + SAVEID(&pp.cdir.id, &st); + } + } + } + break; + case PP_CHOP: + if (p = va_arg(ap, char*)) + { + c = strlen(p); + xp = newof(0, struct oplist, 1, c + 1); + xp->value = ((char*)xp) + sizeof(struct oplist); + s = xp->value; + c = *p++; + while (*p && *p != c) + *s++ = *p++; + *s++ = '/'; + xp->op = s - xp->value; + *s++ = 0; + if (*p && *++p && *p != c) + { + while (*p && *p != c) + *s++ = *p++; + *s++ = '/'; + } + *s = 0; + xp->next = pp.chop; + pp.chop = xp; + } + break; + case PP_COMMENT: + if (pp.comment = va_arg(ap, PPCOMMENT)) + pp.flags |= PP_comment; + else + pp.flags &= ~PP_comment; + break; + case PP_COMPATIBILITY: + set(&pp.state, COMPATIBILITY, va_arg(ap, int)); +#if COMPATIBLE + if (pp.initialized) + ppfsm(FSM_COMPATIBILITY, NiL); +#else + if (pp.state & COMPATIBILITY) + error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]"); +#endif + if (pp.state & COMPATIBILITY) + pp.flags |= PP_compatibility; + else + pp.flags &= ~PP_compatibility; + break; + case PP_COMPILE: + if (pp.initialized) + goto before; + pp.state |= COMPILE; + if (!pp.symtab) + pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); + if (kp = va_arg(ap, struct ppkeyword*)) + for (; s = kp->name; kp++) + { + n = SYM_LEX; + switch (*s) + { + case '-': + s++; + break; + case '+': + s++; + if (!(pp.option & PLUSPLUS)) + break; + /*FALLTHROUGH*/ + default: + n |= SYM_KEYWORD; + break; + } + if (key = ppkeyset(pp.symtab, s)) + { + key->sym.flags = n; + key->lex = kp->value; + } + } + break; + case PP_DEBUG: + error_info.trace = va_arg(ap, int); + break; + case PP_DEFAULT: + if (p = va_arg(ap, char*)) + p = strdup(p); + if (pp.ppdefault) + free(pp.ppdefault); + pp.ppdefault = p; + break; + case PP_DONE: +#if CHECKPOINT + if (pp.mode & DUMP) + ppdump(); +#endif + if (pp.mode & FILEDEPS) + { + sfputc(pp.filedeps.sp, '\n'); + if (pp.filedeps.sp == sfstdout) + sfsync(pp.filedeps.sp); + else + sfclose(pp.filedeps.sp); + } + if (pp.state & STANDALONE) + { + if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n') + ppputchar('\n'); + ppflushout(); + } + error_info.file = 0; + break; + case PP_DUMP: + set(&pp.mode, DUMP, va_arg(ap, int)); +#if !CHECKPOINT + if (pp.mode & DUMP) + error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]"); +#endif + break; + case PP_FILEDEPS: + if (n = va_arg(ap, int)) + pp.filedeps.flags |= n; + else + pp.filedeps.flags = 0; + break; + case PP_FILENAME: + error_info.file = va_arg(ap, char*); + break; + case PP_HOSTDIR: + if (!(pp.mode & INIT)) + pp.ro_mode |= HOSTED; + else if (pp.ro_mode & HOSTED) + break; + pp.ro_mode |= INIT; + p = va_arg(ap, char*); + c = va_arg(ap, int); + pp.hostdir.path = 0; + if (!p) + pp.hosted = c; + else if (streq(p, "-")) + { + if (pp.initialized) + set(&pp.mode, HOSTED, c); + else + { + pp.hosted = c ? 1 : 2; + for (dp = pp.firstdir; dp; dp = dp->next) + if (pp.hosted == 1) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + } + else if (!pp.hosted) + { + if (!*p || stat((pathcanon(p, 0), p), &st)) + pp.hosted = 1; + else + { + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st))) + pp.hosted = 1; + if (pp.hosted == 1) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + if (!pp.hosted) + { + pp.hostdir.path = p; + SAVEID(&pp.hostdir.id, &st); + } + } + } + break; + case PP_ID: + p = va_arg(ap, char*); + c = va_arg(ap, int); + if (p) + ppfsm(c ? FSM_IDADD : FSM_IDDEL, p); + break; + case PP_IGNORE: + if (p = va_arg(ap, char*)) + { + pathcanon(p, 0); + ppsetfile(p)->guard = INC_IGNORE; + message((-3, "%s: ignore", p)); + } + break; + case PP_IGNORELIST: + if (pp.initialized) + goto before; + pp.ignore = va_arg(ap, char*); + break; + case PP_INCLUDE: + if ((p = va_arg(ap, char*)) && *p) + { + pathcanon(p, 0); + if (stat(p, &st)) + break; + for (dp = pp.stddirs; dp = dp->next;) + if (dp->name && SAMEID(&dp->id, &st)) + break; + if (pp.cdir.path && SAMEID(&pp.cdir.id, &st)) + { + pp.cdir.path = 0; + pp.c = 1; + } + if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st)) + { + pp.hostdir.path = 0; + pp.hosted = 1; + } + if ((pp.mode & INIT) && !(pp.ro_mode & INIT)) + pp.hosted = 1; + c = dp && dp->c || pp.c == 1; + n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1; + if (!dp || dp == pp.lastdir->next) + { + if (dp) + { + c = dp->c; + n = dp->type & TYPE_HOSTED; + } + dp = newof(0, struct ppdirs, 1, 0); + dp->name = p; + SAVEID(&dp->id, &st); + dp->type |= TYPE_INCLUDE; + dp->index = INC_LOCAL + pp.ignoresrc != 0; + dp->next = pp.lastdir->next; + pp.lastdir = pp.lastdir->next = dp; + } + dp->c = c; + if (n) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + break; + case PP_INCREF: + pp.incref = va_arg(ap, PPINCREF); + break; + case PP_RESET: + pp.reset.on = 1; + break; + case PP_INIT: + if (pp.initialized) + { + error_info.errors = 0; + error_info.warnings = 0; + } + else + { + /* + * context initialization + */ + + if (!initialized) + { + /* + * out of malloc is fatal + */ + + memfatal(); + + /* + * initialize the error message interface + */ + + error_info.version = (char*)pp.version; +#if DEBUG & TRACE_debug + error_info.auxilliary = context; + pptrace(0); +#endif + + /* + * initialize pplex tables + */ + + ppfsm(FSM_INIT, NiL); + + /* + * fixed macro stack size -- room for improvement + */ + + pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0); + pp.macp->next = pp.macp + 1; + pp.maxmac = (char*)pp.macp + DEFMACSTACK; + initialized = 1; + + /* + * initial include/if control stack + */ + + pp.control = newof(0, long, pp.constack, 0); + pp.maxcon = pp.control + pp.constack - 1; + } + + /* + * validate modes + */ + + switch (pp.arg_mode) + { + case 'a': + case 'C': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_TRANSITION, 1); + break; + case 'A': + case 'c': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_STRICT, 1); + break; + case 'f': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_PLUSPLUS, 1); + ppop(PP_TRANSITION, 1); + break; + case 'F': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_PLUSPLUS, 1); + break; + case 'k': + case 's': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_STRICT, 1); + break; + case 'o': + case 'O': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 0); + break; + case 't': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 1); + break; + } + if (!(pp.arg_style & STYLE_gnu)) + ppop(PP_PEDANTIC, 1); + if (pp.state & PASSTHROUGH) + { + if (pp.state & COMPILE) + { + pp.state &= ~PASSTHROUGH; + error(1, "passthrough ignored for compile"); + } + else + { + ppop(PP_COMPATIBILITY, 1); + ppop(PP_HOSTDIR, "-", 1); + ppop(PP_SPACEOUT, 1); + set(&pp.state, DISABLE, va_arg(ap, int)); + } + } + + /* + * create the hash tables + */ + + if (!pp.symtab) + pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); + if (!pp.dirtab) + { + pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0); + inithash(pp.dirtab, directives); + } + if (!pp.filtab) + pp.filtab = hashalloc(REFALL, HASH_name, "files", 0); + if (!pp.prdtab) + pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0); + if (!pp.strtab) + { + pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0); + inithash(pp.strtab, options); + inithash(pp.strtab, predicates); + inithash(pp.strtab, variables); + } + pp.optflags[X_PROTOTYPED] = OPT_GLOBAL; + pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS; + + /* + * mark macros that are builtin predicates + */ + + for (kp = predicates; s = kp->name; kp++) + { + if (!ppisid(*s)) + s++; + ppassert(DEFINE, s, 0); + } + + /* + * the remaining entry names must be allocated + */ + + hashset(pp.dirtab, HASH_ALLOCATE); + hashset(pp.filtab, HASH_ALLOCATE); + hashset(pp.prdtab, HASH_ALLOCATE); + hashset(pp.strtab, HASH_ALLOCATE); + hashset(pp.symtab, HASH_ALLOCATE); + if (pp.test & TEST_nonoise) + { + c = error_info.trace; + error_info.trace = 0; + } +#if DEBUG + if (!(pp.test & TEST_noinit)) + { +#endif + + /* + * compose, push and read the builtin initialization script + */ + + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + sfprintf(sp, +"\ +#%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\ +#%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\ +", + dirname(PRAGMA), + pp.pass, + keyname(X_MAP), + dirname(DEFINE), + dirname(PRAGMA), + pp.pass, + keyname(X_MAP), + dirname(UNDEF)); + if (pp.ppdefault && *pp.ppdefault) + { + if (pp.probe) + { + c = pp.lastdir->next->type; + pp.lastdir->next->type = 0; + } + if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0) + { + free(pp.ppdefault); + if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0))) + error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE); + } + if (pp.ppdefault) + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault); + if (pp.probe) + pp.lastdir->next->type = c; + } + while (pp.firstop) + { + switch (pp.firstop->op) + { + case PP_ASSERT: + sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value); + break; + case PP_DEFINE: + if (*pp.firstop->value == '#') + sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value); + else + { + if (s = strchr(pp.firstop->value, '=')) + sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1); + else + sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value); + } + break; + case PP_DIRECTIVE: + sfprintf(sp, "#%s\n", pp.firstop->value); + break; + case PP_OPTION: + if (s = strchr(pp.firstop->value, '=')) + sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1); + else + sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value); + break; + case PP_READ: + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value); + break; + case PP_UNDEF: + sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value); + break; + } + pp.lastop = pp.firstop; + pp.firstop = pp.firstop->next; + free(pp.lastop); + } + sfprintf(sp, +"\ +#%s %s:%s\n\ +#%s %s:%s\n\ +#%s !#%s(%s)\n\ +#%s !#%s(%s) || #%s(%s)\n\ +" + , dirname(PRAGMA) + , pp.pass + , keyname(X_BUILTIN) + , dirname(PRAGMA) + , pp.pass + , keyname(X_PREDEFINED) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_PLUSPLUS) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_COMPATIBILITY) + , keyname(X_OPTION) + , keyname(X_TRANSITION) + ); + sfprintf(sp, +"\ +#%s __STDC__\n\ +#%s __STDC__ #(STDC)\n\ +#%s\n\ +#%s #%s(%s)\n\ +#%s %s:%s\n\ +#%s %s:%s\n\ +#%s __STRICT__ 1\n\ +#%s\n\ +#%s\n\ +" + , dirname(IFNDEF) + , dirname(DEFINE) + , dirname(ENDIF) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_STRICT) + , dirname(PRAGMA) + , pp.pass + , keyname(X_ALLMULTIPLE) + , dirname(PRAGMA) + , pp.pass + , keyname(X_READONLY) + , dirname(DEFINE) + , dirname(ENDIF) + , dirname(ENDIF) + ); + for (kp = readonlys; s = kp->name; kp++) + { + if (!ppisid(*s)) + s++; + sfprintf(sp, "#%s %s\n", dirname(UNDEF), s); + } + sfprintf(sp, +"\ +#%s\n\ +#%s __STDPP__ 1\n\ +#%s %s:no%s\n\ +" + , dirname(ENDIF) + , dirname(DEFINE) + , dirname(PRAGMA) + , pp.pass + , keyname(X_PREDEFINED) + ); + if (!pp.truncate) + sfprintf(sp, +"\ +#%s __STDPP__directive #(%s)\n\ +" + , dirname(DEFINE) + , keyname(V_DIRECTIVE) + ); + for (kp = variables; s = kp->name; kp++) + if (ppisid(*s) || *s++ == '+') + { + t = *s == '_' ? "" : "__"; + sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s); + } + sfprintf(sp, +"\ +#%s %s:no%s\n\ +#%s %s:no%s\n\ +" + , dirname(PRAGMA) + , pp.pass + , keyname(X_READONLY) + , dirname(PRAGMA) + , pp.pass + , keyname(X_BUILTIN) + ); + t = sfstruse(sp); + debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t)); + ppcomment = pp.comment; + pp.comment = 0; + pplinesync = pp.linesync; + pp.linesync = 0; + PUSH_INIT(pp.pass, t); + pp.mode |= INIT; + while (pplex()); + pp.mode &= ~INIT; + pp.comment = ppcomment; + pp.linesync = pplinesync; + pp.prefix = 0; + sfstrclose(sp); + if (error_info.trace) + for (dp = pp.firstdir; dp; dp = dp->next) + message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : "")); +#if DEBUG + } + if (pp.test & TEST_nonoise) + error_info.trace = c; +#endif + { + /* + * this is sleazy but at least it's + * hidden in the library + */ +#include <preroot.h> +#if FS_PREROOT + struct pplist* preroot; + + if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot"))) + setpreroot(NiL, preroot->value); +#endif + } + if (pp.ignoresrc) + { + if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir) + error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name); + pp.lcldirs = pp.lcldirs->next; + } + if (pp.ignore) + { + if (*pp.ignore) + ppmapinclude(pp.ignore, NiL); + else + pp.ignore = 0; + } + if (pp.standalone) + pp.state |= STANDALONE; +#if COMPATIBLE + ppfsm(FSM_COMPATIBILITY, NiL); +#endif + ppfsm(FSM_PLUSPLUS, NiL); + pp.initialized = 1; + if (pp.reset.on) + { + pp.reset.symtab = pp.symtab; + pp.symtab = 0; + pp.reset.ro_state = pp.ro_state; + pp.reset.ro_mode = pp.ro_mode; + pp.reset.ro_option = pp.ro_option; + } + } + if (pp.reset.on) + { + if (pp.symtab) + { + hashwalk(pp.filtab, 0, unguard, NiL); + hashfree(pp.symtab); + } + pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0); + hashview(pp.symtab, pp.reset.symtab); + pp.ro_state = pp.reset.ro_state; + pp.ro_mode = pp.reset.ro_mode; + pp.ro_option = pp.reset.ro_option; + } +#if CHECKPOINT + if (pp.mode & DUMP) + { + if (!pp.pragma) + error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA)); + (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1); + } +#endif + if (n = pp.filedeps.flags) + { + if (!(n & PP_deps_file)) + { + pp.state |= NOTEXT; + pp.option |= KEEPNOTEXT; + pp.linesync = 0; + } + if (n & PP_deps_generated) + pp.mode |= GENDEPS; + if (n & PP_deps_local) + pp.mode &= ~HEADERDEPS; + else if (!(pp.mode & FILEDEPS)) + pp.mode |= HEADERDEPS; + pp.mode |= FILEDEPS; + } + + /* + * push the main input file -- special case for hosted mark + */ + + if (pp.firstdir->type & TYPE_HOSTED) + pp.mode |= MARKHOSTED; + else + pp.mode &= ~MARKHOSTED; +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#endif + { + if (!(p = error_info.file)) + p = ""; + else + { + error_info.file = 0; + if (*p) + { + pathcanon(p, 0); + p = ppsetfile(p)->name; + } + } + PUSH_FILE(p, 0); + } + if (pp.mode & FILEDEPS) + { + if (s = strrchr(error_info.file, '/')) + s++; + else + s = error_info.file; + if (!*s) + s = "-"; + s = strcpy(pp.tmpbuf, s); + if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C')) + { + if (c = *++p) + while (*++p == c); + if (*p) + t = 0; + else + t++; + } + if (!t) + { + t = s + strlen(s); + *t++ = '.'; + } + *(t + 1) = 0; + if (pp.state & NOTEXT) + pp.filedeps.sp = sfstdout; + else + { + *t = 'd'; + if (!(pp.filedeps.sp = sfopen(NiL, s, "w"))) + error(ERROR_SYSTEM|3, "%s: cannot create", s); + } + *t = 'o'; + pp.column = sfprintf(pp.filedeps.sp, "%s :", s); + if (*error_info.file) + pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file); + } + if (xp = pp.firsttx) + { + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + while (xp) + { + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value); + xp = xp->next; + } + t = sfstruse(sp); + PUSH_BUFFER("options", t, 1); + sfstrclose(sp); + } + break; + case PP_INPUT: +#if CHECKPOINT && POOL + if (!(pp.mode & DUMP) || pp.pool.input) +#else +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#else +#if POOL + if (pp.pool.input) +#endif +#endif +#endif + { + p = va_arg(ap, char*); + if (!error_info.file) + error_info.file = p; + close(0); + if (open(p, O_RDONLY) != 0) + error(ERROR_SYSTEM|3, "%s: cannot read", p); + if (strmatch(p, "*.(s|S|as|AS|asm|ASM)")) + { + set(&pp.mode, CATLITERAL, 0); + ppop(PP_SPACEOUT, 1); + } + break; + } + /*FALLTHROUGH*/ + case PP_TEXT: + if (pp.initialized) + goto before; + if ((p = va_arg(ap, char*)) && *p) + { + if (pp.lasttx) + pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0); + else + pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0); + pp.lasttx->op = op; + pp.lasttx->value = p; + } + break; + case PP_KEYARGS: + if (pp.initialized) + goto before; + set(&pp.option, KEYARGS, va_arg(ap, int)); + if (pp.option & KEYARGS) +#if MACKEYARGS + set(&pp.mode, CATLITERAL, 1); +#else + error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]"); +#endif + break; + case PP_LINE: + pp.linesync = va_arg(ap, PPLINESYNC); + break; + case PP_LINEBASE: + if (va_arg(ap, int)) + pp.flags |= PP_linebase; + else + pp.flags &= ~PP_linebase; + break; + case PP_LINEFILE: + if (va_arg(ap, int)) + pp.flags |= PP_linefile; + else + pp.flags &= ~PP_linefile; + break; + case PP_LINEID: + if (!(p = va_arg(ap, char*))) + pp.lineid = ""; + else if (*p != '-') + pp.lineid = strdup(p); + else + pp.option |= IGNORELINE; + break; + case PP_LINETYPE: + if ((n = va_arg(ap, int)) >= 1) + pp.flags |= PP_linetype; + else + pp.flags &= ~PP_linetype; + if (n >= 2) + pp.flags |= PP_linehosted; + else + pp.flags &= ~PP_linehosted; + break; + case PP_LOCAL: + if (pp.initialized) + goto before; + pp.ignoresrc++; + pp.stddirs = pp.lastdir; + if (!(pp.ro_option & PREFIX)) + pp.option &= ~PREFIX; + break; + case PP_MACREF: + pp.macref = va_arg(ap, PPMACREF); + break; + case PP_MULTIPLE: + set(&pp.mode, ALLMULTIPLE, va_arg(ap, int)); + break; + case PP_NOHASH: + set(&pp.option, NOHASH, va_arg(ap, int)); + break; + case PP_NOISE: + op = va_arg(ap, int); + set(&pp.option, NOISE, op); + set(&pp.option, NOISEFILTER, op < 0); + break; + case PP_OPTARG: + pp.optarg = va_arg(ap, PPOPTARG); + break; + case PP_OUTPUT: + pp.outfile = va_arg(ap, char*); + if (identical(pp.outfile, 0)) + error(3, "%s: identical to input", pp.outfile); + close(1); + if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1) + error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile); + break; + case PP_PASSTHROUGH: + if (!(pp.state & COMPILE)) + set(&pp.state, PASSTHROUGH, va_arg(ap, int)); + break; + case PP_PEDANTIC: + set(&pp.mode, PEDANTIC, va_arg(ap, int)); + break; + case PP_PLUSCOMMENT: + set(&pp.option, PLUSCOMMENT, va_arg(ap, int)); + if (pp.initialized) + ppfsm(FSM_PLUSPLUS, NiL); + break; + case PP_PLUSPLUS: + set(&pp.option, PLUSPLUS, va_arg(ap, int)); + set(&pp.option, PLUSCOMMENT, va_arg(ap, int)); + if (pp.initialized) + ppfsm(FSM_PLUSPLUS, NiL); + break; + case PP_POOL: + if (pp.initialized) + goto before; + if (va_arg(ap, int)) + { +#if POOL + pp.pool.input = dup(0); + pp.pool.output = dup(1); + p = "/dev/null"; + if (!identical(p, 0)) + { + if (!identical(p, 1)) + ppop(PP_OUTPUT, p); + ppop(PP_INPUT, p); + } +#else + error(3, "preprocessor not compiled with input pool enabled [POOL]"); +#endif + } + break; + case PP_PRAGMA: + pp.pragma = va_arg(ap, PPPRAGMA); + break; + case PP_PRAGMAFLAGS: + if (p = va_arg(ap, char*)) + { + n = OPT_GLOBAL; + if (*p == '-') + p++; + else + n |= OPT_PASS; + if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option) + pp.optflags[c] = n; + } + break; + case PP_PROBE: + pp.probe = va_arg(ap, char*); + break; + case PP_QUOTE: + p = va_arg(ap, char*); + c = va_arg(ap, int); + if (p) + ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p); + break; + case PP_REGUARD: + set(&pp.option, REGUARD, va_arg(ap, int)); + break; + case PP_RESERVED: + if ((pp.state & COMPILE) && (p = va_arg(ap, char*))) + { + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + sfputr(sp, p, -1); + p = sfstruse(sp); + if (s = strchr(p, '=')) + *s++ = 0; + else + s = p; + while (*s == '_') + s++; + for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--); + if (*t == '_') + *t = 0; + else + t = 0; + op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE; + if (pp.test & 0x0400) + error(1, "reserved#1 `%s' %d", s, op); + if (t) + *t = '_'; + if (!(key = ppkeyget(pp.symtab, p))) + key = ppkeyset(pp.symtab, NiL); + else if (!(key->sym.flags & SYM_LEX)) + { + struct ppsymbol tmp; + + tmp = key->sym; + hashlook(pp.symtab, p, HASH_DELETE, NiL); + key = ppkeyset(pp.symtab, NiL); + key->sym.flags = tmp.flags; + key->sym.macro = tmp.macro; + key->sym.value = tmp.value; + key->sym.hidden = tmp.hidden; + } + if (!(key->sym.flags & SYM_KEYWORD)) + { + key->sym.flags |= SYM_KEYWORD|SYM_LEX; + key->lex = op; + if (pp.test & 0x0400) + error(1, "reserved#2 `%s' %d", p, op); + } + sfstrclose(sp); + } + break; + case PP_SPACEOUT: + set(&pp.state, SPACEOUT, va_arg(ap, int)); + break; + case PP_STANDALONE: + if (pp.initialized) + goto before; + pp.standalone = 1; + break; + case PP_STANDARD: + if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st)) + SAVEID(&pp.lastdir->next->id, &st); + for (dp = pp.firstdir; dp; dp = dp->next) + if (dp->name) + for (hp = pp.firstdir; hp != dp; hp = hp->next) + if (hp->name && SAMEID(&hp->id, &dp->id)) + { + hp->c = dp->c; + if (dp->type & TYPE_HOSTED) + hp->type |= TYPE_HOSTED; + else + hp->type &= ~TYPE_HOSTED; + } + break; + case PP_STRICT: + set(&pp.state, TRANSITION, 0); + pp.flags &= ~PP_transition; + set(&pp.state, STRICT, va_arg(ap, int)); + if (pp.state & STRICT) + pp.flags |= PP_strict; + else + pp.flags &= ~PP_strict; + break; + case PP_TEST: + if (p = va_arg(ap, char*)) + for (;;) + { + while (*p == ' ' || *p == '\t') p++; + for (s = p; n = *s; s++) + if (n == ',' || n == ' ' || n == '\t') + { + *s++ = 0; + break; + } + if (!*p) + break; + n = 0; + if (*p == 'n' && *(p + 1) == 'o') + { + p += 2; + op = 0; + } + else + op = 1; + if (streq(p, "count")) + n = TEST_count; + else if (streq(p, "hashcount")) + n = TEST_hashcount; + else if (streq(p, "hashdump")) + n = TEST_hashdump; + else if (streq(p, "hit")) + n = TEST_hit; + else if (streq(p, "init")) + n = TEST_noinit|TEST_INVERT; + else if (streq(p, "noise")) + n = TEST_nonoise|TEST_INVERT; + else if (streq(p, "proto")) + n = TEST_noproto|TEST_INVERT; + else if (*p >= '0' && *p <= '9') + n = strtoul(p, NiL, 0); + else + { + error(1, "%s: unknown test", p); + break; + } + if (n & TEST_INVERT) + { + n &= ~TEST_INVERT; + op = !op; + } + if (op) + pp.test |= n; + else + pp.test &= ~n; + p = s; + debug((-4, "test = 0%o", pp.test)); + } + break; + case PP_TRANSITION: + set(&pp.state, STRICT, 0); + pp.flags &= ~PP_strict; + set(&pp.state, TRANSITION, va_arg(ap, int)); + if (pp.state & TRANSITION) + pp.flags |= PP_transition; + else + pp.flags &= ~PP_transition; + break; + case PP_TRUNCATE: + if (pp.initialized) + goto before; + if ((op = va_arg(ap, int)) < 0) + op = 0; + set(&pp.option, TRUNCATE, op); + if (pp.option & TRUNCATE) + { + Hash_bucket_t* b; + Hash_bucket_t* p; + Hash_position_t* pos; + Hash_table_t* tab; + + pp.truncate = op; + tab = pp.symtab; + pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0); + if (tab && (pos = hashscan(tab, 0))) + { + if (p = hashnext(pos)) + do + { + b = hashnext(pos); + hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL); + } while (p = b); + hashdone(pos); + } + } + else + pp.truncate = 0; + break; + case PP_VENDOR: + p = va_arg(ap, char*); + c = va_arg(ap, int) != 0; + if (!p || !*p) + for (dp = pp.firstdir; dp; dp = dp->next) + dp->type &= ~TYPE_VENDOR; + else if (streq(p, "-")) + { + for (dp = pp.firstdir; dp; dp = dp->next) + if (c) + dp->type |= TYPE_VENDOR; + else + dp->type &= ~TYPE_VENDOR; + } + else if (!stat((pathcanon(p, 0), p), &st)) + { + c = 0; + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st))) + c = 1; + if (c) + dp->type |= TYPE_VENDOR; + else + dp->type &= ~TYPE_VENDOR; + } + } + break; + case PP_WARN: + set(&pp.state, WARN, va_arg(ap, int)); + break; + before: + error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op); + break; + default: + error(3, "ppop(%d): invalid preprocessor operation", op); + break; + } + va_end(ap); +} |