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 library control interface 26 */ 27 28 #include "pplib.h" 29 #include "pptab.h" 30 31 #include <ls.h> 32 33 #define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab) 34 #define REFALL (pp.truncate?pp.dirtab:pp.symtab) 35 36 #define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value) 37 38 /* 39 * set option value 40 * initialization files have lowest precedence 41 */ 42 43 int 44 ppset(register long* p, register long op, int val) 45 { 46 long* r; 47 48 r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option; 49 if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & op)) 50 { 51 debug((-7, "set %s %s skipped -- readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r))); 52 return 0; 53 } 54 if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN)) && (p != &pp.mode || !(op & BUILTIN)) && (p != &pp.option || !(op & PREDEFINED))) 55 { 56 *r |= op; 57 debug((-7, "set %s %s readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r))); 58 } 59 if (val) 60 *p |= op; 61 else 62 *p &= ~op; 63 debug((-7, "set %s %s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r))); 64 return 1; 65 } 66 67 /* 68 * initialize hash table with keywords from key 69 */ 70 71 static void 72 inithash(register Hash_table_t* tab, register struct ppkeyword* key) 73 { 74 register char* s; 75 76 for (; s = key->name; key++) 77 { 78 if (!ppisid(*s)) 79 s++; 80 hashput(tab, s, key->value); 81 } 82 } 83 84 /* 85 * return ppkeyword table name given value 86 */ 87 88 char* 89 ppkeyname(register int value, int dir) 90 { 91 register char* s; 92 register struct ppkeyword* p; 93 94 if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p))) 95 { 96 s = (p + (value - p->value))->name; 97 return s + !ppisid(*s); 98 } 99 #if DEBUG 100 error(PANIC, "no keyword table name for value=%d", value); 101 #endif 102 return "UNKNOWN"; 103 } 104 105 /* 106 * add to the include maps 107 */ 108 109 void 110 ppmapinclude(char* file, register char* s) 111 { 112 register int c; 113 register struct ppdirs* dp; 114 int fd; 115 int flags; 116 int index; 117 int token; 118 char* t; 119 char* old_file; 120 long old_state; 121 struct ppfile* fp; 122 struct ppfile* mp; 123 124 old_file = error_info.file; 125 old_state = pp.state; 126 if (s) 127 PUSH_BUFFER("mapinclude", s, 1); 128 else if (file) 129 { 130 if (*file == '-') 131 { 132 if (!error_info.file) 133 { 134 error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE)); 135 return; 136 } 137 s = t = strcopy(pp.tmpbuf, error_info.file); 138 c = *++file; 139 for (;;) 140 { 141 if (s <= pp.tmpbuf || *s == '/') 142 { 143 s = t; 144 break; 145 } 146 else if (*s == c) 147 break; 148 s--; 149 } 150 strcpy(s, file); 151 file = pp.tmpbuf; 152 } 153 if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0) 154 return; 155 PUSH_FILE(file, fd); 156 } 157 else 158 return; 159 #if CATSTRINGS 160 pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF); 161 #else 162 pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF); 163 #endif 164 pp.level++; 165 flags = INC_MAPALL; 166 fp = mp = 0; 167 for (;;) 168 { 169 switch (token = pplex()) 170 { 171 case 0: 172 case T_STRING: 173 case T_HEADER: 174 if (fp) 175 { 176 fp->guard = INC_IGNORE; 177 for (dp = pp.firstdir->next; dp; dp = dp->next) 178 if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/') 179 { 180 ppsetfile(fp->name + c + 1)->guard = INC_IGNORE; 181 break; 182 } 183 } 184 if (!token) 185 break; 186 pathcanon(pp.token, 0, 0); 187 fp = ppsetfile(pp.token); 188 if (mp) 189 { 190 mp->flags |= flags; 191 if (streq(fp->name, ".")) 192 mp->flags |= INC_MAPNOLOCAL; 193 else 194 mp->bound[index] = fp; 195 196 fp = mp = 0; 197 } 198 else 199 index = token == T_HEADER ? INC_STANDARD : INC_LOCAL; 200 continue; 201 case '=': 202 if (!(mp = fp)) 203 error(3, "%s: \"name\" = \"binding\" expected"); 204 fp = 0; 205 continue; 206 case '\n': 207 continue; 208 case T_ID: 209 if (streq(pp.token, "all")) 210 { 211 flags = INC_MAPALL; 212 continue; 213 } 214 else if (streq(pp.token, "hosted")) 215 { 216 flags = INC_MAPHOSTED; 217 continue; 218 } 219 else if (streq(pp.token, "nohosted")) 220 { 221 flags = INC_MAPNOHOSTED; 222 continue; 223 } 224 /*FALLTHROUGH*/ 225 default: 226 error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE)); 227 break; 228 } 229 break; 230 } 231 pp.level--; 232 error_info.file = old_file; 233 pp.state = old_state; 234 } 235 236 /* 237 * return non-0 if file is identical to fd 238 */ 239 240 static int 241 identical(char* file, int fd) 242 { 243 struct stat a; 244 struct stat b; 245 246 return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino; 247 } 248 249 /* 250 * compare up to pp.truncate chars 251 * 252 * NOTE: __STD* and symbols containing ' ' are not truncated 253 */ 254 255 static int 256 trunccomp(register char* a, register char* b) 257 { 258 return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b); 259 } 260 261 /* 262 * hash up to pp.truncate chars 263 * 264 * NOTE: __STD* and symbols containing ' ' are not truncated 265 */ 266 267 static unsigned int 268 trunchash(char* a) 269 { 270 int n; 271 272 return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n); 273 } 274 275 #if DEBUG & TRACE_debug 276 /* 277 * append context to debug trace 278 */ 279 280 static int 281 context(Sfio_t* sp, int level, int flags) 282 { 283 static int state; 284 285 NoP(level); 286 NoP(flags); 287 if (error_info.trace <= -10 && pp.state != state) 288 { 289 state = pp.state; 290 sfprintf(sp, " %s", ppstatestr(pp.state)); 291 } 292 return 1; 293 } 294 #endif 295 296 /* 297 * reset include guard 298 */ 299 300 static int 301 unguard(const char* name, char* v, void* handle) 302 { 303 register struct ppfile* fp = (struct ppfile*)v; 304 305 fp->guard = 0; 306 return 0; 307 } 308 309 /* 310 * reset macro definition 311 */ 312 313 static void 314 undefine(void* p) 315 { 316 struct ppmacro* mac = ((struct ppsymbol*)p)->macro; 317 318 if (mac) 319 { 320 if (mac->formals) 321 free(mac->formals); 322 free(mac->value); 323 free(mac); 324 } 325 } 326 327 /* 328 * return non-zero if its ok to ppop(op) 329 */ 330 331 static int 332 ppok(int op) 333 { 334 long n; 335 long* r; 336 337 r = &pp.ro_op[op >> 5]; 338 n = 1L << op; 339 if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & n)) 340 { 341 debug((-7, "set op %d index %d skipped -- readonly", op, op >> 5)); 342 return 0; 343 } 344 else if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN))) 345 { 346 *r |= n; 347 debug((-7, "set op %d index %d readonly", op, op >> 5)); 348 } 349 else 350 debug((-7, "set op %d index %d", op, op >> 5)); 351 return 1; 352 } 353 354 /* 355 * pp operations 356 * 357 * NOTE: PP_INIT must be done before the first pplex() call 358 * PP_DONE must be done after the last pplex() call 359 * PP_INIT-PP_DONE must be done for each new PP_INPUT 360 */ 361 362 void 363 ppop(int op, ...) 364 { 365 va_list ap; 366 register char* p; 367 register struct ppkeyword* kp; 368 register char* s; 369 int c; 370 long n; 371 long* r __unused; 372 char* t; 373 struct ppdirs* dp; 374 struct ppdirs* hp; 375 struct ppsymkey* key; 376 struct oplist* xp; 377 Sfio_t* sp; 378 struct stat st; 379 PPCOMMENT ppcomment; 380 PPLINESYNC pplinesync; 381 382 static int initialized; 383 384 va_start(ap, op); 385 switch (op) 386 { 387 case PP_ASSERT: 388 case PP_DEFINE: 389 case PP_DIRECTIVE: 390 case PP_OPTION: 391 case PP_READ: 392 case PP_UNDEF: 393 if (pp.initialized) 394 goto before; 395 if ((p = va_arg(ap, char*)) && *p) 396 { 397 if (pp.lastop) 398 pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0)); 399 else 400 pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0); 401 pp.lastop->op = op; 402 pp.lastop->value = p; 403 } 404 break; 405 case PP_BUILTIN: 406 pp.builtin = va_arg(ap, PPBUILTIN); 407 break; 408 case PP_CDIR: 409 p = va_arg(ap, char*); 410 c = va_arg(ap, int); 411 pp.cdir.path = 0; 412 if (!p) 413 pp.c = c; 414 else if (streq(p, "-")) 415 { 416 pp.c = c; 417 for (dp = pp.firstdir; dp; dp = dp->next) 418 dp->c = c; 419 } 420 else if (!pp.c) 421 { 422 if (!*p || stat((pathcanon(p, 0, 0), p), &st)) 423 pp.c = c; 424 else 425 { 426 for (dp = pp.firstdir; dp; dp = dp->next) 427 { 428 if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st))) 429 pp.c = 1; 430 dp->c = pp.c == 1; 431 } 432 if (!pp.c) 433 { 434 pp.cdir.path = p; 435 SAVEID(&pp.cdir.id, &st); 436 } 437 } 438 } 439 break; 440 case PP_CHOP: 441 if (p = va_arg(ap, char*)) 442 { 443 c = strlen(p); 444 xp = newof(0, struct oplist, 1, c + 1); 445 xp->value = ((char*)xp) + sizeof(struct oplist); 446 s = xp->value; 447 c = *p++; 448 while (*p && *p != c) 449 *s++ = *p++; 450 *s++ = '/'; 451 xp->op = s - xp->value; 452 *s++ = 0; 453 if (*p && *++p && *p != c) 454 { 455 while (*p && *p != c) 456 *s++ = *p++; 457 *s++ = '/'; 458 } 459 *s = 0; 460 xp->next = pp.chop; 461 pp.chop = xp; 462 } 463 break; 464 case PP_COMMENT: 465 if (pp.comment = va_arg(ap, PPCOMMENT)) 466 pp.flags |= PP_comment; 467 else 468 pp.flags &= ~PP_comment; 469 break; 470 case PP_COMPATIBILITY: 471 if (ppset(&pp.state, COMPATIBILITY, va_arg(ap, int))) 472 { 473 #if COMPATIBLE 474 if (pp.initialized) 475 ppfsm(FSM_COMPATIBILITY, NiL); 476 #else 477 if (pp.state & COMPATIBILITY) 478 error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]"); 479 #endif 480 if (pp.state & COMPATIBILITY) 481 pp.flags |= PP_compatibility; 482 else 483 pp.flags &= ~PP_compatibility; 484 } 485 break; 486 case PP_COMPILE: 487 if (pp.initialized) 488 goto before; 489 pp.state |= COMPILE; 490 if (!pp.symtab) 491 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); 492 if (kp = va_arg(ap, struct ppkeyword*)) 493 for (; s = kp->name; kp++) 494 { 495 n = SYM_LEX; 496 switch (*s) 497 { 498 case '-': 499 s++; 500 break; 501 case '+': 502 s++; 503 if (!(pp.option & PLUSPLUS)) 504 break; 505 /*FALLTHROUGH*/ 506 default: 507 n |= SYM_KEYWORD; 508 break; 509 } 510 if (key = ppkeyset(pp.symtab, s)) 511 { 512 key->sym.flags = n; 513 key->lex = kp->value; 514 } 515 } 516 break; 517 case PP_DEBUG: 518 error_info.trace = va_arg(ap, int); 519 break; 520 case PP_DEFAULT: 521 if (p = va_arg(ap, char*)) 522 p = strdup(p); 523 if (pp.ppdefault) 524 free(pp.ppdefault); 525 pp.ppdefault = p; 526 break; 527 case PP_DONE: 528 #if CHECKPOINT 529 if (pp.mode & DUMP) 530 ppdump(); 531 #endif 532 if (pp.mode & FILEDEPS) 533 { 534 sfputc(pp.filedeps.sp, '\n'); 535 if (pp.filedeps.sp == sfstdout) 536 sfsync(pp.filedeps.sp); 537 else 538 sfclose(pp.filedeps.sp); 539 } 540 if (pp.state & STANDALONE) 541 { 542 if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n') 543 ppputchar('\n'); 544 ppflushout(); 545 } 546 error_info.file = 0; 547 break; 548 case PP_DUMP: 549 ppset(&pp.mode, DUMP, va_arg(ap, int)); 550 #if !CHECKPOINT 551 if (pp.mode & DUMP) 552 error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]"); 553 #endif 554 break; 555 case PP_FILEDEPS: 556 if (n = va_arg(ap, int)) 557 pp.filedeps.flags |= n; 558 else 559 pp.filedeps.flags = 0; 560 break; 561 case PP_FILENAME: 562 error_info.file = va_arg(ap, char*); 563 break; 564 case PP_HOSTDIR: 565 if (!(pp.mode & INIT)) 566 pp.ro_mode |= HOSTED; 567 else if (pp.ro_mode & HOSTED) 568 break; 569 pp.ro_mode |= INIT; 570 p = va_arg(ap, char*); 571 c = va_arg(ap, int); 572 pp.hostdir.path = 0; 573 if (!p) 574 pp.hosted = c; 575 else if (streq(p, "-")) 576 { 577 if (pp.initialized) 578 ppset(&pp.mode, HOSTED, c); 579 else 580 { 581 pp.hosted = c ? 1 : 2; 582 for (dp = pp.firstdir; dp; dp = dp->next) 583 if (pp.hosted == 1) 584 dp->type |= TYPE_HOSTED; 585 else 586 dp->type &= ~TYPE_HOSTED; 587 } 588 } 589 else if (!pp.hosted) 590 { 591 if (!*p || stat((pathcanon(p, 0, 0), p), &st)) 592 pp.hosted = 1; 593 else 594 { 595 for (dp = pp.firstdir; dp; dp = dp->next) 596 { 597 if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st))) 598 pp.hosted = 1; 599 if (pp.hosted == 1) 600 dp->type |= TYPE_HOSTED; 601 else 602 dp->type &= ~TYPE_HOSTED; 603 } 604 if (!pp.hosted) 605 { 606 pp.hostdir.path = p; 607 SAVEID(&pp.hostdir.id, &st); 608 } 609 } 610 } 611 break; 612 case PP_ID: 613 p = va_arg(ap, char*); 614 c = va_arg(ap, int); 615 if (p) 616 ppfsm(c ? FSM_IDADD : FSM_IDDEL, p); 617 break; 618 case PP_IGNORE: 619 if (p = va_arg(ap, char*)) 620 { 621 pathcanon(p, 0, 0); 622 ppsetfile(p)->guard = INC_IGNORE; 623 message((-3, "%s: ignore", p)); 624 } 625 break; 626 case PP_IGNORELIST: 627 if (pp.initialized) 628 goto before; 629 pp.ignore = va_arg(ap, char*); 630 break; 631 case PP_INCLUDE: 632 if ((p = va_arg(ap, char*)) && *p) 633 { 634 pathcanon(p, 0, 0); 635 if (stat(p, &st)) 636 break; 637 for (dp = pp.stddirs; dp = dp->next;) 638 if (dp->name && SAMEID(&dp->id, &st)) 639 break; 640 if (pp.cdir.path && SAMEID(&pp.cdir.id, &st)) 641 { 642 pp.cdir.path = 0; 643 pp.c = 1; 644 } 645 if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st)) 646 { 647 pp.hostdir.path = 0; 648 pp.hosted = 1; 649 } 650 if ((pp.mode & INIT) && !(pp.ro_mode & INIT)) 651 pp.hosted = 1; 652 c = dp && dp->c || pp.c == 1; 653 n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1; 654 if (!dp || dp == pp.lastdir->next) 655 { 656 if (dp) 657 { 658 c = dp->c; 659 n = dp->type & TYPE_HOSTED; 660 } 661 dp = newof(0, struct ppdirs, 1, 0); 662 dp->name = p; 663 SAVEID(&dp->id, &st); 664 dp->type |= TYPE_INCLUDE; 665 dp->index = INC_LOCAL + pp.ignoresrc != 0; 666 dp->next = pp.lastdir->next; 667 pp.lastdir = pp.lastdir->next = dp; 668 } 669 dp->c = c; 670 if (n) 671 dp->type |= TYPE_HOSTED; 672 else 673 dp->type &= ~TYPE_HOSTED; 674 } 675 break; 676 case PP_INCREF: 677 pp.incref = va_arg(ap, PPINCREF); 678 break; 679 case PP_RESET: 680 pp.reset.on = 1; 681 break; 682 case PP_INIT: 683 if (pp.initialized) 684 { 685 error_info.errors = 0; 686 error_info.warnings = 0; 687 } 688 else 689 { 690 /* 691 * context initialization 692 */ 693 694 if (!initialized) 695 { 696 /* 697 * out of malloc is fatal 698 */ 699 700 memfatal(); 701 702 /* 703 * initialize the error message interface 704 */ 705 706 error_info.version = (char*)pp.version; 707 #if DEBUG & TRACE_debug 708 error_info.auxilliary = context; 709 pptrace(0); 710 #endif 711 712 /* 713 * initialize pplex tables 714 */ 715 716 ppfsm(FSM_INIT, NiL); 717 718 /* 719 * fixed macro stack size -- room for improvement 720 */ 721 722 pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0); 723 pp.macp->next = pp.macp + 1; 724 pp.maxmac = (char*)pp.macp + DEFMACSTACK; 725 initialized = 1; 726 727 /* 728 * initial include/if control stack 729 */ 730 731 pp.control = newof(0, long, pp.constack, 0); 732 pp.maxcon = pp.control + pp.constack - 1; 733 } 734 735 /* 736 * validate modes 737 */ 738 739 switch (pp.arg_mode) 740 { 741 case 'a': 742 case 'C': 743 ppop(PP_COMPATIBILITY, 0); 744 ppop(PP_TRANSITION, 1); 745 break; 746 case 'A': 747 case 'c': 748 ppop(PP_COMPATIBILITY, 0); 749 ppop(PP_STRICT, 1); 750 break; 751 case 'f': 752 ppop(PP_COMPATIBILITY, 1); 753 ppop(PP_PLUSPLUS, 1); 754 ppop(PP_TRANSITION, 1); 755 break; 756 case 'F': 757 ppop(PP_COMPATIBILITY, 0); 758 ppop(PP_PLUSPLUS, 1); 759 break; 760 case 'k': 761 case 's': 762 ppop(PP_COMPATIBILITY, 1); 763 ppop(PP_STRICT, 1); 764 break; 765 case 'o': 766 case 'O': 767 ppop(PP_COMPATIBILITY, 1); 768 ppop(PP_TRANSITION, 0); 769 break; 770 case 't': 771 ppop(PP_COMPATIBILITY, 1); 772 ppop(PP_TRANSITION, 1); 773 break; 774 } 775 if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu)) 776 ppop(PP_PEDANTIC, 1); 777 if (pp.state & PASSTHROUGH) 778 { 779 if (pp.state & COMPILE) 780 { 781 pp.state &= ~PASSTHROUGH; 782 error(1, "passthrough ignored for compile"); 783 } 784 else 785 { 786 ppop(PP_COMPATIBILITY, 1); 787 ppop(PP_HOSTDIR, "-", 1); 788 ppop(PP_SPACEOUT, 1); 789 ppset(&pp.state, DISABLE, va_arg(ap, int)); 790 } 791 } 792 793 /* 794 * create the hash tables 795 */ 796 797 if (!pp.symtab) 798 pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); 799 if (!pp.dirtab) 800 { 801 pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0); 802 inithash(pp.dirtab, directives); 803 } 804 if (!pp.filtab) 805 pp.filtab = hashalloc(REFALL, HASH_name, "files", 0); 806 if (!pp.prdtab) 807 pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0); 808 if (!pp.strtab) 809 { 810 pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0); 811 inithash(pp.strtab, options); 812 inithash(pp.strtab, predicates); 813 inithash(pp.strtab, variables); 814 } 815 pp.optflags[X_PROTOTYPED] = OPT_GLOBAL; 816 pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS; 817 818 /* 819 * mark macros that are builtin predicates 820 */ 821 822 for (kp = predicates; s = kp->name; kp++) 823 { 824 if (!ppisid(*s)) 825 s++; 826 ppassert(DEFINE, s, 0); 827 } 828 829 /* 830 * the remaining entry names must be allocated 831 */ 832 833 hashset(pp.dirtab, HASH_ALLOCATE); 834 hashset(pp.filtab, HASH_ALLOCATE); 835 hashset(pp.prdtab, HASH_ALLOCATE); 836 hashset(pp.strtab, HASH_ALLOCATE); 837 hashset(pp.symtab, HASH_ALLOCATE); 838 if (pp.test & TEST_nonoise) 839 { 840 c = error_info.trace; 841 error_info.trace = 0; 842 } 843 #if DEBUG 844 if (!(pp.test & TEST_noinit)) 845 { 846 #endif 847 848 /* 849 * compose, push and read the builtin initialization script 850 */ 851 852 if (!(sp = sfstropen())) 853 error(3, "temporary buffer allocation error"); 854 sfprintf(sp, 855 "\ 856 #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\ 857 #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\ 858 ", 859 dirname(PRAGMA), 860 pp.pass, 861 keyname(X_MAP), 862 dirname(DEFINE), 863 dirname(PRAGMA), 864 pp.pass, 865 keyname(X_MAP), 866 dirname(UNDEF)); 867 if (pp.ppdefault && *pp.ppdefault) 868 { 869 if (pp.probe) 870 { 871 c = pp.lastdir->next->type; 872 pp.lastdir->next->type = 0; 873 } 874 if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0) 875 { 876 free(pp.ppdefault); 877 if (!(pp.ppdefault = pathprobe("C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0, pp.path, MAXTOKEN + 1, NiL, 0))) 878 error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE); 879 } 880 if (pp.probe) 881 pp.lastdir->next->type = c; 882 } 883 while (pp.firstop) 884 { 885 switch (pp.firstop->op) 886 { 887 case PP_ASSERT: 888 sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value); 889 break; 890 case PP_DEFINE: 891 if (*pp.firstop->value == '#') 892 sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value); 893 else 894 { 895 if (s = strchr(pp.firstop->value, '=')) 896 sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1); 897 else 898 sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value); 899 } 900 break; 901 case PP_DIRECTIVE: 902 sfprintf(sp, "#%s\n", pp.firstop->value); 903 break; 904 case PP_OPTION: 905 if (s = strchr(pp.firstop->value, '=')) 906 sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1); 907 else 908 sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value); 909 break; 910 case PP_READ: 911 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value); 912 break; 913 case PP_UNDEF: 914 sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value); 915 break; 916 } 917 pp.lastop = pp.firstop; 918 pp.firstop = pp.firstop->next; 919 free(pp.lastop); 920 } 921 sfprintf(sp, 922 "\ 923 #%s %s:%s\n\ 924 #%s %s:%s\n\ 925 #%s !#%s(%s)\n\ 926 #%s !#%s(%s) || #%s(%s)\n\ 927 " 928 , dirname(PRAGMA) 929 , pp.pass 930 , keyname(X_BUILTIN) 931 , dirname(PRAGMA) 932 , pp.pass 933 , keyname(X_PREDEFINED) 934 , dirname(IF) 935 , keyname(X_OPTION) 936 , keyname(X_PLUSPLUS) 937 , dirname(IF) 938 , keyname(X_OPTION) 939 , keyname(X_COMPATIBILITY) 940 , keyname(X_OPTION) 941 , keyname(X_TRANSITION) 942 ); 943 sfprintf(sp, 944 "\ 945 #%s #%s(%s)\n\ 946 #%s %s:%s\n\ 947 #%s %s:%s\n\ 948 #%s __STRICT__ 1\n\ 949 #%s\n\ 950 #%s\n\ 951 " 952 , dirname(IF) 953 , keyname(X_OPTION) 954 , keyname(X_STRICT) 955 , dirname(PRAGMA) 956 , pp.pass 957 , keyname(X_ALLMULTIPLE) 958 , dirname(PRAGMA) 959 , pp.pass 960 , keyname(X_READONLY) 961 , dirname(DEFINE) 962 , dirname(ENDIF) 963 , dirname(ENDIF) 964 ); 965 for (kp = readonlys; s = kp->name; kp++) 966 { 967 if (!ppisid(*s)) 968 s++; 969 sfprintf(sp, "#%s %s\n", dirname(UNDEF), s); 970 } 971 sfprintf(sp, 972 "\ 973 #%s\n\ 974 #%s __STDPP__ 1\n\ 975 #%s %s:no%s\n\ 976 " 977 , dirname(ENDIF) 978 , dirname(DEFINE) 979 , dirname(PRAGMA) 980 , pp.pass 981 , keyname(X_PREDEFINED) 982 ); 983 if (!pp.truncate) 984 sfprintf(sp, 985 "\ 986 #%s __STDPP__directive #(%s)\n\ 987 " 988 , dirname(DEFINE) 989 , keyname(V_DIRECTIVE) 990 ); 991 for (kp = variables; s = kp->name; kp++) 992 if (ppisid(*s) || *s++ == '+') 993 { 994 t = *s == '_' ? "" : "__"; 995 sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s); 996 } 997 sfprintf(sp, 998 "\ 999 #%s %s:no%s\n\ 1000 #%s %s:no%s\n\ 1001 " 1002 , dirname(PRAGMA) 1003 , pp.pass 1004 , keyname(X_READONLY) 1005 , dirname(PRAGMA) 1006 , pp.pass 1007 , keyname(X_BUILTIN) 1008 ); 1009 if (pp.ppdefault && *pp.ppdefault) 1010 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault); 1011 sfprintf(sp, 1012 "\ 1013 #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\ 1014 #%s __STDC__ #(STDC)\n\ 1015 #%s\n\ 1016 " 1017 , dirname(IF) 1018 , dirname(DEFINE) 1019 , dirname(ENDIF) 1020 ); 1021 t = sfstruse(sp); 1022 debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t)); 1023 ppcomment = pp.comment; 1024 pp.comment = 0; 1025 pplinesync = pp.linesync; 1026 pp.linesync = 0; 1027 PUSH_INIT(pp.pass, t); 1028 pp.mode |= INIT; 1029 while (pplex()); 1030 pp.mode &= ~INIT; 1031 pp.comment = ppcomment; 1032 pp.linesync = pplinesync; 1033 pp.prefix = 0; 1034 sfstrclose(sp); 1035 if (error_info.trace) 1036 for (dp = pp.firstdir; dp; dp = dp->next) 1037 message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : "")); 1038 #if DEBUG 1039 } 1040 if (pp.test & TEST_nonoise) 1041 error_info.trace = c; 1042 #endif 1043 { 1044 /* 1045 * this is sleazy but at least it's 1046 * hidden in the library 1047 */ 1048 #include <preroot.h> 1049 #if FS_PREROOT 1050 struct pplist* preroot; 1051 1052 if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot"))) 1053 setpreroot(NiL, preroot->value); 1054 #endif 1055 } 1056 if (pp.ignoresrc) 1057 { 1058 if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir) 1059 error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name); 1060 pp.lcldirs = pp.lcldirs->next; 1061 } 1062 if (pp.ignore) 1063 { 1064 if (*pp.ignore) 1065 ppmapinclude(pp.ignore, NiL); 1066 else 1067 pp.ignore = 0; 1068 } 1069 if (pp.standalone) 1070 pp.state |= STANDALONE; 1071 #if COMPATIBLE 1072 ppfsm(FSM_COMPATIBILITY, NiL); 1073 #endif 1074 ppfsm(FSM_PLUSPLUS, NiL); 1075 pp.initialized = 1; 1076 if (pp.reset.on) 1077 { 1078 pp.reset.symtab = pp.symtab; 1079 pp.symtab = 0; 1080 pp.reset.ro_state = pp.ro_state; 1081 pp.reset.ro_mode = pp.ro_mode; 1082 pp.reset.ro_option = pp.ro_option; 1083 } 1084 } 1085 if (pp.reset.on) 1086 { 1087 if (pp.symtab) 1088 { 1089 hashwalk(pp.filtab, 0, unguard, NiL); 1090 hashfree(pp.symtab); 1091 } 1092 pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0); 1093 hashview(pp.symtab, pp.reset.symtab); 1094 pp.ro_state = pp.reset.ro_state; 1095 pp.ro_mode = pp.reset.ro_mode; 1096 pp.ro_option = pp.reset.ro_option; 1097 } 1098 #if CHECKPOINT 1099 if (pp.mode & DUMP) 1100 { 1101 if (!pp.pragma) 1102 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA)); 1103 (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1); 1104 } 1105 #endif 1106 if (n = pp.filedeps.flags) 1107 { 1108 if (!(n & PP_deps_file)) 1109 { 1110 pp.state |= NOTEXT; 1111 pp.option |= KEEPNOTEXT; 1112 pp.linesync = 0; 1113 } 1114 if (n & PP_deps_generated) 1115 pp.mode |= GENDEPS; 1116 if (n & PP_deps_local) 1117 pp.mode &= ~HEADERDEPS; 1118 else if (!(pp.mode & FILEDEPS)) 1119 pp.mode |= HEADERDEPS; 1120 pp.mode |= FILEDEPS; 1121 } 1122 1123 /* 1124 * push the main input file -- special case for hosted mark 1125 */ 1126 1127 if (pp.firstdir->type & TYPE_HOSTED) 1128 pp.mode |= MARKHOSTED; 1129 else 1130 pp.mode &= ~MARKHOSTED; 1131 #if CHECKPOINT 1132 if (!(pp.mode & DUMP)) 1133 #endif 1134 { 1135 if (!(p = error_info.file)) 1136 p = ""; 1137 else 1138 { 1139 error_info.file = 0; 1140 if (*p) 1141 { 1142 pathcanon(p, 0, 0); 1143 p = ppsetfile(p)->name; 1144 } 1145 } 1146 PUSH_FILE(p, 0); 1147 } 1148 if (pp.mode & FILEDEPS) 1149 { 1150 if (s = strrchr(error_info.file, '/')) 1151 s++; 1152 else 1153 s = error_info.file; 1154 if (!*s) 1155 s = "-"; 1156 s = strcpy(pp.tmpbuf, s); 1157 if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C')) 1158 { 1159 if (c = *++p) 1160 while (*++p == c); 1161 if (*p) 1162 t = 0; 1163 else 1164 t++; 1165 } 1166 if (!t) 1167 { 1168 t = s + strlen(s); 1169 *t++ = '.'; 1170 } 1171 *(t + 1) = 0; 1172 if (pp.state & NOTEXT) 1173 pp.filedeps.sp = sfstdout; 1174 else 1175 { 1176 *t = 'd'; 1177 if (!(pp.filedeps.sp = sfopen(NiL, s, "w"))) 1178 error(ERROR_SYSTEM|3, "%s: cannot create", s); 1179 } 1180 *t = 'o'; 1181 pp.column = sfprintf(pp.filedeps.sp, "%s :", s); 1182 if (*error_info.file) 1183 pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file); 1184 } 1185 if (xp = pp.firsttx) 1186 { 1187 if (!(sp = sfstropen())) 1188 error(3, "temporary buffer allocation error"); 1189 while (xp) 1190 { 1191 sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value); 1192 xp = xp->next; 1193 } 1194 t = sfstruse(sp); 1195 PUSH_BUFFER("options", t, 1); 1196 sfstrclose(sp); 1197 } 1198 break; 1199 case PP_INPUT: 1200 #if CHECKPOINT && POOL 1201 if (!(pp.mode & DUMP) || pp.pool.input) 1202 #else 1203 #if CHECKPOINT 1204 if (!(pp.mode & DUMP)) 1205 #else 1206 #if POOL 1207 if (pp.pool.input) 1208 #endif 1209 #endif 1210 #endif 1211 { 1212 p = va_arg(ap, char*); 1213 if (!error_info.file) 1214 error_info.file = p; 1215 close(0); 1216 if (open(p, O_RDONLY) != 0) 1217 error(ERROR_SYSTEM|3, "%s: cannot read", p); 1218 if (strmatch(p, "*.(s|S|as|AS|asm|ASM)")) 1219 { 1220 ppset(&pp.mode, CATLITERAL, 0); 1221 ppop(PP_SPACEOUT, 1); 1222 } 1223 break; 1224 } 1225 /*FALLTHROUGH*/ 1226 case PP_TEXT: 1227 if (pp.initialized) 1228 goto before; 1229 if ((p = va_arg(ap, char*)) && *p) 1230 { 1231 if (pp.lasttx) 1232 pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0); 1233 else 1234 pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0); 1235 pp.lasttx->op = op; 1236 pp.lasttx->value = p; 1237 } 1238 break; 1239 case PP_KEYARGS: 1240 if (pp.initialized) 1241 goto before; 1242 ppset(&pp.option, KEYARGS, va_arg(ap, int)); 1243 if (pp.option & KEYARGS) 1244 #if MACKEYARGS 1245 ppset(&pp.mode, CATLITERAL, 1); 1246 #else 1247 error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]"); 1248 #endif 1249 break; 1250 case PP_LINE: 1251 if (ppok(op)) 1252 pp.linesync = va_arg(ap, PPLINESYNC); 1253 break; 1254 case PP_LINEBASE: 1255 if (ppok(op)) 1256 { 1257 if (va_arg(ap, int)) 1258 pp.flags |= PP_linebase; 1259 else 1260 pp.flags &= ~PP_linebase; 1261 } 1262 break; 1263 case PP_LINEFILE: 1264 if (ppok(op)) 1265 { 1266 if (va_arg(ap, int)) 1267 pp.flags |= PP_linefile; 1268 else 1269 pp.flags &= ~PP_linefile; 1270 } 1271 break; 1272 case PP_LINEID: 1273 if (ppok(op)) 1274 { 1275 if (!(p = va_arg(ap, char*))) 1276 pp.lineid = ""; 1277 else if (*p != '-') 1278 pp.lineid = strdup(p); 1279 else 1280 pp.option |= IGNORELINE; 1281 } 1282 break; 1283 case PP_LINETYPE: 1284 if (ppok(op)) 1285 { 1286 if ((n = va_arg(ap, int)) >= 1) 1287 pp.flags |= PP_linetype; 1288 else 1289 pp.flags &= ~PP_linetype; 1290 if (n >= 2) 1291 pp.flags |= PP_linehosted; 1292 else 1293 pp.flags &= ~PP_linehosted; 1294 } 1295 break; 1296 case PP_LOCAL: 1297 if (pp.initialized) 1298 goto before; 1299 pp.ignoresrc++; 1300 pp.stddirs = pp.lastdir; 1301 if (!(pp.ro_option & PREFIX)) 1302 pp.option &= ~PREFIX; 1303 break; 1304 case PP_MACREF: 1305 pp.macref = va_arg(ap, PPMACREF); 1306 break; 1307 case PP_MULTIPLE: 1308 ppset(&pp.mode, ALLMULTIPLE, va_arg(ap, int)); 1309 break; 1310 case PP_NOHASH: 1311 ppset(&pp.option, NOHASH, va_arg(ap, int)); 1312 break; 1313 case PP_NOISE: 1314 op = va_arg(ap, int); 1315 ppset(&pp.option, NOISE, op); 1316 ppset(&pp.option, NOISEFILTER, op < 0); 1317 break; 1318 case PP_OPTARG: 1319 pp.optarg = va_arg(ap, PPOPTARG); 1320 break; 1321 case PP_OUTPUT: 1322 pp.outfile = va_arg(ap, char*); 1323 if (identical(pp.outfile, 0)) 1324 error(3, "%s: identical to input", pp.outfile); 1325 close(1); 1326 if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1) 1327 error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile); 1328 break; 1329 case PP_PASSTHROUGH: 1330 if (!(pp.state & COMPILE)) 1331 ppset(&pp.state, PASSTHROUGH, va_arg(ap, int)); 1332 break; 1333 case PP_PEDANTIC: 1334 ppset(&pp.mode, PEDANTIC, va_arg(ap, int)); 1335 break; 1336 case PP_PLUSCOMMENT: 1337 if (ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized) 1338 ppfsm(FSM_PLUSPLUS, NiL); 1339 break; 1340 case PP_PLUSPLUS: 1341 if (ppset(&pp.option, PLUSPLUS, va_arg(ap, int)) && ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized) 1342 ppfsm(FSM_PLUSPLUS, NiL); 1343 break; 1344 case PP_POOL: 1345 if (pp.initialized) 1346 goto before; 1347 if (va_arg(ap, int)) 1348 { 1349 #if POOL 1350 pp.pool.input = dup(0); 1351 pp.pool.output = dup(1); 1352 p = "/dev/null"; 1353 if (!identical(p, 0)) 1354 { 1355 if (!identical(p, 1)) 1356 ppop(PP_OUTPUT, p); 1357 ppop(PP_INPUT, p); 1358 } 1359 #else 1360 error(3, "preprocessor not compiled with input pool enabled [POOL]"); 1361 #endif 1362 } 1363 break; 1364 case PP_PRAGMA: 1365 pp.pragma = va_arg(ap, PPPRAGMA); 1366 break; 1367 case PP_PRAGMAFLAGS: 1368 if (p = va_arg(ap, char*)) 1369 { 1370 n = OPT_GLOBAL; 1371 if (*p == '-') 1372 p++; 1373 else 1374 n |= OPT_PASS; 1375 if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option) 1376 pp.optflags[c] = n; 1377 } 1378 break; 1379 case PP_PROBE: 1380 pp.probe = va_arg(ap, char*); 1381 break; 1382 case PP_QUOTE: 1383 p = va_arg(ap, char*); 1384 c = va_arg(ap, int); 1385 if (p) 1386 ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p); 1387 break; 1388 case PP_REGUARD: 1389 ppset(&pp.option, REGUARD, va_arg(ap, int)); 1390 break; 1391 case PP_RESERVED: 1392 if ((pp.state & COMPILE) && (p = va_arg(ap, char*))) 1393 { 1394 if (!(sp = sfstropen())) 1395 error(3, "temporary buffer allocation error"); 1396 sfputr(sp, p, -1); 1397 p = sfstruse(sp); 1398 if (s = strchr(p, '=')) 1399 *s++ = 0; 1400 else 1401 s = p; 1402 while (*s == '_') 1403 s++; 1404 for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--); 1405 if (*t == '_') 1406 *t = 0; 1407 else 1408 t = 0; 1409 op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE; 1410 if (pp.test & 0x0400) 1411 error(1, "reserved#1 `%s' %d", s, op); 1412 if (t) 1413 *t = '_'; 1414 if (!(key = ppkeyget(pp.symtab, p))) 1415 key = ppkeyset(pp.symtab, NiL); 1416 else if (!(key->sym.flags & SYM_LEX)) 1417 { 1418 struct ppsymbol tmp; 1419 1420 tmp = key->sym; 1421 hashlook(pp.symtab, p, HASH_DELETE, NiL); 1422 key = ppkeyset(pp.symtab, NiL); 1423 key->sym.flags = tmp.flags; 1424 key->sym.macro = tmp.macro; 1425 key->sym.value = tmp.value; 1426 key->sym.hidden = tmp.hidden; 1427 } 1428 if (!(key->sym.flags & SYM_KEYWORD)) 1429 { 1430 key->sym.flags |= SYM_KEYWORD|SYM_LEX; 1431 key->lex = op; 1432 if (pp.test & 0x0400) 1433 error(1, "reserved#2 `%s' %d", p, op); 1434 } 1435 sfstrclose(sp); 1436 } 1437 break; 1438 case PP_SPACEOUT: 1439 ppset(&pp.state, SPACEOUT, va_arg(ap, int)); 1440 break; 1441 case PP_STANDALONE: 1442 if (pp.initialized) 1443 goto before; 1444 pp.standalone = 1; 1445 break; 1446 case PP_STANDARD: 1447 if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st)) 1448 SAVEID(&pp.lastdir->next->id, &st); 1449 for (dp = pp.firstdir; dp; dp = dp->next) 1450 if (dp->name) 1451 for (hp = pp.firstdir; hp != dp; hp = hp->next) 1452 if (hp->name && SAMEID(&hp->id, &dp->id)) 1453 { 1454 hp->c = dp->c; 1455 if (dp->type & TYPE_HOSTED) 1456 hp->type |= TYPE_HOSTED; 1457 else 1458 hp->type &= ~TYPE_HOSTED; 1459 } 1460 break; 1461 case PP_STRICT: 1462 if (ppset(&pp.state, STRICT, va_arg(ap, int))) 1463 { 1464 if (ppset(&pp.state, TRANSITION, 0)) 1465 pp.flags &= ~PP_transition; 1466 if (pp.state & STRICT) 1467 pp.flags |= PP_strict; 1468 else 1469 pp.flags &= ~PP_strict; 1470 } 1471 break; 1472 case PP_TEST: 1473 if (p = va_arg(ap, char*)) 1474 for (;;) 1475 { 1476 while (*p == ' ' || *p == '\t') p++; 1477 for (s = p; n = *s; s++) 1478 if (n == ',' || n == ' ' || n == '\t') 1479 { 1480 *s++ = 0; 1481 break; 1482 } 1483 if (!*p) 1484 break; 1485 n = 0; 1486 if (*p == 'n' && *(p + 1) == 'o') 1487 { 1488 p += 2; 1489 op = 0; 1490 } 1491 else 1492 op = 1; 1493 if (streq(p, "count")) 1494 n = TEST_count; 1495 else if (streq(p, "hashcount")) 1496 n = TEST_hashcount; 1497 else if (streq(p, "hashdump")) 1498 n = TEST_hashdump; 1499 else if (streq(p, "hit")) 1500 n = TEST_hit; 1501 else if (streq(p, "init")) 1502 n = TEST_noinit|TEST_INVERT; 1503 else if (streq(p, "noise")) 1504 n = TEST_nonoise|TEST_INVERT; 1505 else if (streq(p, "proto")) 1506 n = TEST_noproto|TEST_INVERT; 1507 else if (*p >= '0' && *p <= '9') 1508 n = strtoul(p, NiL, 0); 1509 else 1510 { 1511 error(1, "%s: unknown test", p); 1512 break; 1513 } 1514 if (n & TEST_INVERT) 1515 { 1516 n &= ~TEST_INVERT; 1517 op = !op; 1518 } 1519 if (op) 1520 pp.test |= n; 1521 else 1522 pp.test &= ~n; 1523 p = s; 1524 debug((-4, "test = 0%o", pp.test)); 1525 } 1526 break; 1527 case PP_TRANSITION: 1528 if (ppset(&pp.state, TRANSITION, va_arg(ap, int))) 1529 { 1530 if (ppset(&pp.state, STRICT, 0)) 1531 pp.flags &= ~PP_strict; 1532 if (pp.state & TRANSITION) 1533 pp.flags |= PP_transition; 1534 else 1535 pp.flags &= ~PP_transition; 1536 } 1537 break; 1538 case PP_TRUNCATE: 1539 if (pp.initialized) 1540 goto before; 1541 if ((op = va_arg(ap, int)) < 0) 1542 op = 0; 1543 ppset(&pp.option, TRUNCATE, op); 1544 if (pp.option & TRUNCATE) 1545 { 1546 Hash_bucket_t* b; 1547 Hash_bucket_t* p; 1548 Hash_position_t* pos; 1549 Hash_table_t* tab; 1550 1551 pp.truncate = op; 1552 tab = pp.symtab; 1553 pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0); 1554 if (tab && (pos = hashscan(tab, 0))) 1555 { 1556 if (p = hashnext(pos)) 1557 do 1558 { 1559 b = hashnext(pos); 1560 hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL); 1561 } while (p = b); 1562 hashdone(pos); 1563 } 1564 } 1565 else 1566 pp.truncate = 0; 1567 break; 1568 case PP_VENDOR: 1569 p = va_arg(ap, char*); 1570 c = va_arg(ap, int) != 0; 1571 if (!p || !*p) 1572 for (dp = pp.firstdir; dp; dp = dp->next) 1573 dp->type &= ~TYPE_VENDOR; 1574 else if (streq(p, "-")) 1575 { 1576 for (dp = pp.firstdir; dp; dp = dp->next) 1577 if (c) 1578 dp->type |= TYPE_VENDOR; 1579 else 1580 dp->type &= ~TYPE_VENDOR; 1581 } 1582 else if (!stat((pathcanon(p, 0, 0), p), &st)) 1583 { 1584 c = 0; 1585 for (dp = pp.firstdir; dp; dp = dp->next) 1586 { 1587 if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st))) 1588 c = 1; 1589 if (c) 1590 dp->type |= TYPE_VENDOR; 1591 else 1592 dp->type &= ~TYPE_VENDOR; 1593 } 1594 } 1595 break; 1596 case PP_WARN: 1597 ppset(&pp.state, WARN, va_arg(ap, int)); 1598 break; 1599 before: 1600 error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op); 1601 break; 1602 default: 1603 error(3, "ppop(%d): invalid preprocessor operation", op); 1604 break; 1605 } 1606 va_end(ap); 1607 } 1608