/* add a symbol to the #define symbol table */ void tok_add_define(tokcxdef *ctx, char *sym, int len, char *expan, int explen) { int hsh; tokdfdef *df; /* if it's already defined, ignore it */ if (tok_find_define(ctx, sym, len)) return; /* find the appropriate entry in the hash table */ hsh = tokdfhsh(sym, len); /* allocate space for the symbol */ df = (tokdfdef *)mchalo(ctx->tokcxerr, (sizeof(tokdfdef) + len + explen - 1), "tok_add_define"); /* set up the new symbol */ df->nm = df->expan + explen; df->len = len; df->explen = explen; memcpy(df->expan, expan, explen); memcpy(df->nm, sym, len); /* link it into the hash chain */ df->nxt = ctx->tokcxdf[hsh]; ctx->tokcxdf[hsh] = df; }
/* * Read preprocessor state from a file */ void tok_read_defines(tokcxdef *ctx, osfildef *fp, errcxdef *ec) { int i; tokdfdef **dfp; tokdfdef *df; char buf[4]; /* write each element of the hash chains */ for (i = TOKDFHSHSIZ, dfp = ctx->tokcxdf ; i ; ++dfp, --i) { /* read this hash chain */ for (;;) { /* read the next entry's header, and stop if this is the end */ if (osfrb(fp, buf, 4)) errsig(ec, ERR_RDGAM); if (osrp2(buf) == 0) break; /* set up a new symbol of the appropriate size */ df = (tokdfdef *)mchalo(ec, (sizeof(tokdfdef) + osrp2(buf) + osrp2(buf+2) - 1), "tok_read_defines"); df->explen = osrp2(buf+2); df->nm = df->expan + df->explen; df->len = osrp2(buf); /* read the rest of the symbol */ if (osfrb(fp, df->nm, df->len) || (df->explen != 0 && osfrb(fp, df->expan, df->explen))) errsig(ec, ERR_RDGAM); /* * If a symbol with this name already exists in the table, * discard the new one -- the symbols defined by -D and the * current set of built-in symbols takes precedence over the * set loaded from the file. */ if (tok_find_define(ctx, df->nm, df->len)) { /* simply discard this symbol */ mchfre(df); } else { /* link it into this hash chain */ df->nxt = *dfp; *dfp = df; } } } }
tokcxdef *tokcxini(errcxdef *errctx, mcmcxdef *mcmctx, tokldef *sctab) { int i; int cnt; tokldef *p; uchar c; uchar index[256]; tokcxdef *ret; tokscdef *sc; ushort siz; /* set up index table: finds tokcxsc entry from character value */ memset(index, 0, (size_t)sizeof(index)); for (i = cnt = 0, p = sctab ; (c = p->toklstr[0]) != 0 ; ++cnt, ++p) if (!index[c]) index[c] = ++i; /* allocate memory for table plus the tokscdef's */ siz = sizeof(tokcxdef) + (i * sizeof(tokscdef *)) + ((cnt + 1) * sizeof(tokscdef)); ret = (tokcxdef *)mchalo(errctx, siz, "tokcxini"); memset(ret, 0, (size_t)siz); /* copy the index, set up fixed part */ memcpy(ret->tokcxinx, index, sizeof(ret->tokcxinx)); ret->tokcxerr = errctx; ret->tokcxmem = mcmctx; /* start out without an #if */ ret->tokcxifcur = TOKIF_IF_YES; /* force the first toknext() to read a line */ ret->tokcxptr = "\000"; /* figure where the tokscdef's go (right after sc pointer array) */ sc = (tokscdef *)&ret->tokcxsc[i+1]; /* set up the individual tokscdef entries, and link into lists */ for (p = sctab ; (c = p->toklstr[0]) != 0 ; ++p, ++sc) { size_t len; sc->toksctyp = p->tokltyp; len = sc->toksclen = strlen(p->toklstr); memcpy(sc->tokscstr, p->toklstr, len); sc->tokscnxt = ret->tokcxsc[index[c]]; ret->tokcxsc[index[c]] = sc; } return(ret); }
/* add an include path to a tokdef */ void tokaddinc(tokcxdef *ctx, char *path, int pathlen) { tokpdef *newpath; tokpdef *last; /* find the tail of the include path list, if any */ for (last = ctx->tokcxinc ; last && last->tokpnxt ; last = last->tokpnxt) ; /* allocate storage for and set up a new path structure */ newpath = (tokpdef *)mchalo(ctx->tokcxerr, (sizeof(tokpdef) + pathlen - 1), "tokaddinc"); newpath->tokplen = pathlen; newpath->tokpnxt = (tokpdef *)0; memcpy(newpath->tokpdir, path, (size_t)pathlen); /* link in at end of list (if no list yet, newpath becomes first entry) */ if (last) last->tokpnxt = newpath; else ctx->tokcxinc = newpath; }
/* set up contents property for load-on-demand */ void supcont(void *ctx0, objnum obj, prpnum prp) { supcxdef *ctx = (supcxdef *)ctx0; vocidef ***vpg; vocidef **v; voccxdef *voc = ctx->supcxvoc; int i; int j; int len = 2; objnum chi; objnum loc; /* be sure the buffer is allocated */ if (!ctx->supcxbuf) { ctx->supcxlen = 512; ctx->supcxbuf = mchalo(ctx->supcxerr, ctx->supcxlen, "supcont"); } assert(prp == PRP_CONTENTS); /* the only thing that makes sense */ for (vpg = voc->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i) { if (!*vpg) continue; /* no entries on this page */ for (v = *vpg, chi = (i << 8), j = 0 ; j < 256 ; ++v, ++chi, ++j) { /* if there's no record at this location, skip it */ if (!*v) continue; /* inherit the location if it hasn't been set to any value */ if ((*v)->vociloc == MCMONINV && !((*v)->vociflg & VOCIFLOCNIL)) loc = (*v)->vociilc; else loc = (*v)->vociloc; /* if this object is in the indicated location, add it */ if (loc == obj && !((*v)->vociflg & VOCIFCLASS)) { /* see if we have room in list buffer; expand buffer if not */ if (len + 3 > ctx->supcxlen) { uchar *newbuf; /* allocate a new buffer */ newbuf = mchalo(ctx->supcxerr, (len + 512), "supcont"); /* copy the old buffer's contents into the new buffer */ memcpy(newbuf, ctx->supcxbuf, ctx->supcxlen); /* remember the new buffer length */ ctx->supcxlen = len + 512; /* free the old buffer */ mchfre(ctx->supcxbuf); /* remember the new buffer */ ctx->supcxbuf = newbuf; /* sanity check for integer overflow */ if (len + 3 > ctx->supcxlen) errsig(ctx->supcxmem->mcmcxgl->mcmcxerr, ERR_SUPOVF); } ctx->supcxbuf[len] = DAT_OBJECT; oswp2(ctx->supcxbuf + len + 1, chi); len += 3; } } } oswp2(ctx->supcxbuf, len); objsetp(ctx->supcxmem, obj, prp, DAT_LIST, ctx->supcxbuf, ctx->supcxrun->runcxundo); }
/* get a new line from line source, processing '#' directives */ static int tokgetlin(tokcxdef *ctx, int dopound) { for (;;) { if (linget(ctx->tokcxlin)) { /* at eof in current source; resume parent if there is one */ if (ctx->tokcxlin->linpar) { lindef *parent; parent = ctx->tokcxlin->linpar; /* remember parent */ lincls(ctx->tokcxlin); /* close included file */ if (!ctx->tokcxdbg) /* if no debug context... */ mchfre(ctx->tokcxlin); /* free line source */ ctx->tokcxlin = parent; /* reset to parent line source */ if (parent->linflg & LINFCMODE) ctx->tokcxflg |= TOKCXFCMODE; else ctx->tokcxflg &= ~TOKCXFCMODE; continue; /* back for another attempt */ } else { /* check for outstanding #if/#ifdef */ if (ctx->tokcxifcnt) errlog(ctx->tokcxerr, ERR_NOENDIF); /* return end-of-file indication */ return TRUE; } } /* if this is a multi-segment line, copy it into our own buffer */ if (ctx->tokcxlin->linflg & LINFMORE) { char *p; uint rem; int done; if (!ctx->tokcxbuf) { /* allocate 1k as a default buffer */ ctx->tokcxbuf = (char *)mchalo(ctx->tokcxerr, 1024, "tok"); ctx->tokcxbsz = 1024; } ctx->tokcxlen = 0; for (done = FALSE, p = ctx->tokcxbuf, rem = ctx->tokcxbsz ; !done ; ) { size_t len = ctx->tokcxlin->linlen; /* add the current segment's length into line length */ ctx->tokcxlen += len; /* we're done after this piece if the last fetch was all */ done = !(ctx->tokcxlin->linflg & LINFMORE); if (len + 1 > rem) { char *newp; /* increase the size of the buffer */ if (ctx->tokcxbsz > (unsigned)0x8000) errsig(ctx->tokcxerr, ERR_LONGLIN); rem += 4096; ctx->tokcxbsz += 4096; /* allocate a new buffer and copy line into it */ newp = (char *)mchalo(ctx->tokcxerr, ctx->tokcxbsz, "tok"); memcpy(newp, ctx->tokcxbuf, (size_t)(p - ctx->tokcxbuf)); /* free the original buffer, and use the new one */ p = (p - ctx->tokcxbuf) + newp; mchfre(ctx->tokcxbuf); ctx->tokcxbuf = newp; } /* add the line to the buffer */ memcpy(p, ctx->tokcxlin->linbuf, len); p += len; rem -= len; /* get the next piece of the line if there is one */ if (!done) { if (linget(ctx->tokcxlin)) break; } } /* null-terminate the buffer, and use it for input */ *p = '\0'; ctx->tokcxptr = ctx->tokcxbuf; } else { ctx->tokcxptr = ctx->tokcxlin->linbuf; ctx->tokcxlen = ctx->tokcxlin->linlen; } /* check for preprocessor directives */ if (dopound && ctx->tokcxlen != 0 && ctx->tokcxptr[0] == '#' && !(ctx->tokcxlin->linflg & LINFNOINC)) { char *p; int len; static struct { char *nm; int len; int ok_in_if; void (*fn)(tokcxdef *, char *, int); } *dirp, dir[] = { { "include", 7, FALSE, tokinclude }, { "pragma", 6, FALSE, tokpragma }, { "define", 6, FALSE, tokdefine }, { "ifdef", 5, TRUE, tokifdef }, { "ifndef", 6, TRUE, tokifndef }, { "if", 2, TRUE, tokif }, { "else", 4, TRUE, tokelse }, { "elif", 4, TRUE, tokelif }, { "endif", 5, TRUE, tokendif }, { "undef", 5, FALSE, tokundef }, { "error", 5, FALSE, tok_p_error } }; int i; /* scan off spaces between '#' and directive */ for (len = ctx->tokcxlen - 1, p = &ctx->tokcxptr[1] ; len && t_isspace(*p) ; --len, ++p) ; /* find and process the directive */ for (dirp = dir, i = sizeof(dir)/sizeof(dir[0]) ; i ; --i, ++dirp) { /* compare this directive; if it wins, call its function */ if (len >= dirp->len && !memcmp(p, dirp->nm, (size_t)dirp->len) && (len == dirp->len || t_isspace(*(p + dirp->len)))) { int cnt; int stat; /* * if we're not in a #if's false part, or if the * directive is processed even in #if false parts, * process the line, otherwise skip it */ cnt = ctx->tokcxifcnt; if (dirp->ok_in_if || cnt == 0 || ((stat = ctx->tokcxifcur) == TOKIF_IF_YES || stat == TOKIF_ELSE_YES)) { /* skip whitespace following the directive */ for (p += dirp->len, len -= dirp->len ; len && t_isspace(*p) ; --len, ++p) ; /* invoke the function to process this directive */ (*dirp->fn)(ctx, p, len); } /* there's no need to look at more directives */ break; } } /* if we didn't find anything, flag the error */ if (i == 0) errlog(ctx->tokcxerr, ERR_PRPDIR); /* ignore this line */ continue; } else { /* * Check the #if level. If we're in an #if, and we're to * ignore lines (because of a false condition or an #else * part for a true condition), skip this line. */ if (ctx->tokcxifcnt != 0) { switch(ctx->tokcxifcur) { case TOKIF_IF_NO: case TOKIF_ELSE_NO: /* ignore this line */ continue; default: /* we're in a true part - keep the line */ break; } } ctx->tokcxlin->linflg &= ~LINFDBG; /* no debug record yet */ return(FALSE); /* return the line we found */ } } }