diff options
Diffstat (limited to 'usr/src/lib/libpp/common/ppinput.c')
-rw-r--r-- | usr/src/lib/libpp/common/ppinput.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/common/ppinput.c b/usr/src/lib/libpp/common/ppinput.c new file mode 100644 index 0000000000..170e5f5dca --- /dev/null +++ b/usr/src/lib/libpp/common/ppinput.c @@ -0,0 +1,721 @@ +/*********************************************************************** +* * +* 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 stacked input stream support + */ + +#include "pplib.h" + + +/* + * convert path to native representation + */ + +#if 0 +#include "../../lib/libast/path/pathnative.c" /* drop in 2002 */ +#else +/* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */ +#include "../../libast/common/path/pathnative.c" +#endif + +static char* +native(register const char* s) +{ + register int c; + register struct ppfile* xp; + int m; + int n; + + static Sfio_t* np; + static Sfio_t* qp; + + if (!s) + return 0; + if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen())) + return (char*)s; + n = PATH_MAX; + do + { + m = n; + n = pathnative(s, sfstrrsrv(np, m), m); + } while (n > m); + sfstrseek(np, n, SEEK_CUR); + s = (const char*)sfstruse(np); + for (;;) + { + switch (c = *s++) + { + case 0: + break; + case '\\': + case '"': + sfputc(qp, '\\'); + /*FALLTHROUGH*/ + default: + sfputc(qp, c); + continue; + } + break; + } + if (!(xp = ppsetfile(sfstruse(qp)))) + return (char*)s; + return xp->name; +} + +/* + * push stream onto input stack + * used by the PUSH_type macros + */ + +void +pppush(register int t, register char* s, register char* p, int n) +{ + register struct ppinstk* cur; + + PUSH(t, cur); + cur->line = error_info.line; + cur->file = error_info.file; + switch (t) + { + case IN_FILE: + if (pp.option & NATIVE) + s = native(s); + cur->flags |= IN_newline; + cur->fd = n; + cur->hide = ++pp.hide; + cur->symbol = 0; +#if CHECKPOINT + if ((pp.mode & (DUMP|INIT)) == DUMP) + { + cur->index = newof(0, struct ppindex, 1, 0); + if (pp.lastindex) pp.lastindex->next = cur->index; + else pp.firstindex = cur->index; + pp.lastindex = cur->index; + cur->index->file = pp.original; + cur->index->begin = ppoffset(); + } +#endif + n = 1; +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#endif + if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0)) + cur->flags |= IN_flush; +#if ARCHIVE + if (pp.member) + { + switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT)) + { + case 0: +#if CHECKPOINT + cur->buflen = pp.member->size; +#endif + p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ; + if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset) + error(3, "%s: archive seek error", pp.member->archive->name); + if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size) + error(3, "%s: archive read error", pp.member->archive->name); + pp.member = 0; + break; + case TYPE_BUFFER: +#if CHECKPOINT + case TYPE_CHECKPOINT|TYPE_BUFFER: + cur->buflen = pp.member->size; +#endif + p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset; + cur->flags |= IN_static; + pp.member = 0; + break; +#if CHECKPOINT + case TYPE_CHECKPOINT: + p = cur->buffer = ""; + cur->flags |= IN_static; + break; +#endif + } + cur->flags |= IN_eof|IN_newline; + cur->fd = -1; + } + else +#endif + { + if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET)) + cur->flags |= IN_regular; + errno = 0; +#if PROTOTYPE + if (!(pp.option & NOPROTO) && !(pp.test & TEST_noproto) && ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY || (pp.option & PLUSPLUS) || (pp.mode & EXTERNALIZE)) && (cur->buffer = pppopen(NiL, cur->fd, NiL, NiL, NiL, NiL, (PROTO_HEADER|PROTO_RETAIN)|(((pp.mode & EXTERNALIZE) || (pp.option & PROTOTYPED)) ? PROTO_FORCE : PROTO_PASS)|((pp.mode & EXTERNALIZE) ? PROTO_EXTERNALIZE : 0)|((pp.mode & MARKC) ? PROTO_PLUSPLUS : 0)))) + { + *(p = cur->buffer - 1) = 0; + cur->buffer -= PPBAKSIZ; + cur->flags |= IN_prototype; + cur->fd = -1; + } + else +#endif + *(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0; + } + if (pp.incref && !(pp.mode & INIT)) + (*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH); + if (pp.macref || (pp.option & IGNORELINE)) + cur->flags |= IN_ignoreline; + cur->prefix = pp.prefix; + /*FALLTHROUGH*/ + case IN_BUFFER: + case IN_INIT: + case IN_RESCAN: + pushcontrol(); + cur->control = pp.control; + *pp.control = 0; + cur->vendor = pp.vendor; + if (cur->type != IN_RESCAN) + { + if (cur->type == IN_INIT) + pp.mode |= MARKHOSTED; + error_info.file = s; + error_info.line = n; + } + if (pp.state & HIDDEN) + { + pp.state &= ~HIDDEN; + pp.hidden = 0; + if (!(pp.state & NOTEXT) && pplastout() != '\n') + ppputchar('\n'); + } + pp.state |= NEWLINE; + if (pp.mode & HOSTED) cur->flags |= IN_hosted; + else cur->flags &= ~IN_hosted; + if (pp.mode & (INIT|MARKHOSTED)) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + } + switch (cur->type) + { + case IN_FILE: + if (!(pp.mode & (INIT|MARKHOSTED))) + { + pp.mode &= ~HOSTED; + pp.flags &= ~PP_hosted; + } +#if CATSTRINGS + if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE; + else +#endif + if (pp.linesync) + (*pp.linesync)(error_info.line, error_info.file); +#if ARCHIVE && CHECKPOINT + if (pp.member) + ppload(NiL); +#endif + if (pp.mode & MARKC) + { + cur->flags |= IN_c; + pp.mode &= ~MARKC; + if (!(cur->prev->flags & IN_c)) + { + debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); + PUSH_BUFFER("C", "extern \"C\" {\n", 1); + return; + } + } + else if (cur->prev->flags & IN_c) + { + debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); + PUSH_BUFFER("C", "extern \"C++\" {\n", 1); + return; + } + break; + case IN_BUFFER: + cur->buffer = p = strdup(p); + break; + default: + cur->buffer = p; + break; + } + cur->nextchr = p; + break; +#if DEBUG + default: + error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type); + break; +#endif + } + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); +} + +/* + * external buffer push + */ + +void +ppinput(char* b, char* f, int n) +{ + PUSH_BUFFER(f, b, n); +} + +/* + * return expanded value of buffer p + */ + +char* +ppexpand(register char* p) +{ + register char* m; + register int n; + register int c; + long restore; + char* pptoken; + char* ppmactop; + struct ppmacstk* nextmacp; + struct ppinstk* cur; + + debug((-7, "before expand: %s", p)); + if (ppmactop = pp.mactop) + { + nextmacp = pp.macp->next; + nextframe(pp.macp, pp.mactop); + } + restore = pp.state & (COLLECTING|DISABLE|STRIP); + pp.state &= ~restore; + pp.mode &= ~MARKMACRO; + PUSH_STRING(p); + cur = pp.in; + pp.in->flags |= IN_expand; + pptoken = pp.token; + n = 2 * MAXTOKEN; + pp.token = p = oldof(0, char, 0, n); + m = p + MAXTOKEN; + for (;;) + { + if (pplex()) + { + if ((pp.token = pp.toknxt) > m) + { + c = pp.token - p; + p = newof(p, char, n += MAXTOKEN, 0); + m = p + n - MAXTOKEN; + pp.token = p + c; + } + if (pp.mode & MARKMACRO) + { + pp.mode &= ~MARKMACRO; + *pp.token++ = MARK; + *pp.token++ = 'X'; + } + } + else if (pp.in == cur) + break; + } + *pp.token = 0; + if (ppmactop) + pp.macp->next = nextmacp; + debug((-7, "after expand: %s", p)); + pp.token = pptoken; + pp.state |= restore; + pp.in = pp.in->prev; + return p; +} + +#if CHECKPOINT + +#define LOAD_FUNCTION (1<<0) +#define LOAD_MULTILINE (1<<1) +#define LOAD_NOEXPAND (1<<2) +#define LOAD_PREDICATE (1<<3) +#define LOAD_READONLY (1<<4) +#define LOAD_VARIADIC (1<<5) + +/* + * macro definition dump + */ + +static int +dump(const char* name, char* v, void* handle) +{ + register struct ppmacro* mac; + register struct ppsymbol* sym = (struct ppsymbol*)v; + register int flags; + + NoP(name); + NoP(handle); + if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED))) + { + ppprintf("%s", sym->name); + ppputchar(0); + flags = 0; + if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION; + if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE; + if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND; + if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE; + if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY; + if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC; + ppputchar(flags); + if (sym->flags & SYM_FUNCTION) + { + ppprintf("%d", mac->arity); + ppputchar(0); + if (mac->arity) + { + ppprintf("%s", mac->formals); + ppputchar(0); + } + } + ppprintf("%s", mac->value); + ppputchar(0); + } + return(0); +} + +/* + * dump macro definitions for quick loading via ppload() + */ + +void +ppdump(void) +{ + register struct ppindex* ip; + unsigned long macro_offset; + unsigned long index_offset; + + /* + * NOTE: we assume '\0' does not occur in valid preprocessed output + */ + + ppputchar(0); + + /* + * output global flags + */ + + macro_offset = ppoffset(); + ppputchar(0); + + /* + * output macro definitions + */ + + hashwalk(pp.symtab, 0, dump, NiL); + ppputchar(0); + + /* + * output include file index + */ + + index_offset = ppoffset(); + ip = pp.firstindex; + while (ip) + { + ppprintf("%s", ip->file->name); + ppputchar(0); + if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST) + ppprintf("%s", ip->file->guard->name); + ppputchar(0); + ppprintf("%lu", ip->begin); + ppputchar(0); + ppprintf("%lu", ip->end); + ppputchar(0); + ip = ip->next; + } + ppputchar(0); + + /* + * output offset directory + */ + + ppprintf("%010lu", macro_offset); + ppputchar(0); + ppprintf("%010lu", index_offset); + ppputchar(0); + ppflushout(); +} + +/* + * load text and macro definitions from a previous ppdump() + * s is the string argument from the pragma (including quotes) + */ + +void +ppload(register char* s) +{ + register char* b; + register Sfio_t* sp; + int m; + char* g; + char* t; + unsigned long n; + unsigned long p; + unsigned long macro_offset; + unsigned long index_offset; + unsigned long file_offset; + unsigned long file_size; + unsigned long keep_begin; + unsigned long keep_end; + unsigned long skip_end; + unsigned long next_begin; + unsigned long next_end; + struct ppfile* fp; + struct ppsymbol* sym; + struct ppmacro* mac; + + char* ip = 0; + + pp.mode |= LOADING; + if (!(pp.state & STANDALONE)) + error(3, "checkpoint load in standalone mode only"); +#if ARCHIVE + if (pp.member) + { + sp = pp.member->archive->info.sp; + file_offset = pp.member->offset; + file_size = pp.member->size; + if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1))) + error(3, "checkpoint magic error"); + } + else +#endif + { + if (pp.in->type != IN_FILE) + error(3, "checkpoint load from files only"); + if (pp.in->flags & IN_prototype) + pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ); + file_offset = 0; + if (pp.in->fd >= 0) + { + if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ))) + error(3, "checkpoint read error"); + file_size = sfseek(sp, 0L, SEEK_END); + } + else + { + file_size = pp.in->buflen; + if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING))) + error(3, "checkpoint read error"); + } + } + if (!streq(s, pp.checkpoint)) + error(3, "checkpoint version %s does not match %s", s, pp.checkpoint); + + /* + * get the macro and index offsets + */ + + p = file_offset + file_size - 22; + if ((n = sfseek(sp, p, SEEK_SET)) != p) + error(3, "checkpoint directory seek error"); + if (!(t = sfreserve(sp, 22, 0))) + error(3, "checkpoint directory read error"); + macro_offset = file_offset + strtol(t, &t, 10); + index_offset = file_offset + strtol(t + 1, NiL, 10); + + /* + * read the include index + */ + + if (sfseek(sp, index_offset, SEEK_SET) != index_offset) + error(3, "checkpoint index seek error"); + if (!(s = sfreserve(sp, n - index_offset, 0))) + error(3, "checkpoint index read error"); + if (sfset(sp, 0, 0) & SF_STRING) + b = s; + else if (!(b = ip = memdup(s, n - index_offset))) + error(3, "checkpoint index alloc error"); + + /* + * loop on the index and copy the non-ignored chunks to the output + */ + + ppcheckout(); + p = PPBUFSIZ - (pp.outp - pp.outbuf); + keep_begin = 0; + keep_end = 0; + skip_end = 0; + while (*b) + { + fp = ppsetfile(b); + while (*b++); + g = b; + while (*b++); + next_begin = strtol(b, &t, 10); + next_end = strtol(t + 1, &t, 10); +if (pp.test & 0x0200) error(2, "%s: %s p=%lu next=<%lu,%lu> keep=<%lu,%lu> skip=<-,%lu> guard=%s", keyname(X_CHECKPOINT), fp->name, p, next_begin, next_end, keep_begin, keep_end, skip_end, fp->guard == INC_CLEAR ? "[CLEAR]" : fp->guard == INC_TEST ? "[TEST]" : fp->guard == INC_IGNORE ? "[IGNORE]" : fp->guard->name); + b = t + 1; + if (next_begin >= skip_end) + { + if (!ppmultiple(fp, INC_TEST)) + { +if (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name); + if (!keep_begin && skip_end < next_begin) + keep_begin = skip_end; + if (keep_begin) + { + flush: + if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin) + error(3, "checkpoint data seek error"); + n = next_begin - keep_begin; +if (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p); + while (n > p) + { + if (sfread(sp, pp.outp, p) != p) + error(3, "checkpoint data read error"); + PPWRITE(PPBUFSIZ); + pp.outp = pp.outbuf; + n -= p; + p = PPBUFSIZ; + } + if (n) + { + if (sfread(sp, pp.outp, n) != n) + error(3, "checkpoint data read error"); + pp.outp += n; + p -= n; + } + keep_begin = 0; + if (keep_end <= next_end) + keep_end = 0; + } + skip_end = next_end; + } + else if (!keep_begin) + { + if (skip_end) + { + keep_begin = skip_end; + skip_end = 0; + } + else keep_begin = next_begin; + if (keep_end < next_end) + keep_end = next_end; + } + } + if (*g && fp->guard != INC_IGNORE) + fp->guard = ppsymset(pp.symtab, g); + } + if (keep_end) + { + if (!keep_begin) + keep_begin = skip_end > next_end ? skip_end : next_end; + next_begin = next_end = keep_end; + g = b; + goto flush; + } +if (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT)); + + /* + * read the compacted definitions + */ + + if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset) + error(3, "checkpoint macro seek error"); + if (!(s = sfreserve(sp, index_offset - macro_offset, 0))) + error(3, "checkpoint macro read error"); + + /* + * read the flags + */ + + while (*s) + { +#if _options_dumped_ + if (streq(s, "OPTION")) /* ... */; + else +#endif + error(3, "%-.48s: unknown flags in checkpoint file", s); + } + s++; + + /* + * unpack and enter the definitions + */ + + while (*s) + { + b = s; + while (*s++); + m = *s++; + sym = ppsymset(pp.symtab, b); + if (sym->macro) + { + if (m & LOAD_FUNCTION) + { + if (*s++ != '0') + while (*s++); + while (*s++); + } +if (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value); + while (*s++); + } + else + { + ppfsm(FSM_MACRO, b); + sym->flags = 0; + if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION; + if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE; + if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND; + if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE; + if (m & LOAD_READONLY) sym->flags |= SYM_READONLY; + if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC; + mac = sym->macro = newof(0, struct ppmacro, 1, 0); + if (sym->flags & SYM_FUNCTION) + { + for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0'); + if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name); + if (mac->arity = n) + { + b = s; + while (*s++); + mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b); + } + } + b = s; + while (*s++); + mac->size = s - b - 1; + mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1); +if (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value); + } + } + + /* + * we are now at EOF + */ + + if (ip) + { + pp.in->fd = -1; + free(ip); + } +#if ARCHIVE + if (pp.member) pp.member = 0; + else +#endif + { + sfclose(sp); + pp.in->flags |= IN_eof|IN_newline; + pp.in->nextchr = pp.in->buffer + PPBAKSIZ; + *pp.in->nextchr++ = 0; + *pp.in->nextchr = 0; + } + pp.mode &= ~LOADING; +} + +#endif |