1*da2e3ebdSchin /*********************************************************************** 2*da2e3ebdSchin * * 3*da2e3ebdSchin * This software is part of the ast package * 4*da2e3ebdSchin * Copyright (c) 1986-2007 AT&T Knowledge Ventures * 5*da2e3ebdSchin * and is licensed under the * 6*da2e3ebdSchin * Common Public License, Version 1.0 * 7*da2e3ebdSchin * by AT&T Knowledge Ventures * 8*da2e3ebdSchin * * 9*da2e3ebdSchin * A copy of the License is available at * 10*da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11*da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*da2e3ebdSchin * * 13*da2e3ebdSchin * Information and Software Systems Research * 14*da2e3ebdSchin * AT&T Research * 15*da2e3ebdSchin * Florham Park NJ * 16*da2e3ebdSchin * * 17*da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18*da2e3ebdSchin * * 19*da2e3ebdSchin ***********************************************************************/ 20*da2e3ebdSchin #pragma prototyped 21*da2e3ebdSchin /* 22*da2e3ebdSchin * Glenn Fowler 23*da2e3ebdSchin * AT&T Research 24*da2e3ebdSchin * 25*da2e3ebdSchin * preprocessor stacked input stream support 26*da2e3ebdSchin */ 27*da2e3ebdSchin 28*da2e3ebdSchin #include "pplib.h" 29*da2e3ebdSchin 30*da2e3ebdSchin 31*da2e3ebdSchin /* 32*da2e3ebdSchin * convert path to native representation 33*da2e3ebdSchin */ 34*da2e3ebdSchin 35*da2e3ebdSchin #if 0 36*da2e3ebdSchin #include "../../lib/libast/path/pathnative.c" /* drop in 2002 */ 37*da2e3ebdSchin #else 38*da2e3ebdSchin /* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */ 39*da2e3ebdSchin #include "../../libast/common/path/pathnative.c" 40*da2e3ebdSchin #endif 41*da2e3ebdSchin 42*da2e3ebdSchin static char* 43*da2e3ebdSchin native(register const char* s) 44*da2e3ebdSchin { 45*da2e3ebdSchin register int c; 46*da2e3ebdSchin register struct ppfile* xp; 47*da2e3ebdSchin int m; 48*da2e3ebdSchin int n; 49*da2e3ebdSchin 50*da2e3ebdSchin static Sfio_t* np; 51*da2e3ebdSchin static Sfio_t* qp; 52*da2e3ebdSchin 53*da2e3ebdSchin if (!s) 54*da2e3ebdSchin return 0; 55*da2e3ebdSchin if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen())) 56*da2e3ebdSchin return (char*)s; 57*da2e3ebdSchin n = PATH_MAX; 58*da2e3ebdSchin do 59*da2e3ebdSchin { 60*da2e3ebdSchin m = n; 61*da2e3ebdSchin n = pathnative(s, sfstrrsrv(np, m), m); 62*da2e3ebdSchin } while (n > m); 63*da2e3ebdSchin sfstrseek(np, n, SEEK_CUR); 64*da2e3ebdSchin s = (const char*)sfstruse(np); 65*da2e3ebdSchin for (;;) 66*da2e3ebdSchin { 67*da2e3ebdSchin switch (c = *s++) 68*da2e3ebdSchin { 69*da2e3ebdSchin case 0: 70*da2e3ebdSchin break; 71*da2e3ebdSchin case '\\': 72*da2e3ebdSchin case '"': 73*da2e3ebdSchin sfputc(qp, '\\'); 74*da2e3ebdSchin /*FALLTHROUGH*/ 75*da2e3ebdSchin default: 76*da2e3ebdSchin sfputc(qp, c); 77*da2e3ebdSchin continue; 78*da2e3ebdSchin } 79*da2e3ebdSchin break; 80*da2e3ebdSchin } 81*da2e3ebdSchin if (!(xp = ppsetfile(sfstruse(qp)))) 82*da2e3ebdSchin return (char*)s; 83*da2e3ebdSchin return xp->name; 84*da2e3ebdSchin } 85*da2e3ebdSchin 86*da2e3ebdSchin /* 87*da2e3ebdSchin * push stream onto input stack 88*da2e3ebdSchin * used by the PUSH_type macros 89*da2e3ebdSchin */ 90*da2e3ebdSchin 91*da2e3ebdSchin void 92*da2e3ebdSchin pppush(register int t, register char* s, register char* p, int n) 93*da2e3ebdSchin { 94*da2e3ebdSchin register struct ppinstk* cur; 95*da2e3ebdSchin 96*da2e3ebdSchin PUSH(t, cur); 97*da2e3ebdSchin cur->line = error_info.line; 98*da2e3ebdSchin cur->file = error_info.file; 99*da2e3ebdSchin switch (t) 100*da2e3ebdSchin { 101*da2e3ebdSchin case IN_FILE: 102*da2e3ebdSchin if (pp.option & NATIVE) 103*da2e3ebdSchin s = native(s); 104*da2e3ebdSchin cur->flags |= IN_newline; 105*da2e3ebdSchin cur->fd = n; 106*da2e3ebdSchin cur->hide = ++pp.hide; 107*da2e3ebdSchin cur->symbol = 0; 108*da2e3ebdSchin #if CHECKPOINT 109*da2e3ebdSchin if ((pp.mode & (DUMP|INIT)) == DUMP) 110*da2e3ebdSchin { 111*da2e3ebdSchin cur->index = newof(0, struct ppindex, 1, 0); 112*da2e3ebdSchin if (pp.lastindex) pp.lastindex->next = cur->index; 113*da2e3ebdSchin else pp.firstindex = cur->index; 114*da2e3ebdSchin pp.lastindex = cur->index; 115*da2e3ebdSchin cur->index->file = pp.original; 116*da2e3ebdSchin cur->index->begin = ppoffset(); 117*da2e3ebdSchin } 118*da2e3ebdSchin #endif 119*da2e3ebdSchin n = 1; 120*da2e3ebdSchin #if CHECKPOINT 121*da2e3ebdSchin if (!(pp.mode & DUMP)) 122*da2e3ebdSchin #endif 123*da2e3ebdSchin if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0)) 124*da2e3ebdSchin cur->flags |= IN_flush; 125*da2e3ebdSchin #if ARCHIVE 126*da2e3ebdSchin if (pp.member) 127*da2e3ebdSchin { 128*da2e3ebdSchin switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT)) 129*da2e3ebdSchin { 130*da2e3ebdSchin case 0: 131*da2e3ebdSchin #if CHECKPOINT 132*da2e3ebdSchin cur->buflen = pp.member->size; 133*da2e3ebdSchin #endif 134*da2e3ebdSchin p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ; 135*da2e3ebdSchin if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset) 136*da2e3ebdSchin error(3, "%s: archive seek error", pp.member->archive->name); 137*da2e3ebdSchin if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size) 138*da2e3ebdSchin error(3, "%s: archive read error", pp.member->archive->name); 139*da2e3ebdSchin pp.member = 0; 140*da2e3ebdSchin break; 141*da2e3ebdSchin case TYPE_BUFFER: 142*da2e3ebdSchin #if CHECKPOINT 143*da2e3ebdSchin case TYPE_CHECKPOINT|TYPE_BUFFER: 144*da2e3ebdSchin cur->buflen = pp.member->size; 145*da2e3ebdSchin #endif 146*da2e3ebdSchin p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset; 147*da2e3ebdSchin cur->flags |= IN_static; 148*da2e3ebdSchin pp.member = 0; 149*da2e3ebdSchin break; 150*da2e3ebdSchin #if CHECKPOINT 151*da2e3ebdSchin case TYPE_CHECKPOINT: 152*da2e3ebdSchin p = cur->buffer = ""; 153*da2e3ebdSchin cur->flags |= IN_static; 154*da2e3ebdSchin break; 155*da2e3ebdSchin #endif 156*da2e3ebdSchin } 157*da2e3ebdSchin cur->flags |= IN_eof|IN_newline; 158*da2e3ebdSchin cur->fd = -1; 159*da2e3ebdSchin } 160*da2e3ebdSchin else 161*da2e3ebdSchin #endif 162*da2e3ebdSchin { 163*da2e3ebdSchin if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET)) 164*da2e3ebdSchin cur->flags |= IN_regular; 165*da2e3ebdSchin errno = 0; 166*da2e3ebdSchin #if PROTOTYPE 167*da2e3ebdSchin 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)))) 168*da2e3ebdSchin { 169*da2e3ebdSchin *(p = cur->buffer - 1) = 0; 170*da2e3ebdSchin cur->buffer -= PPBAKSIZ; 171*da2e3ebdSchin cur->flags |= IN_prototype; 172*da2e3ebdSchin cur->fd = -1; 173*da2e3ebdSchin } 174*da2e3ebdSchin else 175*da2e3ebdSchin #endif 176*da2e3ebdSchin *(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0; 177*da2e3ebdSchin } 178*da2e3ebdSchin if (pp.incref && !(pp.mode & INIT)) 179*da2e3ebdSchin (*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH); 180*da2e3ebdSchin if (pp.macref || (pp.option & IGNORELINE)) 181*da2e3ebdSchin cur->flags |= IN_ignoreline; 182*da2e3ebdSchin cur->prefix = pp.prefix; 183*da2e3ebdSchin /*FALLTHROUGH*/ 184*da2e3ebdSchin case IN_BUFFER: 185*da2e3ebdSchin case IN_INIT: 186*da2e3ebdSchin case IN_RESCAN: 187*da2e3ebdSchin pushcontrol(); 188*da2e3ebdSchin cur->control = pp.control; 189*da2e3ebdSchin *pp.control = 0; 190*da2e3ebdSchin cur->vendor = pp.vendor; 191*da2e3ebdSchin if (cur->type != IN_RESCAN) 192*da2e3ebdSchin { 193*da2e3ebdSchin if (cur->type == IN_INIT) 194*da2e3ebdSchin pp.mode |= MARKHOSTED; 195*da2e3ebdSchin error_info.file = s; 196*da2e3ebdSchin error_info.line = n; 197*da2e3ebdSchin } 198*da2e3ebdSchin if (pp.state & HIDDEN) 199*da2e3ebdSchin { 200*da2e3ebdSchin pp.state &= ~HIDDEN; 201*da2e3ebdSchin pp.hidden = 0; 202*da2e3ebdSchin if (!(pp.state & NOTEXT) && pplastout() != '\n') 203*da2e3ebdSchin ppputchar('\n'); 204*da2e3ebdSchin } 205*da2e3ebdSchin pp.state |= NEWLINE; 206*da2e3ebdSchin if (pp.mode & HOSTED) cur->flags |= IN_hosted; 207*da2e3ebdSchin else cur->flags &= ~IN_hosted; 208*da2e3ebdSchin if (pp.mode & (INIT|MARKHOSTED)) 209*da2e3ebdSchin { 210*da2e3ebdSchin pp.mode |= HOSTED; 211*da2e3ebdSchin pp.flags |= PP_hosted; 212*da2e3ebdSchin } 213*da2e3ebdSchin switch (cur->type) 214*da2e3ebdSchin { 215*da2e3ebdSchin case IN_FILE: 216*da2e3ebdSchin if (!(pp.mode & (INIT|MARKHOSTED))) 217*da2e3ebdSchin { 218*da2e3ebdSchin pp.mode &= ~HOSTED; 219*da2e3ebdSchin pp.flags &= ~PP_hosted; 220*da2e3ebdSchin } 221*da2e3ebdSchin #if CATSTRINGS 222*da2e3ebdSchin if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE; 223*da2e3ebdSchin else 224*da2e3ebdSchin #endif 225*da2e3ebdSchin if (pp.linesync) 226*da2e3ebdSchin (*pp.linesync)(error_info.line, error_info.file); 227*da2e3ebdSchin #if ARCHIVE && CHECKPOINT 228*da2e3ebdSchin if (pp.member) 229*da2e3ebdSchin ppload(NiL); 230*da2e3ebdSchin #endif 231*da2e3ebdSchin if (pp.mode & MARKC) 232*da2e3ebdSchin { 233*da2e3ebdSchin cur->flags |= IN_c; 234*da2e3ebdSchin pp.mode &= ~MARKC; 235*da2e3ebdSchin if (!(cur->prev->flags & IN_c)) 236*da2e3ebdSchin { 237*da2e3ebdSchin debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); 238*da2e3ebdSchin PUSH_BUFFER("C", "extern \"C\" {\n", 1); 239*da2e3ebdSchin return; 240*da2e3ebdSchin } 241*da2e3ebdSchin } 242*da2e3ebdSchin else if (cur->prev->flags & IN_c) 243*da2e3ebdSchin { 244*da2e3ebdSchin debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); 245*da2e3ebdSchin PUSH_BUFFER("C", "extern \"C++\" {\n", 1); 246*da2e3ebdSchin return; 247*da2e3ebdSchin } 248*da2e3ebdSchin break; 249*da2e3ebdSchin case IN_BUFFER: 250*da2e3ebdSchin cur->buffer = p = strdup(p); 251*da2e3ebdSchin break; 252*da2e3ebdSchin default: 253*da2e3ebdSchin cur->buffer = p; 254*da2e3ebdSchin break; 255*da2e3ebdSchin } 256*da2e3ebdSchin cur->nextchr = p; 257*da2e3ebdSchin break; 258*da2e3ebdSchin #if DEBUG 259*da2e3ebdSchin default: 260*da2e3ebdSchin error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type); 261*da2e3ebdSchin break; 262*da2e3ebdSchin #endif 263*da2e3ebdSchin } 264*da2e3ebdSchin debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); 265*da2e3ebdSchin } 266*da2e3ebdSchin 267*da2e3ebdSchin /* 268*da2e3ebdSchin * external buffer push 269*da2e3ebdSchin */ 270*da2e3ebdSchin 271*da2e3ebdSchin void 272*da2e3ebdSchin ppinput(char* b, char* f, int n) 273*da2e3ebdSchin { 274*da2e3ebdSchin PUSH_BUFFER(f, b, n); 275*da2e3ebdSchin } 276*da2e3ebdSchin 277*da2e3ebdSchin /* 278*da2e3ebdSchin * return expanded value of buffer p 279*da2e3ebdSchin */ 280*da2e3ebdSchin 281*da2e3ebdSchin char* 282*da2e3ebdSchin ppexpand(register char* p) 283*da2e3ebdSchin { 284*da2e3ebdSchin register char* m; 285*da2e3ebdSchin register int n; 286*da2e3ebdSchin register int c; 287*da2e3ebdSchin long restore; 288*da2e3ebdSchin char* pptoken; 289*da2e3ebdSchin char* ppmactop; 290*da2e3ebdSchin struct ppmacstk* nextmacp; 291*da2e3ebdSchin struct ppinstk* cur; 292*da2e3ebdSchin 293*da2e3ebdSchin debug((-7, "before expand: %s", p)); 294*da2e3ebdSchin if (ppmactop = pp.mactop) 295*da2e3ebdSchin { 296*da2e3ebdSchin nextmacp = pp.macp->next; 297*da2e3ebdSchin nextframe(pp.macp, pp.mactop); 298*da2e3ebdSchin } 299*da2e3ebdSchin restore = pp.state & (COLLECTING|DISABLE|STRIP); 300*da2e3ebdSchin pp.state &= ~restore; 301*da2e3ebdSchin pp.mode &= ~MARKMACRO; 302*da2e3ebdSchin PUSH_STRING(p); 303*da2e3ebdSchin cur = pp.in; 304*da2e3ebdSchin pp.in->flags |= IN_expand; 305*da2e3ebdSchin pptoken = pp.token; 306*da2e3ebdSchin n = 2 * MAXTOKEN; 307*da2e3ebdSchin pp.token = p = oldof(0, char, 0, n); 308*da2e3ebdSchin m = p + MAXTOKEN; 309*da2e3ebdSchin for (;;) 310*da2e3ebdSchin { 311*da2e3ebdSchin if (pplex()) 312*da2e3ebdSchin { 313*da2e3ebdSchin if ((pp.token = pp.toknxt) > m) 314*da2e3ebdSchin { 315*da2e3ebdSchin c = pp.token - p; 316*da2e3ebdSchin p = newof(p, char, n += MAXTOKEN, 0); 317*da2e3ebdSchin m = p + n - MAXTOKEN; 318*da2e3ebdSchin pp.token = p + c; 319*da2e3ebdSchin } 320*da2e3ebdSchin if (pp.mode & MARKMACRO) 321*da2e3ebdSchin { 322*da2e3ebdSchin pp.mode &= ~MARKMACRO; 323*da2e3ebdSchin *pp.token++ = MARK; 324*da2e3ebdSchin *pp.token++ = 'X'; 325*da2e3ebdSchin } 326*da2e3ebdSchin } 327*da2e3ebdSchin else if (pp.in == cur) 328*da2e3ebdSchin break; 329*da2e3ebdSchin } 330*da2e3ebdSchin *pp.token = 0; 331*da2e3ebdSchin if (ppmactop) 332*da2e3ebdSchin pp.macp->next = nextmacp; 333*da2e3ebdSchin debug((-7, "after expand: %s", p)); 334*da2e3ebdSchin pp.token = pptoken; 335*da2e3ebdSchin pp.state |= restore; 336*da2e3ebdSchin pp.in = pp.in->prev; 337*da2e3ebdSchin return p; 338*da2e3ebdSchin } 339*da2e3ebdSchin 340*da2e3ebdSchin #if CHECKPOINT 341*da2e3ebdSchin 342*da2e3ebdSchin #define LOAD_FUNCTION (1<<0) 343*da2e3ebdSchin #define LOAD_MULTILINE (1<<1) 344*da2e3ebdSchin #define LOAD_NOEXPAND (1<<2) 345*da2e3ebdSchin #define LOAD_PREDICATE (1<<3) 346*da2e3ebdSchin #define LOAD_READONLY (1<<4) 347*da2e3ebdSchin #define LOAD_VARIADIC (1<<5) 348*da2e3ebdSchin 349*da2e3ebdSchin /* 350*da2e3ebdSchin * macro definition dump 351*da2e3ebdSchin */ 352*da2e3ebdSchin 353*da2e3ebdSchin static int 354*da2e3ebdSchin dump(const char* name, char* v, void* handle) 355*da2e3ebdSchin { 356*da2e3ebdSchin register struct ppmacro* mac; 357*da2e3ebdSchin register struct ppsymbol* sym = (struct ppsymbol*)v; 358*da2e3ebdSchin register int flags; 359*da2e3ebdSchin 360*da2e3ebdSchin NoP(name); 361*da2e3ebdSchin NoP(handle); 362*da2e3ebdSchin if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED))) 363*da2e3ebdSchin { 364*da2e3ebdSchin ppprintf("%s", sym->name); 365*da2e3ebdSchin ppputchar(0); 366*da2e3ebdSchin flags = 0; 367*da2e3ebdSchin if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION; 368*da2e3ebdSchin if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE; 369*da2e3ebdSchin if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND; 370*da2e3ebdSchin if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE; 371*da2e3ebdSchin if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY; 372*da2e3ebdSchin if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC; 373*da2e3ebdSchin ppputchar(flags); 374*da2e3ebdSchin if (sym->flags & SYM_FUNCTION) 375*da2e3ebdSchin { 376*da2e3ebdSchin ppprintf("%d", mac->arity); 377*da2e3ebdSchin ppputchar(0); 378*da2e3ebdSchin if (mac->arity) 379*da2e3ebdSchin { 380*da2e3ebdSchin ppprintf("%s", mac->formals); 381*da2e3ebdSchin ppputchar(0); 382*da2e3ebdSchin } 383*da2e3ebdSchin } 384*da2e3ebdSchin ppprintf("%s", mac->value); 385*da2e3ebdSchin ppputchar(0); 386*da2e3ebdSchin } 387*da2e3ebdSchin return(0); 388*da2e3ebdSchin } 389*da2e3ebdSchin 390*da2e3ebdSchin /* 391*da2e3ebdSchin * dump macro definitions for quick loading via ppload() 392*da2e3ebdSchin */ 393*da2e3ebdSchin 394*da2e3ebdSchin void 395*da2e3ebdSchin ppdump(void) 396*da2e3ebdSchin { 397*da2e3ebdSchin register struct ppindex* ip; 398*da2e3ebdSchin unsigned long macro_offset; 399*da2e3ebdSchin unsigned long index_offset; 400*da2e3ebdSchin 401*da2e3ebdSchin /* 402*da2e3ebdSchin * NOTE: we assume '\0' does not occur in valid preprocessed output 403*da2e3ebdSchin */ 404*da2e3ebdSchin 405*da2e3ebdSchin ppputchar(0); 406*da2e3ebdSchin 407*da2e3ebdSchin /* 408*da2e3ebdSchin * output global flags 409*da2e3ebdSchin */ 410*da2e3ebdSchin 411*da2e3ebdSchin macro_offset = ppoffset(); 412*da2e3ebdSchin ppputchar(0); 413*da2e3ebdSchin 414*da2e3ebdSchin /* 415*da2e3ebdSchin * output macro definitions 416*da2e3ebdSchin */ 417*da2e3ebdSchin 418*da2e3ebdSchin hashwalk(pp.symtab, 0, dump, NiL); 419*da2e3ebdSchin ppputchar(0); 420*da2e3ebdSchin 421*da2e3ebdSchin /* 422*da2e3ebdSchin * output include file index 423*da2e3ebdSchin */ 424*da2e3ebdSchin 425*da2e3ebdSchin index_offset = ppoffset(); 426*da2e3ebdSchin ip = pp.firstindex; 427*da2e3ebdSchin while (ip) 428*da2e3ebdSchin { 429*da2e3ebdSchin ppprintf("%s", ip->file->name); 430*da2e3ebdSchin ppputchar(0); 431*da2e3ebdSchin if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST) 432*da2e3ebdSchin ppprintf("%s", ip->file->guard->name); 433*da2e3ebdSchin ppputchar(0); 434*da2e3ebdSchin ppprintf("%lu", ip->begin); 435*da2e3ebdSchin ppputchar(0); 436*da2e3ebdSchin ppprintf("%lu", ip->end); 437*da2e3ebdSchin ppputchar(0); 438*da2e3ebdSchin ip = ip->next; 439*da2e3ebdSchin } 440*da2e3ebdSchin ppputchar(0); 441*da2e3ebdSchin 442*da2e3ebdSchin /* 443*da2e3ebdSchin * output offset directory 444*da2e3ebdSchin */ 445*da2e3ebdSchin 446*da2e3ebdSchin ppprintf("%010lu", macro_offset); 447*da2e3ebdSchin ppputchar(0); 448*da2e3ebdSchin ppprintf("%010lu", index_offset); 449*da2e3ebdSchin ppputchar(0); 450*da2e3ebdSchin ppflushout(); 451*da2e3ebdSchin } 452*da2e3ebdSchin 453*da2e3ebdSchin /* 454*da2e3ebdSchin * load text and macro definitions from a previous ppdump() 455*da2e3ebdSchin * s is the string argument from the pragma (including quotes) 456*da2e3ebdSchin */ 457*da2e3ebdSchin 458*da2e3ebdSchin void 459*da2e3ebdSchin ppload(register char* s) 460*da2e3ebdSchin { 461*da2e3ebdSchin register char* b; 462*da2e3ebdSchin register Sfio_t* sp; 463*da2e3ebdSchin int m; 464*da2e3ebdSchin char* g; 465*da2e3ebdSchin char* t; 466*da2e3ebdSchin unsigned long n; 467*da2e3ebdSchin unsigned long p; 468*da2e3ebdSchin unsigned long macro_offset; 469*da2e3ebdSchin unsigned long index_offset; 470*da2e3ebdSchin unsigned long file_offset; 471*da2e3ebdSchin unsigned long file_size; 472*da2e3ebdSchin unsigned long keep_begin; 473*da2e3ebdSchin unsigned long keep_end; 474*da2e3ebdSchin unsigned long skip_end; 475*da2e3ebdSchin unsigned long next_begin; 476*da2e3ebdSchin unsigned long next_end; 477*da2e3ebdSchin struct ppfile* fp; 478*da2e3ebdSchin struct ppsymbol* sym; 479*da2e3ebdSchin struct ppmacro* mac; 480*da2e3ebdSchin 481*da2e3ebdSchin char* ip = 0; 482*da2e3ebdSchin 483*da2e3ebdSchin pp.mode |= LOADING; 484*da2e3ebdSchin if (!(pp.state & STANDALONE)) 485*da2e3ebdSchin error(3, "checkpoint load in standalone mode only"); 486*da2e3ebdSchin #if ARCHIVE 487*da2e3ebdSchin if (pp.member) 488*da2e3ebdSchin { 489*da2e3ebdSchin sp = pp.member->archive->info.sp; 490*da2e3ebdSchin file_offset = pp.member->offset; 491*da2e3ebdSchin file_size = pp.member->size; 492*da2e3ebdSchin if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1))) 493*da2e3ebdSchin error(3, "checkpoint magic error"); 494*da2e3ebdSchin } 495*da2e3ebdSchin else 496*da2e3ebdSchin #endif 497*da2e3ebdSchin { 498*da2e3ebdSchin if (pp.in->type != IN_FILE) 499*da2e3ebdSchin error(3, "checkpoint load from files only"); 500*da2e3ebdSchin if (pp.in->flags & IN_prototype) 501*da2e3ebdSchin pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ); 502*da2e3ebdSchin file_offset = 0; 503*da2e3ebdSchin if (pp.in->fd >= 0) 504*da2e3ebdSchin { 505*da2e3ebdSchin if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ))) 506*da2e3ebdSchin error(3, "checkpoint read error"); 507*da2e3ebdSchin file_size = sfseek(sp, 0L, SEEK_END); 508*da2e3ebdSchin } 509*da2e3ebdSchin else 510*da2e3ebdSchin { 511*da2e3ebdSchin file_size = pp.in->buflen; 512*da2e3ebdSchin if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING))) 513*da2e3ebdSchin error(3, "checkpoint read error"); 514*da2e3ebdSchin } 515*da2e3ebdSchin } 516*da2e3ebdSchin if (!streq(s, pp.checkpoint)) 517*da2e3ebdSchin error(3, "checkpoint version %s does not match %s", s, pp.checkpoint); 518*da2e3ebdSchin 519*da2e3ebdSchin /* 520*da2e3ebdSchin * get the macro and index offsets 521*da2e3ebdSchin */ 522*da2e3ebdSchin 523*da2e3ebdSchin p = file_offset + file_size - 22; 524*da2e3ebdSchin if ((n = sfseek(sp, p, SEEK_SET)) != p) 525*da2e3ebdSchin error(3, "checkpoint directory seek error"); 526*da2e3ebdSchin if (!(t = sfreserve(sp, 22, 0))) 527*da2e3ebdSchin error(3, "checkpoint directory read error"); 528*da2e3ebdSchin macro_offset = file_offset + strtol(t, &t, 10); 529*da2e3ebdSchin index_offset = file_offset + strtol(t + 1, NiL, 10); 530*da2e3ebdSchin 531*da2e3ebdSchin /* 532*da2e3ebdSchin * read the include index 533*da2e3ebdSchin */ 534*da2e3ebdSchin 535*da2e3ebdSchin if (sfseek(sp, index_offset, SEEK_SET) != index_offset) 536*da2e3ebdSchin error(3, "checkpoint index seek error"); 537*da2e3ebdSchin if (!(s = sfreserve(sp, n - index_offset, 0))) 538*da2e3ebdSchin error(3, "checkpoint index read error"); 539*da2e3ebdSchin if (sfset(sp, 0, 0) & SF_STRING) 540*da2e3ebdSchin b = s; 541*da2e3ebdSchin else if (!(b = ip = memdup(s, n - index_offset))) 542*da2e3ebdSchin error(3, "checkpoint index alloc error"); 543*da2e3ebdSchin 544*da2e3ebdSchin /* 545*da2e3ebdSchin * loop on the index and copy the non-ignored chunks to the output 546*da2e3ebdSchin */ 547*da2e3ebdSchin 548*da2e3ebdSchin ppcheckout(); 549*da2e3ebdSchin p = PPBUFSIZ - (pp.outp - pp.outbuf); 550*da2e3ebdSchin keep_begin = 0; 551*da2e3ebdSchin keep_end = 0; 552*da2e3ebdSchin skip_end = 0; 553*da2e3ebdSchin while (*b) 554*da2e3ebdSchin { 555*da2e3ebdSchin fp = ppsetfile(b); 556*da2e3ebdSchin while (*b++); 557*da2e3ebdSchin g = b; 558*da2e3ebdSchin while (*b++); 559*da2e3ebdSchin next_begin = strtol(b, &t, 10); 560*da2e3ebdSchin next_end = strtol(t + 1, &t, 10); 561*da2e3ebdSchin 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); 562*da2e3ebdSchin b = t + 1; 563*da2e3ebdSchin if (next_begin >= skip_end) 564*da2e3ebdSchin { 565*da2e3ebdSchin if (!ppmultiple(fp, INC_TEST)) 566*da2e3ebdSchin { 567*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name); 568*da2e3ebdSchin if (!keep_begin && skip_end < next_begin) 569*da2e3ebdSchin keep_begin = skip_end; 570*da2e3ebdSchin if (keep_begin) 571*da2e3ebdSchin { 572*da2e3ebdSchin flush: 573*da2e3ebdSchin if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin) 574*da2e3ebdSchin error(3, "checkpoint data seek error"); 575*da2e3ebdSchin n = next_begin - keep_begin; 576*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p); 577*da2e3ebdSchin while (n > p) 578*da2e3ebdSchin { 579*da2e3ebdSchin if (sfread(sp, pp.outp, p) != p) 580*da2e3ebdSchin error(3, "checkpoint data read error"); 581*da2e3ebdSchin PPWRITE(PPBUFSIZ); 582*da2e3ebdSchin pp.outp = pp.outbuf; 583*da2e3ebdSchin n -= p; 584*da2e3ebdSchin p = PPBUFSIZ; 585*da2e3ebdSchin } 586*da2e3ebdSchin if (n) 587*da2e3ebdSchin { 588*da2e3ebdSchin if (sfread(sp, pp.outp, n) != n) 589*da2e3ebdSchin error(3, "checkpoint data read error"); 590*da2e3ebdSchin pp.outp += n; 591*da2e3ebdSchin p -= n; 592*da2e3ebdSchin } 593*da2e3ebdSchin keep_begin = 0; 594*da2e3ebdSchin if (keep_end <= next_end) 595*da2e3ebdSchin keep_end = 0; 596*da2e3ebdSchin } 597*da2e3ebdSchin skip_end = next_end; 598*da2e3ebdSchin } 599*da2e3ebdSchin else if (!keep_begin) 600*da2e3ebdSchin { 601*da2e3ebdSchin if (skip_end) 602*da2e3ebdSchin { 603*da2e3ebdSchin keep_begin = skip_end; 604*da2e3ebdSchin skip_end = 0; 605*da2e3ebdSchin } 606*da2e3ebdSchin else keep_begin = next_begin; 607*da2e3ebdSchin if (keep_end < next_end) 608*da2e3ebdSchin keep_end = next_end; 609*da2e3ebdSchin } 610*da2e3ebdSchin } 611*da2e3ebdSchin if (*g && fp->guard != INC_IGNORE) 612*da2e3ebdSchin fp->guard = ppsymset(pp.symtab, g); 613*da2e3ebdSchin } 614*da2e3ebdSchin if (keep_end) 615*da2e3ebdSchin { 616*da2e3ebdSchin if (!keep_begin) 617*da2e3ebdSchin keep_begin = skip_end > next_end ? skip_end : next_end; 618*da2e3ebdSchin next_begin = next_end = keep_end; 619*da2e3ebdSchin g = b; 620*da2e3ebdSchin goto flush; 621*da2e3ebdSchin } 622*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT)); 623*da2e3ebdSchin 624*da2e3ebdSchin /* 625*da2e3ebdSchin * read the compacted definitions 626*da2e3ebdSchin */ 627*da2e3ebdSchin 628*da2e3ebdSchin if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset) 629*da2e3ebdSchin error(3, "checkpoint macro seek error"); 630*da2e3ebdSchin if (!(s = sfreserve(sp, index_offset - macro_offset, 0))) 631*da2e3ebdSchin error(3, "checkpoint macro read error"); 632*da2e3ebdSchin 633*da2e3ebdSchin /* 634*da2e3ebdSchin * read the flags 635*da2e3ebdSchin */ 636*da2e3ebdSchin 637*da2e3ebdSchin while (*s) 638*da2e3ebdSchin { 639*da2e3ebdSchin #if _options_dumped_ 640*da2e3ebdSchin if (streq(s, "OPTION")) /* ... */; 641*da2e3ebdSchin else 642*da2e3ebdSchin #endif 643*da2e3ebdSchin error(3, "%-.48s: unknown flags in checkpoint file", s); 644*da2e3ebdSchin } 645*da2e3ebdSchin s++; 646*da2e3ebdSchin 647*da2e3ebdSchin /* 648*da2e3ebdSchin * unpack and enter the definitions 649*da2e3ebdSchin */ 650*da2e3ebdSchin 651*da2e3ebdSchin while (*s) 652*da2e3ebdSchin { 653*da2e3ebdSchin b = s; 654*da2e3ebdSchin while (*s++); 655*da2e3ebdSchin m = *s++; 656*da2e3ebdSchin sym = ppsymset(pp.symtab, b); 657*da2e3ebdSchin if (sym->macro) 658*da2e3ebdSchin { 659*da2e3ebdSchin if (m & LOAD_FUNCTION) 660*da2e3ebdSchin { 661*da2e3ebdSchin if (*s++ != '0') 662*da2e3ebdSchin while (*s++); 663*da2e3ebdSchin while (*s++); 664*da2e3ebdSchin } 665*da2e3ebdSchin if (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value); 666*da2e3ebdSchin while (*s++); 667*da2e3ebdSchin } 668*da2e3ebdSchin else 669*da2e3ebdSchin { 670*da2e3ebdSchin ppfsm(FSM_MACRO, b); 671*da2e3ebdSchin sym->flags = 0; 672*da2e3ebdSchin if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION; 673*da2e3ebdSchin if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE; 674*da2e3ebdSchin if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND; 675*da2e3ebdSchin if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE; 676*da2e3ebdSchin if (m & LOAD_READONLY) sym->flags |= SYM_READONLY; 677*da2e3ebdSchin if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC; 678*da2e3ebdSchin mac = sym->macro = newof(0, struct ppmacro, 1, 0); 679*da2e3ebdSchin if (sym->flags & SYM_FUNCTION) 680*da2e3ebdSchin { 681*da2e3ebdSchin for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0'); 682*da2e3ebdSchin if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name); 683*da2e3ebdSchin if (mac->arity = n) 684*da2e3ebdSchin { 685*da2e3ebdSchin b = s; 686*da2e3ebdSchin while (*s++); 687*da2e3ebdSchin mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b); 688*da2e3ebdSchin } 689*da2e3ebdSchin } 690*da2e3ebdSchin b = s; 691*da2e3ebdSchin while (*s++); 692*da2e3ebdSchin mac->size = s - b - 1; 693*da2e3ebdSchin mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1); 694*da2e3ebdSchin if (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value); 695*da2e3ebdSchin } 696*da2e3ebdSchin } 697*da2e3ebdSchin 698*da2e3ebdSchin /* 699*da2e3ebdSchin * we are now at EOF 700*da2e3ebdSchin */ 701*da2e3ebdSchin 702*da2e3ebdSchin if (ip) 703*da2e3ebdSchin { 704*da2e3ebdSchin pp.in->fd = -1; 705*da2e3ebdSchin free(ip); 706*da2e3ebdSchin } 707*da2e3ebdSchin #if ARCHIVE 708*da2e3ebdSchin if (pp.member) pp.member = 0; 709*da2e3ebdSchin else 710*da2e3ebdSchin #endif 711*da2e3ebdSchin { 712*da2e3ebdSchin sfclose(sp); 713*da2e3ebdSchin pp.in->flags |= IN_eof|IN_newline; 714*da2e3ebdSchin pp.in->nextchr = pp.in->buffer + PPBAKSIZ; 715*da2e3ebdSchin *pp.in->nextchr++ = 0; 716*da2e3ebdSchin *pp.in->nextchr = 0; 717*da2e3ebdSchin } 718*da2e3ebdSchin pp.mode &= ~LOADING; 719*da2e3ebdSchin } 720*da2e3ebdSchin 721*da2e3ebdSchin #endif 722