1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1986-2010 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * preprocessor stacked input stream support
1N/A */
1N/A
1N/A#include "pplib.h"
1N/A
1N/A
1N/A/*
1N/A * convert path to native representation
1N/A */
1N/A
1N/A#if 0
1N/A#include "../../lib/libast/path/pathnative.c" /* drop in 2002 */
1N/A#else
1N/A/* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */
1N/A#include "../../libast/common/path/pathnative.c"
1N/A#endif
1N/A
1N/Astatic char*
1N/Anative(register const char* s)
1N/A{
1N/A register int c;
1N/A register struct ppfile* xp;
1N/A int m;
1N/A int n;
1N/A
1N/A static Sfio_t* np;
1N/A static Sfio_t* qp;
1N/A
1N/A if (!s)
1N/A return 0;
1N/A if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen()))
1N/A return (char*)s;
1N/A n = PATH_MAX;
1N/A do
1N/A {
1N/A m = n;
1N/A n = pathnative(s, sfstrrsrv(np, m), m);
1N/A } while (n > m);
1N/A sfstrseek(np, n, SEEK_CUR);
1N/A s = (const char*)sfstruse(np);
1N/A for (;;)
1N/A {
1N/A switch (c = *s++)
1N/A {
1N/A case 0:
1N/A break;
1N/A case '\\':
1N/A case '"':
1N/A sfputc(qp, '\\');
1N/A /*FALLTHROUGH*/
1N/A default:
1N/A sfputc(qp, c);
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A if (!(xp = ppsetfile(sfstruse(qp))))
1N/A return (char*)s;
1N/A return xp->name;
1N/A}
1N/A
1N/A/*
1N/A * push stream onto input stack
1N/A * used by the PUSH_type macros
1N/A */
1N/A
1N/Avoid
1N/Apppush(register int t, register char* s, register char* p, int n)
1N/A{
1N/A register struct ppinstk* cur;
1N/A
1N/A PUSH(t, cur);
1N/A cur->line = error_info.line;
1N/A cur->file = error_info.file;
1N/A switch (t)
1N/A {
1N/A case IN_FILE:
1N/A if (pp.option & NATIVE)
1N/A s = native(s);
1N/A cur->flags |= IN_newline;
1N/A cur->fd = n;
1N/A cur->hide = ++pp.hide;
1N/A cur->symbol = 0;
1N/A#if CHECKPOINT
1N/A if ((pp.mode & (DUMP|INIT)) == DUMP)
1N/A {
1N/A cur->index = newof(0, struct ppindex, 1, 0);
1N/A if (pp.lastindex) pp.lastindex->next = cur->index;
1N/A else pp.firstindex = cur->index;
1N/A pp.lastindex = cur->index;
1N/A cur->index->file = pp.original;
1N/A cur->index->begin = ppoffset();
1N/A }
1N/A#endif
1N/A n = 1;
1N/A#if CHECKPOINT
1N/A if (!(pp.mode & DUMP))
1N/A#endif
1N/A if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0))
1N/A cur->flags |= IN_flush;
1N/A#if ARCHIVE
1N/A if (pp.member)
1N/A {
1N/A switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT))
1N/A {
1N/A case 0:
1N/A#if CHECKPOINT
1N/A cur->buflen = pp.member->size;
1N/A#endif
1N/A p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ;
1N/A if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset)
1N/A error(3, "%s: archive seek error", pp.member->archive->name);
1N/A if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size)
1N/A error(3, "%s: archive read error", pp.member->archive->name);
1N/A pp.member = 0;
1N/A break;
1N/A case TYPE_BUFFER:
1N/A#if CHECKPOINT
1N/A case TYPE_CHECKPOINT|TYPE_BUFFER:
1N/A cur->buflen = pp.member->size;
1N/A#endif
1N/A p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset;
1N/A cur->flags |= IN_static;
1N/A pp.member = 0;
1N/A break;
1N/A#if CHECKPOINT
1N/A case TYPE_CHECKPOINT:
1N/A p = cur->buffer = "";
1N/A cur->flags |= IN_static;
1N/A break;
1N/A#endif
1N/A }
1N/A cur->flags |= IN_eof|IN_newline;
1N/A cur->fd = -1;
1N/A }
1N/A else
1N/A#endif
1N/A {
1N/A if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET))
1N/A cur->flags |= IN_regular;
1N/A errno = 0;
1N/A#if PROTOTYPE
1N/A 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))))
1N/A {
1N/A *(p = cur->buffer - 1) = 0;
1N/A cur->buffer -= PPBAKSIZ;
1N/A cur->flags |= IN_prototype;
1N/A cur->fd = -1;
1N/A }
1N/A else
1N/A#endif
1N/A *(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0;
1N/A }
1N/A if (pp.incref && !(pp.mode & INIT))
1N/A (*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH);
1N/A if (pp.macref || (pp.option & IGNORELINE))
1N/A cur->flags |= IN_ignoreline;
1N/A cur->prefix = pp.prefix;
1N/A /*FALLTHROUGH*/
1N/A case IN_BUFFER:
1N/A case IN_INIT:
1N/A case IN_RESCAN:
1N/A pushcontrol();
1N/A cur->control = pp.control;
1N/A *pp.control = 0;
1N/A cur->vendor = pp.vendor;
1N/A if (cur->type != IN_RESCAN)
1N/A {
1N/A if (cur->type == IN_INIT)
1N/A pp.mode |= MARKHOSTED;
1N/A error_info.file = s;
1N/A error_info.line = n;
1N/A }
1N/A if (pp.state & HIDDEN)
1N/A {
1N/A pp.state &= ~HIDDEN;
1N/A pp.hidden = 0;
1N/A if (!(pp.state & NOTEXT) && pplastout() != '\n')
1N/A ppputchar('\n');
1N/A }
1N/A pp.state |= NEWLINE;
1N/A if (pp.mode & HOSTED) cur->flags |= IN_hosted;
1N/A else cur->flags &= ~IN_hosted;
1N/A if (pp.mode & (INIT|MARKHOSTED))
1N/A {
1N/A pp.mode |= HOSTED;
1N/A pp.flags |= PP_hosted;
1N/A }
1N/A switch (cur->type)
1N/A {
1N/A case IN_FILE:
1N/A if (!(pp.mode & (INIT|MARKHOSTED)))
1N/A {
1N/A pp.mode &= ~HOSTED;
1N/A pp.flags &= ~PP_hosted;
1N/A }
1N/A#if CATSTRINGS
1N/A if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
1N/A else
1N/A#endif
1N/A if (pp.linesync)
1N/A (*pp.linesync)(error_info.line, error_info.file);
1N/A#if ARCHIVE && CHECKPOINT
1N/A if (pp.member)
1N/A ppload(NiL);
1N/A#endif
1N/A if (pp.mode & MARKC)
1N/A {
1N/A cur->flags |= IN_c;
1N/A pp.mode &= ~MARKC;
1N/A if (!(cur->prev->flags & IN_c))
1N/A {
1N/A debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
1N/A PUSH_BUFFER("C", "extern \"C\" {\n", 1);
1N/A return;
1N/A }
1N/A }
1N/A else if (cur->prev->flags & IN_c)
1N/A {
1N/A debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
1N/A PUSH_BUFFER("C", "extern \"C++\" {\n", 1);
1N/A return;
1N/A }
1N/A break;
1N/A case IN_BUFFER:
1N/A cur->buffer = p = strdup(p);
1N/A break;
1N/A default:
1N/A cur->buffer = p;
1N/A break;
1N/A }
1N/A cur->nextchr = p;
1N/A break;
1N/A#if DEBUG
1N/A default:
1N/A error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type);
1N/A break;
1N/A#endif
1N/A }
1N/A debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr)));
1N/A}
1N/A
1N/A/*
1N/A * external buffer push
1N/A */
1N/A
1N/Avoid
1N/Appinput(char* b, char* f, int n)
1N/A{
1N/A PUSH_BUFFER(f, b, n);
1N/A}
1N/A
1N/A/*
1N/A * return expanded value of buffer p
1N/A */
1N/A
1N/Achar*
1N/Appexpand(register char* p)
1N/A{
1N/A register char* m;
1N/A register int n;
1N/A register int c;
1N/A long restore;
1N/A char* pptoken;
1N/A char* ppmactop;
1N/A struct ppmacstk* nextmacp;
1N/A struct ppinstk* cur;
1N/A
1N/A debug((-7, "before expand: %s", p));
1N/A if (ppmactop = pp.mactop)
1N/A {
1N/A nextmacp = pp.macp->next;
1N/A nextframe(pp.macp, pp.mactop);
1N/A }
1N/A restore = pp.state & (COLLECTING|DISABLE|STRIP);
1N/A pp.state &= ~restore;
1N/A pp.mode &= ~MARKMACRO;
1N/A PUSH_STRING(p);
1N/A cur = pp.in;
1N/A pp.in->flags |= IN_expand;
1N/A pptoken = pp.token;
1N/A n = 2 * MAXTOKEN;
1N/A pp.token = p = oldof(0, char, 0, n);
1N/A m = p + MAXTOKEN;
1N/A for (;;)
1N/A {
1N/A if (pplex())
1N/A {
1N/A if ((pp.token = pp.toknxt) > m)
1N/A {
1N/A c = pp.token - p;
1N/A p = newof(p, char, n += MAXTOKEN, 0);
1N/A m = p + n - MAXTOKEN;
1N/A pp.token = p + c;
1N/A }
1N/A if (pp.mode & MARKMACRO)
1N/A {
1N/A pp.mode &= ~MARKMACRO;
1N/A *pp.token++ = MARK;
1N/A *pp.token++ = 'X';
1N/A }
1N/A }
1N/A else if (pp.in == cur)
1N/A break;
1N/A }
1N/A *pp.token = 0;
1N/A if (ppmactop)
1N/A pp.macp->next = nextmacp;
1N/A debug((-7, "after expand: %s", p));
1N/A pp.token = pptoken;
1N/A pp.state |= restore;
1N/A pp.in = pp.in->prev;
1N/A return p;
1N/A}
1N/A
1N/A#if CHECKPOINT
1N/A
1N/A#define LOAD_FUNCTION (1<<0)
1N/A#define LOAD_MULTILINE (1<<1)
1N/A#define LOAD_NOEXPAND (1<<2)
1N/A#define LOAD_PREDICATE (1<<3)
1N/A#define LOAD_READONLY (1<<4)
1N/A#define LOAD_VARIADIC (1<<5)
1N/A
1N/A/*
1N/A * macro definition dump
1N/A */
1N/A
1N/Astatic int
1N/Adump(const char* name, char* v, void* handle)
1N/A{
1N/A register struct ppmacro* mac;
1N/A register struct ppsymbol* sym = (struct ppsymbol*)v;
1N/A register int flags;
1N/A
1N/A NoP(name);
1N/A NoP(handle);
1N/A if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED)))
1N/A {
1N/A ppprintf("%s", sym->name);
1N/A ppputchar(0);
1N/A flags = 0;
1N/A if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION;
1N/A if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE;
1N/A if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND;
1N/A if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE;
1N/A if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY;
1N/A if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC;
1N/A ppputchar(flags);
1N/A if (sym->flags & SYM_FUNCTION)
1N/A {
1N/A ppprintf("%d", mac->arity);
1N/A ppputchar(0);
1N/A if (mac->arity)
1N/A {
1N/A ppprintf("%s", mac->formals);
1N/A ppputchar(0);
1N/A }
1N/A }
1N/A ppprintf("%s", mac->value);
1N/A ppputchar(0);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/A/*
1N/A * dump macro definitions for quick loading via ppload()
1N/A */
1N/A
1N/Avoid
1N/Appdump(void)
1N/A{
1N/A register struct ppindex* ip;
1N/A unsigned long macro_offset;
1N/A unsigned long index_offset;
1N/A
1N/A /*
1N/A * NOTE: we assume '\0' does not occur in valid preprocessed output
1N/A */
1N/A
1N/A ppputchar(0);
1N/A
1N/A /*
1N/A * output global flags
1N/A */
1N/A
1N/A macro_offset = ppoffset();
1N/A ppputchar(0);
1N/A
1N/A /*
1N/A * output macro definitions
1N/A */
1N/A
1N/A hashwalk(pp.symtab, 0, dump, NiL);
1N/A ppputchar(0);
1N/A
1N/A /*
1N/A * output include file index
1N/A */
1N/A
1N/A index_offset = ppoffset();
1N/A ip = pp.firstindex;
1N/A while (ip)
1N/A {
1N/A ppprintf("%s", ip->file->name);
1N/A ppputchar(0);
1N/A if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST)
1N/A ppprintf("%s", ip->file->guard->name);
1N/A ppputchar(0);
1N/A ppprintf("%lu", ip->begin);
1N/A ppputchar(0);
1N/A ppprintf("%lu", ip->end);
1N/A ppputchar(0);
1N/A ip = ip->next;
1N/A }
1N/A ppputchar(0);
1N/A
1N/A /*
1N/A * output offset directory
1N/A */
1N/A
1N/A ppprintf("%010lu", macro_offset);
1N/A ppputchar(0);
1N/A ppprintf("%010lu", index_offset);
1N/A ppputchar(0);
1N/A ppflushout();
1N/A}
1N/A
1N/A/*
1N/A * load text and macro definitions from a previous ppdump()
1N/A * s is the string argument from the pragma (including quotes)
1N/A */
1N/A
1N/Avoid
1N/Appload(register char* s)
1N/A{
1N/A register char* b;
1N/A register Sfio_t* sp;
1N/A int m;
1N/A char* g;
1N/A char* t;
1N/A unsigned long n;
1N/A unsigned long p;
1N/A unsigned long macro_offset;
1N/A unsigned long index_offset;
1N/A unsigned long file_offset;
1N/A unsigned long file_size;
1N/A unsigned long keep_begin;
1N/A unsigned long keep_end;
1N/A unsigned long skip_end;
1N/A unsigned long next_begin;
1N/A unsigned long next_end;
1N/A struct ppfile* fp;
1N/A struct ppsymbol* sym;
1N/A struct ppmacro* mac;
1N/A
1N/A char* ip = 0;
1N/A
1N/A pp.mode |= LOADING;
1N/A if (!(pp.state & STANDALONE))
1N/A error(3, "checkpoint load in standalone mode only");
1N/A#if ARCHIVE
1N/A if (pp.member)
1N/A {
1N/A sp = pp.member->archive->info.sp;
1N/A file_offset = pp.member->offset;
1N/A file_size = pp.member->size;
1N/A if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1)))
1N/A error(3, "checkpoint magic error");
1N/A }
1N/A else
1N/A#endif
1N/A {
1N/A if (pp.in->type != IN_FILE)
1N/A error(3, "checkpoint load from files only");
1N/A if (pp.in->flags & IN_prototype)
1N/A pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ);
1N/A file_offset = 0;
1N/A if (pp.in->fd >= 0)
1N/A {
1N/A if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ)))
1N/A error(3, "checkpoint read error");
1N/A file_size = sfseek(sp, 0L, SEEK_END);
1N/A }
1N/A else
1N/A {
1N/A file_size = pp.in->buflen;
1N/A if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING)))
1N/A error(3, "checkpoint read error");
1N/A }
1N/A }
1N/A if (!streq(s, pp.checkpoint))
1N/A error(3, "checkpoint version %s does not match %s", s, pp.checkpoint);
1N/A
1N/A /*
1N/A * get the macro and index offsets
1N/A */
1N/A
1N/A p = file_offset + file_size - 22;
1N/A if ((n = sfseek(sp, p, SEEK_SET)) != p)
1N/A error(3, "checkpoint directory seek error");
1N/A if (!(t = sfreserve(sp, 22, 0)))
1N/A error(3, "checkpoint directory read error");
1N/A macro_offset = file_offset + strtol(t, &t, 10);
1N/A index_offset = file_offset + strtol(t + 1, NiL, 10);
1N/A
1N/A /*
1N/A * read the include index
1N/A */
1N/A
1N/A if (sfseek(sp, index_offset, SEEK_SET) != index_offset)
1N/A error(3, "checkpoint index seek error");
1N/A if (!(s = sfreserve(sp, n - index_offset, 0)))
1N/A error(3, "checkpoint index read error");
1N/A if (sfset(sp, 0, 0) & SF_STRING)
1N/A b = s;
1N/A else if (!(b = ip = memdup(s, n - index_offset)))
1N/A error(3, "checkpoint index alloc error");
1N/A
1N/A /*
1N/A * loop on the index and copy the non-ignored chunks to the output
1N/A */
1N/A
1N/A ppcheckout();
1N/A p = PPBUFSIZ - (pp.outp - pp.outbuf);
1N/A keep_begin = 0;
1N/A keep_end = 0;
1N/A skip_end = 0;
1N/A while (*b)
1N/A {
1N/A fp = ppsetfile(b);
1N/A while (*b++);
1N/A g = b;
1N/A while (*b++);
1N/A next_begin = strtol(b, &t, 10);
1N/A next_end = strtol(t + 1, &t, 10);
1N/Aif (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);
1N/A b = t + 1;
1N/A if (next_begin >= skip_end)
1N/A {
1N/A if (!ppmultiple(fp, INC_TEST))
1N/A {
1N/Aif (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name);
1N/A if (!keep_begin && skip_end < next_begin)
1N/A keep_begin = skip_end;
1N/A if (keep_begin)
1N/A {
1N/A flush:
1N/A if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin)
1N/A error(3, "checkpoint data seek error");
1N/A n = next_begin - keep_begin;
1N/Aif (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p);
1N/A while (n > p)
1N/A {
1N/A if (sfread(sp, pp.outp, p) != p)
1N/A error(3, "checkpoint data read error");
1N/A PPWRITE(PPBUFSIZ);
1N/A pp.outp = pp.outbuf;
1N/A n -= p;
1N/A p = PPBUFSIZ;
1N/A }
1N/A if (n)
1N/A {
1N/A if (sfread(sp, pp.outp, n) != n)
1N/A error(3, "checkpoint data read error");
1N/A pp.outp += n;
1N/A p -= n;
1N/A }
1N/A keep_begin = 0;
1N/A if (keep_end <= next_end)
1N/A keep_end = 0;
1N/A }
1N/A skip_end = next_end;
1N/A }
1N/A else if (!keep_begin)
1N/A {
1N/A if (skip_end)
1N/A {
1N/A keep_begin = skip_end;
1N/A skip_end = 0;
1N/A }
1N/A else keep_begin = next_begin;
1N/A if (keep_end < next_end)
1N/A keep_end = next_end;
1N/A }
1N/A }
1N/A if (*g && fp->guard != INC_IGNORE)
1N/A fp->guard = ppsymset(pp.symtab, g);
1N/A }
1N/A if (keep_end)
1N/A {
1N/A if (!keep_begin)
1N/A keep_begin = skip_end > next_end ? skip_end : next_end;
1N/A next_begin = next_end = keep_end;
1N/A g = b;
1N/A goto flush;
1N/A }
1N/Aif (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT));
1N/A
1N/A /*
1N/A * read the compacted definitions
1N/A */
1N/A
1N/A if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset)
1N/A error(3, "checkpoint macro seek error");
1N/A if (!(s = sfreserve(sp, index_offset - macro_offset, 0)))
1N/A error(3, "checkpoint macro read error");
1N/A
1N/A /*
1N/A * read the flags
1N/A */
1N/A
1N/A while (*s)
1N/A {
1N/A#if _options_dumped_
1N/A if (streq(s, "OPTION")) /* ... */;
1N/A else
1N/A#endif
1N/A error(3, "%-.48s: unknown flags in checkpoint file", s);
1N/A }
1N/A s++;
1N/A
1N/A /*
1N/A * unpack and enter the definitions
1N/A */
1N/A
1N/A while (*s)
1N/A {
1N/A b = s;
1N/A while (*s++);
1N/A m = *s++;
1N/A sym = ppsymset(pp.symtab, b);
1N/A if (sym->macro)
1N/A {
1N/A if (m & LOAD_FUNCTION)
1N/A {
1N/A if (*s++ != '0')
1N/A while (*s++);
1N/A while (*s++);
1N/A }
1N/Aif (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value);
1N/A while (*s++);
1N/A }
1N/A else
1N/A {
1N/A ppfsm(FSM_MACRO, b);
1N/A sym->flags = 0;
1N/A if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION;
1N/A if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE;
1N/A if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND;
1N/A if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE;
1N/A if (m & LOAD_READONLY) sym->flags |= SYM_READONLY;
1N/A if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC;
1N/A mac = sym->macro = newof(0, struct ppmacro, 1, 0);
1N/A if (sym->flags & SYM_FUNCTION)
1N/A {
1N/A for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0');
1N/A if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name);
1N/A if (mac->arity = n)
1N/A {
1N/A b = s;
1N/A while (*s++);
1N/A mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b);
1N/A }
1N/A }
1N/A b = s;
1N/A while (*s++);
1N/A mac->size = s - b - 1;
1N/A mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1);
1N/Aif (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value);
1N/A }
1N/A }
1N/A
1N/A /*
1N/A * we are now at EOF
1N/A */
1N/A
1N/A if (ip)
1N/A {
1N/A pp.in->fd = -1;
1N/A free(ip);
1N/A }
1N/A#if ARCHIVE
1N/A if (pp.member) pp.member = 0;
1N/A else
1N/A#endif
1N/A {
1N/A sfclose(sp);
1N/A pp.in->flags |= IN_eof|IN_newline;
1N/A pp.in->nextchr = pp.in->buffer + PPBAKSIZ;
1N/A *pp.in->nextchr++ = 0;
1N/A *pp.in->nextchr = 0;
1N/A }
1N/A pp.mode &= ~LOADING;
1N/A}
1N/A
1N/A#endif