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