summaryrefslogtreecommitdiff
path: root/usr/src/lib/libpp/common/ppinput.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libpp/common/ppinput.c')
-rw-r--r--usr/src/lib/libpp/common/ppinput.c721
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