|
|
1.1 ! root 1: /* C Compatible Compiler Preprocessor (CCCP) ! 2: Copyright (C) 1986, Free Software Foundation, Inc. ! 3: Written by Paul Rubin, June 1986 ! 4: ! 5: NO WARRANTY ! 6: ! 7: BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY ! 8: NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT ! 9: WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, ! 10: RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" ! 11: WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, ! 12: BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ! 13: FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY ! 14: AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE ! 15: DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR ! 16: CORRECTION. ! 17: ! 18: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. ! 19: STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY ! 20: WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE ! 21: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR ! 22: OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE ! 23: USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR ! 24: DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR ! 25: A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS ! 26: PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH ! 27: DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. ! 28: ! 29: GENERAL PUBLIC LICENSE TO COPY ! 30: ! 31: 1. You may copy and distribute verbatim copies of this source file ! 32: as you receive it, in any medium, provided that you conspicuously ! 33: and appropriately publish on each copy a valid copyright notice ! 34: "Copyright (C) 1986 Free Software Foundation"; and include ! 35: following the copyright notice a verbatim copy of the above disclaimer ! 36: of warranty and of this License. ! 37: ! 38: 2. You may modify your copy or copies of this source file or ! 39: any portion of it, and copy and distribute such modifications under ! 40: the terms of Paragraph 1 above, provided that you also do the following: ! 41: ! 42: a) cause the modified files to carry prominent notices stating ! 43: that you changed the files and the date of any change; and ! 44: ! 45: b) cause the whole of any work that you distribute or publish, ! 46: that in whole or in part contains or is a derivative of this ! 47: program or any part thereof, to be licensed at no charge to all ! 48: third parties on terms identical to those contained in this ! 49: License Agreement (except that you may choose to grant more extensive ! 50: warranty protection to some or all third parties, at your option). ! 51: ! 52: c) You may charge a distribution fee for the physical act of ! 53: transferring a copy, and you may at your option offer warranty ! 54: protection in exchange for a fee. ! 55: ! 56: Mere aggregation of another unrelated program with this program (or its ! 57: derivative) on a volume of a storage or distribution medium does not bring ! 58: the other program under the scope of these terms. ! 59: ! 60: 3. You may copy and distribute this program (or a portion or derivative ! 61: of it, under Paragraph 2) in object code or executable form under the terms ! 62: of Paragraphs 1 and 2 above provided that you also do one of the following: ! 63: ! 64: a) accompany it with the complete corresponding machine-readable ! 65: source code, which must be distributed under the terms of ! 66: Paragraphs 1 and 2 above; or, ! 67: ! 68: b) accompany it with a written offer, valid for at least three ! 69: years, to give any third party free (except for a nominal ! 70: shipping charge) a complete machine-readable copy of the ! 71: corresponding source code, to be distributed under the terms of ! 72: Paragraphs 1 and 2 above; or, ! 73: ! 74: c) accompany it with the information you received as to where the ! 75: corresponding source code may be obtained. (This alternative is ! 76: allowed only for noncommercial distribution and only if you ! 77: received the program in object code or executable form alone.) ! 78: ! 79: For an executable file, complete source code means all the source code for ! 80: all modules it contains; but, as a special exception, it need not include ! 81: source code for modules which are standard libraries that accompany the ! 82: operating system on which the executable file runs. ! 83: ! 84: 4. You may not copy, sublicense, distribute or transfer this program ! 85: except as expressly provided under this License Agreement. Any attempt ! 86: otherwise to copy, sublicense, distribute or transfer this program is void and ! 87: your rights to use the program under this License agreement shall be ! 88: automatically terminated. However, parties who have received computer ! 89: software programs from you with this License Agreement will not have ! 90: their licenses terminated so long as such parties remain in full compliance. ! 91: ! 92: In other words, you are welcome to use, share and improve this program. ! 93: You are forbidden to forbid anyone else to use, share and improve ! 94: what you give them. Help stamp out software-hoarding! */ ! 95: ! 96: typedef unsigned char U_CHAR; ! 97: ! 98: #ifdef EMACS ! 99: #define NO_SHORTNAMES ! 100: #include "../src/config.h" ! 101: #ifdef static ! 102: #undef static ! 103: #endif ! 104: #ifdef open ! 105: #undef open ! 106: #undef close ! 107: #undef read ! 108: #undef write ! 109: #endif /* open */ ! 110: #endif /* EMACS */ ! 111: ! 112: #include <sys/types.h> ! 113: #include <sys/stat.h> ! 114: #include <sys/file.h> ! 115: #include <ctype.h> ! 116: #include <stdio.h> ! 117: #ifndef USG ! 118: #include <sys/time.h> /* for __DATE__ and __TIME__ */ ! 119: #else ! 120: #define index strchr ! 121: #define rindex strrchr ! 122: #include <time.h> ! 123: #include <fcntl.h> ! 124: #endif /* USG */ ! 125: ! 126: void bcopy (), bzero (); ! 127: int bcmp (); ! 128: ! 129: char *xmalloc (), *xrealloc (), *xcalloc (); ! 130: void fatal (), pfatal_with_name (), perror_with_name (); ! 131: ! 132: char *progname; ! 133: ! 134: #define FATAL_EXIT_CODE 33 /* gnu cc command understands this */ ! 135: ! 136: struct directory_stack ! 137: { ! 138: struct directory_stack *next; ! 139: char *fname; ! 140: }; ! 141: ! 142: /* #include "file" starts with the first entry in the stack */ ! 143: /* #include <file> starts with the second. */ ! 144: /* -I directories are added after the first */ ! 145: struct directory_stack default_includes[2] = ! 146: { ! 147: { &default_includes[1], "." }, ! 148: { 0, "/usr/include" } ! 149: }; ! 150: struct directory_stack *include = &default_includes[0]; ! 151: ! 152: int max_include_len = 14; /* strlen (default_include) + 2 ! 153: (for / and null) */ ! 154: ! 155: char STDIN_FILE[] = ""; /* Empty, like real cpp */ ! 156: int put_out_comments = 0; /* JF non-zero means leave comments in the ! 157: output file. Used by lint */ ! 158: ! 159: /* table to tell if char can be part of a C identifier. */ ! 160: U_CHAR is_idchar[256]; ! 161: /* table to tell if char can be first char of a c identifier. */ ! 162: U_CHAR is_idstart[256]; ! 163: /* table to tell if c is horizontal space. isspace() thinks that ! 164: newline is space; this is not a good idea for this program. */ ! 165: U_CHAR is_hor_space[256]; ! 166: ! 167: /* I/O buffer structure. Ought to be used for the output file too. ! 168: These are also used when there is no file present, for example, ! 169: when rescanning a definition. Then, the fname field is null. */ ! 170: #define INPUT_STACK_MAX 100 ! 171: struct file_buf { ! 172: struct infile *next; /* for making stacks of file ptrs */ ! 173: char *fname; ! 174: int lineno; ! 175: int length; ! 176: U_CHAR *buf; ! 177: U_CHAR *bufp; ! 178: } instack[INPUT_STACK_MAX]; ! 179: int indepth = 0; ! 180: ! 181: typedef struct file_buf FILE_BUF; ! 182: ! 183: /* The output buffer. Its LENGTH field is the amount of room allocated ! 184: for the buffer, not the number of chars actually present. To get ! 185: that, subtract outbuf.buf from outbuf.bufp. */ ! 186: ! 187: #define OUTBUF_SIZE 10 /* initial size of output buffer */ ! 188: FILE_BUF outbuf; ! 189: ! 190: /* Structure allocated for every #define. For a simple replacement ! 191: such as ! 192: #define foo bar , ! 193: nargs = -1, the `pattern' list is null, and the expansion is just ! 194: the replacement text. Nargs = 0 means a real macro with no args, ! 195: e.g., ! 196: #define getchar() getc(stdin) . ! 197: When there are args, the expansion is the replacement text with the ! 198: args squashed out, and the reflist is a list describing how to ! 199: build the output from the input: e.g., "3 chars, then the 1st arg, ! 200: then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". ! 201: The chars here come from the expansion. Thus, for any definition ! 202: d , strlen(d->expansion) should equal the sum of all the ! 203: d->pattern->nchars. Note that the list can be arbitrarily long--- ! 204: its length depends on the number of times the arguements appear in ! 205: the replacement text, not how many args there are. Example: ! 206: #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and ! 207: pattern list ! 208: { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } ! 209: where (x, y) means (nchars, argno). */ ! 210: ! 211: typedef struct definition DEFINITION; ! 212: struct definition { ! 213: int nargs; ! 214: int length; /* length of expansion string */ ! 215: U_CHAR *expansion; ! 216: struct reflist { ! 217: struct reflist *next; ! 218: int nchars; ! 219: int argno; ! 220: } *pattern; ! 221: }; ! 222: ! 223: /* different kinds of things that can appear in the value field ! 224: of a hash node. Actually, this may be useless now. */ ! 225: union hashval { ! 226: int ival; ! 227: char *cpval; ! 228: DEFINITION *defn; ! 229: }; ! 230: ! 231: ! 232: /* The structure of a node in the hash table. The hash table ! 233: has entries for all tokens defined by #define commands (type T_MACRO), ! 234: plus some special tokens like __LINE__ (these each have their own ! 235: type, and the appropriate code is run when that type of node is seen. ! 236: It does not contain control words like "#define", which are recognized ! 237: by a separate piece of code. */ ! 238: typedef struct hashnode HASHNODE; ! 239: struct hashnode { ! 240: HASHNODE *next; /* double links for easy deletion */ ! 241: HASHNODE *prev; ! 242: HASHNODE **bucket_hdr; /* also, a back pointer to this node's hash ! 243: chain is kept, in case the node is the head ! 244: of the chain and gets deleted. */ ! 245: int type; /* type of special token */ ! 246: int length; /* length of token, for quick comparison */ ! 247: U_CHAR *name; /* the actual name */ ! 248: union hashval value; /* pointer to expansion, or whatever */ ! 249: }; ! 250: ! 251: ! 252: HASHNODE *install(); ! 253: /* different flavors of hash nodes --- also used in keyword table */ ! 254: #define T_DEFINE 1 /* the "#define" keyword */ ! 255: #define T_INCLUDE 2 /* the "#include" keyword */ ! 256: #define T_IFDEF 3 /* the "#ifdef" keyword */ ! 257: #define T_IF 4 /* the "#if" keyword */ ! 258: #define T_EXPAND 5 /* argument to be expanded (now unused) */ ! 259: #define T_MACRO 6 /* macro defined by "#define" */ ! 260: #define T_ELSE 7 /* "#else" */ ! 261: #define T_PRAGMA 8 /* "#pragma" */ ! 262: #define T_ELIF 9 /* "#else" */ ! 263: #define T_UNDEF 10 /* "#undef" */ ! 264: #define T_LINE 11 /* "#line" */ ! 265: #define T_ERROR 12 /* "#error" */ ! 266: #define T_IFNDEF 13 /* "#ifndef"; forgot this earlier */ ! 267: #define T_ENDIF 14 /* "#endif" */ ! 268: #define T_SPECLINE 15 /* special symbol "__LINE__" */ ! 269: #define T_DATE 16 /* "__DATE__" */ ! 270: #define T_FILE 17 /* "__FILE__" */ ! 271: #define T_TIME 18 /* "__TIME__" */ ! 272: ! 273: #define T_SPEC_DEFINED 19 /* special macro for use in #if statements */ ! 274: ! 275: ! 276: ! 277: /* some more different types will be needed --- no longer bloody likely */ ! 278: ! 279: ! 280: int do_define(), do_line(), do_include(), do_undef(), do_error(), ! 281: do_pragma(), do_if(), do_xifdef(), do_else(), ! 282: do_elif(), do_endif(); ! 283: ! 284: ! 285: /* table of control words, along with code to execute when the keyword ! 286: is seen. For now, it is searched linearly, so put the most frequently ! 287: found keywords at the beginning of the list. */ ! 288: ! 289: struct keyword_table { ! 290: int length; ! 291: int (*func)(); ! 292: char *name; ! 293: int type; ! 294: } keyword_table[] = { ! 295: { 6, do_define, "define", T_DEFINE}, ! 296: { 4, do_line, "line", T_LINE}, ! 297: { 7, do_include, "include", T_INCLUDE}, ! 298: { 5, do_undef, "undef", T_UNDEF}, ! 299: { 5, do_error, "error", T_ERROR}, ! 300: { 2, do_if, "if", T_IF}, ! 301: { 5, do_xifdef, "ifdef", T_IFDEF}, ! 302: { 6, do_xifdef, "ifndef", T_IFNDEF}, ! 303: { 4, do_else, "else", T_ELSE}, ! 304: { 4, do_elif, "elif", T_ELIF}, ! 305: { 5, do_endif, "endif", T_ENDIF}, ! 306: { 6, do_pragma, "pragma", T_PRAGMA}, ! 307: { -1, 0, "", -1}, ! 308: }; ! 309: ! 310: /* Some definitions for the hash table. The hash function MUST be ! 311: computed as shown in hashf() below. That is because the rescan ! 312: loop computes the hash value `on the fly' for most tokens, ! 313: in order to avoid the overhead of a lot of procedure calls to ! 314: the hashf() function. Hashf() only exists for the sake of ! 315: politeness, for use when speed isn't so important. */ ! 316: ! 317: #define HASHSIZE 1009 ! 318: HASHNODE *hashtab[HASHSIZE]; ! 319: #define HASHSTEP(old, c) ((old << 1) + c) ! 320: #define MAKE_POS(v) (v & ~0x80000000) /* make number positive */ ! 321: ! 322: #define SKIP_WHITE_SPACE(p) { while (is_hor_space[*p]) p++; } ! 323: ! 324: ! 325: ! 326: main (argc, argv) ! 327: int argc; ! 328: char **argv; ! 329: { ! 330: struct stat sbuf; ! 331: char *in_fname, *out_fname; ! 332: int out_fd = 1; /* default to stdout */ ! 333: int f, i; ! 334: FILE_BUF *fp; ! 335: ! 336: progname = argv[0]; ! 337: in_fname = NULL; ! 338: out_fname = NULL; ! 339: initialize_random_junk (); ! 340: ! 341: fp = &instack[indepth++]; ! 342: ! 343: /* if (argc < 2) JF no args means work as filter ! 344: return FATAL_EXIT_CODE; */ ! 345: ! 346: for (i = 1; i < argc; i++) { ! 347: if (argv[i][0] != '-') { ! 348: if (out_fname != NULL) ! 349: fatal ("Usage: %s [switches] input output\n", argv[0]); ! 350: else if (in_fname != NULL) { ! 351: out_fname = argv[i]; ! 352: if ((out_fd = creat (out_fname, 0666)) < 0) ! 353: pfatal_with_name (out_fname); ! 354: } else ! 355: in_fname = argv[i]; ! 356: } else { ! 357: switch (argv[i][1]) { ! 358: U_CHAR *p; ! 359: struct directory_stack *dirtmp; ! 360: case 'D': ! 361: if ((p = (U_CHAR *) index(argv[i]+2, '=')) != NULL) ! 362: *p = ' '; ! 363: make_definition (argv[i] + 2); ! 364: break; ! 365: case 'U': /* JF #undef something */ ! 366: make_undef(argv[i] + 2); ! 367: break; ! 368: case 'C': /* JF do later -C means leave comments alone! */ ! 369: put_out_comments++; ! 370: break; ! 371: case 'E': /* -E comes from cc -E; ignore it. */ ! 372: break; ! 373: case 'M': /* Makefile dependencies or something like ! 374: that. Not implimented yet */ ! 375: break; ! 376: case 'I': /* JF handle directory path right */ ! 377: dirtmp = (struct directory_stack *) ! 378: xmalloc (sizeof (struct directory_stack)); ! 379: dirtmp->next = include->next; ! 380: include->next = dirtmp; ! 381: dirtmp->fname = argv[i]+2; ! 382: include = dirtmp; ! 383: if (strlen (argv[i]) > max_include_len) ! 384: max_include_len = strlen (argv[i]); ! 385: break; ! 386: ! 387: case '\0': /* JF handle '-' as file name meaning stdin or stdout */ ! 388: if (in_fname == NULL) { ! 389: in_fname = STDIN_FILE; ! 390: break; ! 391: } else if (out_fname == NULL) { ! 392: out_fname = "stdout"; ! 393: break; ! 394: } /* else fall through into error */ ! 395: ! 396: default: ! 397: fatal ("Illegal option %s\n", argv[i]); ! 398: } ! 399: } ! 400: } ! 401: ! 402: /* JF check for stdin */ ! 403: if (in_fname == STDIN_FILE || in_fname == NULL) ! 404: f = 0; ! 405: else if ((f = open (in_fname, O_RDONLY)) < 0) ! 406: goto perror; ! 407: ! 408: fstat (f, &sbuf); ! 409: fp->fname = in_fname; ! 410: fp->lineno = 1; ! 411: /* JF all this is mine about reading pipes and ttys */ ! 412: if ((sbuf.st_mode & S_IFMT) != S_IFREG) { ! 413: int size; ! 414: int bsize; ! 415: int cnt; ! 416: U_CHAR *bufp; ! 417: ! 418: bsize = 2000; ! 419: size = 0; ! 420: fp->buf = (U_CHAR *) xmalloc (bsize + 1); ! 421: bufp = fp->buf; ! 422: for (;;) { ! 423: cnt = read (f, bufp, bsize - size); ! 424: if (cnt < 0) goto perror; /* error! */ ! 425: if (cnt == 0) break; /* End of file */ ! 426: size += cnt; ! 427: bufp += cnt; ! 428: if (bsize-size == 0) { /* Buffer is full! */ ! 429: bsize *= 2; ! 430: fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 1); ! 431: bufp = fp->buf + size; /* May have moved */ ! 432: } ! 433: } ! 434: fp->buf[size] = '\0'; ! 435: fp->length = size; ! 436: } else { ! 437: fp->length = sbuf.st_size; ! 438: fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1); ! 439: ! 440: if (read (f, fp->buf, sbuf.st_size) != sbuf.st_size) ! 441: goto perror; ! 442: ! 443: fp->buf[sbuf.st_size] = '\0'; ! 444: } ! 445: ! 446: /* initialize output buffer */ ! 447: outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE); ! 448: outbuf.bufp = outbuf.buf; ! 449: outbuf.length = OUTBUF_SIZE; ! 450: ! 451: output_line_command (fp, &outbuf); ! 452: rescan (fp, &outbuf); ! 453: ! 454: /* do something different than this later */ ! 455: fflush (stdout); ! 456: write (out_fd, outbuf.buf, outbuf.bufp - outbuf.buf); ! 457: exit (0); ! 458: ! 459: perror: ! 460: pfatal_with_name (argv[1]); ! 461: } ! 462: ! 463: /* ! 464: * The main loop of the program. Try to examine and move past most ! 465: * ordinary input chars as fast as possible. Call appropriate routines ! 466: * when something special (such as a macro expansion) has to happen. ! 467: ! 468: IP is the source of input to scan. ! 469: OP is the place to put input. */ ! 470: ! 471: rescan (ip, op) ! 472: FILE_BUF *ip, *op; ! 473: { ! 474: register int c; ! 475: register int ident_length = 0, hash = 0; ! 476: register U_CHAR *limit; ! 477: U_CHAR *check_expand (); ! 478: struct keyword_table *handle_directive (); ! 479: int excess_newlines = 0; ! 480: int escaped = 0; ! 481: ! 482: U_CHAR *bp; ! 483: ! 484: check_expand(op, ip->length); ! 485: ! 486: ip->bufp = ip->buf; ! 487: limit = ip->buf + ip->length; ! 488: while (1) { ! 489: if (ip->bufp < limit) { ! 490: c = *ip->bufp++; ! 491: *op->bufp++ = c; ! 492: } else { ! 493: c = -1; ! 494: } ! 495: ! 496: --escaped; ! 497: /* Now ESCAPED is 0 if and only if this character is escaped. */ ! 498: ! 499: switch (c) { ! 500: case '\\': ! 501: if (escaped == 0) ! 502: goto randomchar; ! 503: if (*ip->bufp != '\n') ! 504: { ! 505: escaped = 1; ! 506: goto randomchar; ! 507: } ! 508: /* always merge lines ending with backslash-newline */ ! 509: ++ip->bufp; ! 510: ++ip->lineno; ! 511: ++excess_newlines; ! 512: --op->bufp; /* remove backslash from obuf */ ! 513: continue; /* back to top of while loop */ ! 514: ! 515: case '#': ! 516: /* # keyword: a # must be first nonblank char on the line */ ! 517: for (bp = ip->bufp - 1; bp >= ip->buf; bp--) ! 518: if (*bp == '\n') ! 519: break; ! 520: bp++; /* skip nl or move back into buffer */ ! 521: SKIP_WHITE_SPACE (bp); ! 522: if (*bp != '#') ! 523: goto randomchar; ! 524: ident_length = hash = 0; ! 525: --op->bufp; /* don't copy the '#' */ ! 526: ! 527: if (handle_directive (ip, op, &excess_newlines) == NULL) { ! 528: ++op->bufp; /* copy the '#' after all */ ! 529: goto randomchar; ! 530: } ! 531: break; ! 532: ! 533: case '\"': /* skip quoted string */ ! 534: case '\'': ! 535: /* a single quoted string is treated like a double -- some ! 536: programs (e.g., troff) are perverse this way */ ! 537: ! 538: if (escaped == 0) ! 539: goto randomchar; /* false alarm-- it's escaped. */ ! 540: ! 541: /* skip ahead to a matching quote. */ ! 542: ! 543: bp = ip->bufp; ! 544: while (bp < limit) { ! 545: *op->bufp++ = *bp; ! 546: switch (*bp++) { ! 547: case '\n': ! 548: ++ip->lineno; ! 549: break; ! 550: case '\\': ! 551: if (bp >= limit) ! 552: break; ! 553: if (*bp == '\n') ! 554: { ! 555: /* backslash newline is replaced by nothing at all, ! 556: but remember that the source line count is out of synch. */ ! 557: --op->bufp; ! 558: ++bp; ! 559: ++excess_newlines; ! 560: ++ip->lineno; ! 561: } ! 562: else ! 563: *op->bufp++ = *bp++; ! 564: break; ! 565: case '\"': ! 566: case '\'': ! 567: if (bp[-1] == c) ! 568: goto while2end; ! 569: break; ! 570: } ! 571: } ! 572: while2end: ! 573: ip->bufp = bp; ! 574: break; ! 575: ! 576: case '/': /* possible comment */ ! 577: if (*ip->bufp != '*') ! 578: goto randomchar; ! 579: if (put_out_comments) { ! 580: bp = ip->bufp; ! 581: *op->bufp++ = *bp++; ! 582: } else { ! 583: bp = ip->bufp + 1; ! 584: --op->bufp; /* don't leave initial slash in buffer */ ! 585: } ! 586: ! 587: for (;;) { ! 588: while (bp < limit) { ! 589: if (put_out_comments) ! 590: *op->bufp++ = *bp; ! 591: switch (*bp++) { ! 592: case '*': ! 593: goto whileend; ! 594: case '\n': ! 595: /* copy the newline into the output buffer, in order to ! 596: avoid the pain of a #line every time a multiline comment ! 597: is seen. This means keywords with embedded comments ! 598: that contain newlines (blucch!) will lose. By making ! 599: sure that excess_newlines is not just a flag, but really ! 600: an accurate count, it might be possible to get around this. */ ! 601: if (!put_out_comments) ! 602: *op->bufp++ = '\n'; ! 603: ++ip->lineno; ! 604: } ! 605: } ! 606: whileend: ! 607: if (bp >= limit) { ! 608: error ("unterminated comment"); ! 609: break; /* causes eof condition */ ! 610: } ! 611: if (*bp == '/') ! 612: break; ! 613: } ! 614: if (put_out_comments) ! 615: *op->bufp++ = '/'; ! 616: ip->bufp = bp + 1; ! 617: break; ! 618: ! 619: case '0': case '1': case '2': case '3': case '4': ! 620: case '5': case '6': case '7': case '8': case '9': ! 621: /* if digit is not part of identifier, it is random */ ! 622: if (ident_length == 0) ! 623: goto randomchar; ! 624: /* fall through */ ! 625: ! 626: case '_': ! 627: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': ! 628: case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': ! 629: case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': ! 630: case 's': case 't': case 'u': case 'v': case 'w': case 'x': ! 631: case 'y': case 'z': ! 632: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ! 633: case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': ! 634: case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': ! 635: case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': ! 636: case 'Y': case 'Z': ! 637: ident_length++; ! 638: /* compute step of hash function, to avoid a proc call on every token */ ! 639: hash = HASHSTEP(hash, c); ! 640: break; ! 641: ! 642: default: ! 643: randomchar: ! 644: if (ident_length > 0) { ! 645: register HASHNODE *hp; ! 646: for (hp = hashtab[MAKE_POS(hash) % HASHSIZE]; hp != NULL; ! 647: hp = hp->next) { ! 648: U_CHAR *save_ibufp; /* kludge, see below */ ! 649: ! 650: if (hp->length == ident_length) { ! 651: register int i = ident_length; ! 652: register U_CHAR *p = hp->name; ! 653: register U_CHAR *q = op->bufp - i; ! 654: ! 655: if (c != (U_CHAR) -1) ! 656: q--; ! 657: ! 658: do { /* all this to avoid a strncmp() */ ! 659: if (*p++ != *q++) ! 660: goto hashcollision; ! 661: } while (--i); ! 662: ! 663: save_ibufp = ip->bufp; ! 664: /* back up over identifier, then expand token */ ! 665: op->bufp -= ident_length; ! 666: if (c != (U_CHAR) -1) op->bufp--; ! 667: macroexpand (hp, ip, op, &excess_newlines); ! 668: ! 669: check_expand(op, ip->length - (ip->bufp - ip->buf)); ! 670: ! 671: /* If we just processed an identifier at end of input, ! 672: return right away. */ ! 673: if (c == (U_CHAR) -1) ! 674: return; ! 675: ! 676: /* if the expansion routine has not moved the input ! 677: pointer, put back the char that ended the token. ! 678: This is a kludge because there might be a different ! 679: reason to put it back or not put it back. */ ! 680: if (ip->bufp == save_ibufp) ! 681: *op->bufp++ = c; ! 682: ! 683: break; /* out of for loop */ ! 684: } ! 685: hashcollision: ! 686: ; ! 687: } /* end for loop */ ! 688: ident_length = hash = 0; /* stop collecting identifier */ ! 689: } ! 690: ! 691: /* If we just processed an identifier at end of input, ! 692: return right away. */ ! 693: if (c == -1) ! 694: return; ! 695: ! 696: /* count the newline, if it was one. The reason this is ! 697: done down here instead of as a case in the switch is ! 698: that some expansions might want to look at the line ! 699: number, and if they happen right before the newline, ! 700: we don't want them to get the wrong one. So the newline ! 701: must be counted AFTER any expansions happen. */ ! 702: if (c == '\n') { ! 703: ++ip->lineno; ! 704: if (excess_newlines > 0) { ! 705: output_line_command (ip, op); ! 706: check_expand(op, ip->length - (ip->bufp - ip->buf)); ! 707: ! 708: excess_newlines = 0; ! 709: } ! 710: } ! 711: break; /* from switch */ ! 712: } ! 713: } ! 714: } ! 715: ! 716: /* ! 717: * Process a # directive. Expects ip->bufp to point to the '#', as in ! 718: * "#define foo bar". Bumps *excess_newlines counter as necessary if ! 719: * the command is several lines long (and also updates ip->lineno). ! 720: * The main reason for this is that the comments could contain ! 721: * newlines, which would be confusing. Passes to the command handler ! 722: * (do_define, do_include, etc.): the addresses of the 1st and ! 723: * last chars of the command (starting immediately after the # ! 724: * keyword), plus op and the keyword table pointer. If the line ! 725: * contains comments the command is copied into a temporary buffer ! 726: * (sans comments) and the temporary buffer is passed to the command ! 727: * handler instead. ! 728: */ ! 729: ! 730: struct keyword_table * ! 731: handle_directive (ip, op, excess_newlines) ! 732: FILE_BUF *ip, *op; ! 733: int *excess_newlines; ! 734: { ! 735: register U_CHAR *bp, *cp; ! 736: register struct keyword_table *kt; ! 737: register int ident_length; ! 738: ! 739: /* Nonzero means we must copy the entire command ! 740: to get rid of comments or backslash-newlines. */ ! 741: int copy_command = 0; ! 742: ! 743: bp = ip->bufp; ! 744: SKIP_WHITE_SPACE(bp); ! 745: cp = bp; ! 746: while (is_idchar[*cp]) ! 747: cp++; ! 748: ident_length = cp - bp; ! 749: ! 750: /* ! 751: * Decode the keyword and call the appropriate expansion ! 752: * routine, after moving the input pointer up to the next line. ! 753: * If the keyword is not a legitimate control word, return NULL. ! 754: * Otherwise, return ptr to the keyword structure matched. ! 755: */ ! 756: for (kt = keyword_table; kt->length > 0; kt++) { ! 757: if (kt->length == ident_length && !strncmp(kt->name, bp, ident_length)) { ! 758: register U_CHAR *buf; ! 759: register U_CHAR *limit = ip->buf + ip->length; ! 760: U_CHAR *skip_to_end_of_comment(); ! 761: ! 762: buf = bp = bp + ident_length; ! 763: while (bp < limit) { ! 764: if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */ ! 765: U_CHAR quotec; ! 766: ! 767: for (quotec = *bp++; bp < limit && *bp != quotec; bp++) { ! 768: if (*bp == '\\') bp++; ! 769: if (*bp == '\n') { ! 770: if (bp[-1] == '\\') ! 771: copy_command++; ! 772: else { ! 773: /* --bp; */ ! 774: break; /* JF ugly, but might work */ ! 775: } ! 776: } ! 777: } ! 778: continue; ! 779: } ! 780: if (*bp == '/' && bp[1] == '*') { ! 781: copy_command++; ! 782: ip->bufp = bp + 2; ! 783: skip_to_end_of_comment (ip, NULL); ! 784: bp = ip->bufp; ! 785: continue; ! 786: } ! 787: ! 788: if (*bp++ == '\n') { ! 789: if (*(bp-2) == '\\') ! 790: copy_command++; ! 791: else { ! 792: --bp; /* point to the newline */ ! 793: break; ! 794: } ! 795: } ! 796: } ! 797: if (copy_command) { ! 798: /* need to copy entire command into temp buffer before dispatching */ ! 799: ! 800: cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus ! 801: some slop */ ! 802: bp = buf; ! 803: buf = cp; ! 804: ! 805: while (bp < limit) { ! 806: if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */ ! 807: U_CHAR quotec; ! 808: ! 809: *cp++ = *bp; ! 810: for (quotec = *bp++; bp < limit && *bp != quotec; *cp++ = *bp++) { ! 811: if (*bp == '\\') ! 812: *cp++ = *bp++; ! 813: if (*bp == '\n') { ! 814: if (bp[-1] == '\\') { ! 815: ++ip->lineno; ! 816: ++*excess_newlines; ! 817: } else break; /* JF ugly, but might work */ ! 818: } ! 819: } ! 820: continue; ! 821: } ! 822: if (*bp == '/' && bp[1] == '*') { ! 823: int newlines_found = 0; ! 824: ip->bufp = bp + 2; ! 825: skip_to_end_of_comment (ip, &newlines_found); ! 826: *excess_newlines += newlines_found; ! 827: ip->lineno += newlines_found; ! 828: bp = ip->bufp; ! 829: continue; ! 830: } ! 831: ! 832: if (*bp == '\n') { ! 833: if (bp[-1] == '\\') { ! 834: ++ip->lineno; ! 835: ++*excess_newlines; ! 836: } else ! 837: break; ! 838: } ! 839: *cp++ = *bp++; ! 840: } ! 841: } ! 842: else ! 843: cp = bp; ! 844: ! 845: ip->bufp = bp; /* skip to the end of the command */ ! 846: ! 847: /* call the appropriate command handler. Buf now points to ! 848: either the appropriate place in the input buffer, or to ! 849: the temp buffer if it was necessary to make one. Cp ! 850: points to the first char after the contents of the (possibly ! 851: copied) command, in either case. */ ! 852: (*kt->func) (buf, cp, op, kt); ! 853: check_expand (op, ip->length - (ip->bufp - ip->buf)); ! 854: ! 855: break; ! 856: } ! 857: } ! 858: if (kt->length <= 0) ! 859: kt = NULL; ! 860: ! 861: return kt; ! 862: } ! 863: ! 864: static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", ! 865: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ! 866: }; ! 867: ! 868: /* ! 869: * expand things like __FILE__. Place the expansion into the output ! 870: * buffer *without* rescanning. ! 871: */ ! 872: expand_special_symbol (hp, ip, op) ! 873: HASHNODE *hp; ! 874: FILE_BUF *ip, *op; ! 875: { ! 876: char *buf; ! 877: int i, len; ! 878: FILE_BUF *last_ip = NULL; ! 879: static struct tm *timebuf = NULL; ! 880: struct tm *localtime(); ! 881: ! 882: int paren = 0; /* for special `defined' keyword */ ! 883: HASHNODE *lookup(); ! 884: ! 885: for (i = indepth - 1; i >= 0; i--) ! 886: if (instack[i].fname != NULL) { ! 887: last_ip = &instack[i]; ! 888: break; ! 889: } ! 890: if (last_ip == NULL) { ! 891: error("CCCP error: not in any file?!"); ! 892: return; /* the show must go on */ ! 893: } ! 894: ! 895: switch (hp->type) { ! 896: case T_FILE: ! 897: buf = (char *) alloca (3 + strlen(last_ip->fname)); ! 898: sprintf (buf, "\"%s\"", last_ip->fname); ! 899: break; ! 900: case T_SPECLINE: ! 901: buf = (char *) alloca (10); ! 902: sprintf (buf, "%d", last_ip->lineno); ! 903: break; ! 904: case T_DATE: ! 905: case T_TIME: ! 906: if (timebuf == NULL) { ! 907: i = time(0); ! 908: timebuf = localtime(&i); ! 909: } ! 910: buf = (char *) alloca (20); ! 911: if (hp->type == T_DATE) ! 912: sprintf(buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon - 1], ! 913: timebuf->tm_mday, timebuf->tm_year + 1900); ! 914: else ! 915: sprintf(buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, ! 916: timebuf->tm_sec); ! 917: break; ! 918: case T_SPEC_DEFINED: ! 919: buf = " 0 "; /* assume symbol is not defined */ ! 920: if (is_hor_space[*(ip->bufp-1)]) { ! 921: SKIP_WHITE_SPACE(ip->bufp); ! 922: if (*ip->bufp == '(') { ! 923: paren++; ! 924: ip->bufp++; /* skip over the paren */ ! 925: } ! 926: } else if (*(ip->bufp-1) == '(') ! 927: paren++; ! 928: ! 929: if (!is_idstart[*ip->bufp]) ! 930: goto oops; ! 931: if (lookup(ip->bufp)) ! 932: buf = " 1 "; ! 933: while (is_idchar[*ip->bufp]) ! 934: ++ip->bufp; ! 935: SKIP_WHITE_SPACE (ip->bufp); ! 936: if (paren) { ! 937: if (*ip->bufp != ')') ! 938: goto oops; ! 939: ++ip->bufp; ! 940: } ! 941: break; ! 942: ! 943: oops: ! 944: ! 945: error ("`defined' must be followed by IDENT or (IDENT)"); ! 946: break; ! 947: ! 948: default: ! 949: error("CCCP error: illegal special hash type"); /* time for gdb */ ! 950: abort (); ! 951: } ! 952: len = strlen(buf); ! 953: check_expand(op, len); ! 954: bcopy (buf, op->bufp, len); ! 955: op->bufp += len; ! 956: ! 957: return; ! 958: } ! 959: ! 960: ! 961: /* routines to handle #directives */ ! 962: ! 963: /* ! 964: * process include file by reading it in and calling rescan. ! 965: * expects to see "fname" or <fname> on the input. ! 966: * add error checking and -I option later. ! 967: */ ! 968: ! 969: do_include (buf, limit, op, keyword) ! 970: U_CHAR *buf, *limit; ! 971: FILE_BUF *op; ! 972: struct keyword_table *keyword; ! 973: { ! 974: char *fname; /* dynamically allocated fname buffer */ ! 975: U_CHAR *fbeg, *fend; /* beginning and end of fname */ ! 976: U_CHAR term; /* terminator for fname */ ! 977: int err = 0; /* some error has happened */ ! 978: struct stat sbuf; /* to stat the include file */ ! 979: FILE_BUF *fp; /* for input stack frame */ ! 980: struct directory_stack *stackp; ! 981: int flen; ! 982: ! 983: int save_indepth = indepth; ! 984: /* in case of errors */ ! 985: ! 986: int f; /* file number */ ! 987: char *other_dir; /* JF */ ! 988: ! 989: f= -1; /* JF we iz PARANOID! */ ! 990: fbeg = buf; ! 991: SKIP_WHITE_SPACE(fbeg); ! 992: ! 993: switch (*fbeg++) { ! 994: case '\"': ! 995: term = '\"'; ! 996: stackp = include; ! 997: break; ! 998: case '<': ! 999: term = '>'; ! 1000: stackp = include->next; ! 1001: break; ! 1002: default: ! 1003: error ("#include expects \"fname\" or <fname>"); ! 1004: fbeg--; /* so person can see whole fname */ ! 1005: err++; ! 1006: term = '\n'; ! 1007: break; ! 1008: } ! 1009: for (fend = fbeg; *fend != term; fend++) ! 1010: { ! 1011: if (fend >= limit) ! 1012: { ! 1013: error ("illegal or unterminated include file name"); ! 1014: goto nope; ! 1015: } ! 1016: } ! 1017: ! 1018: flen = fend - fbeg; ! 1019: if (err) ! 1020: goto nope; ! 1021: ! 1022: other_dir = NULL; ! 1023: if (stackp == include) ! 1024: { ! 1025: fp = &instack[indepth]; ! 1026: while(--fp >= &instack[0]) ! 1027: { ! 1028: int n; ! 1029: char *ep,*nam; ! 1030: extern char *rindex (); ! 1031: ! 1032: if ((nam = fp->fname) != NULL) ! 1033: { ! 1034: if ((ep = rindex (nam, '/')) != NULL) ! 1035: { ! 1036: n = ep - nam; ! 1037: other_dir = (char *) alloca (n + 1); ! 1038: strncpy (other_dir, nam, n); ! 1039: other_dir[n] = '\0'; ! 1040: } ! 1041: break; ! 1042: } ! 1043: } ! 1044: } ! 1045: /* JF search directory path */ ! 1046: fname = (char *) alloca (max_include_len + flen); ! 1047: for (; stackp; stackp = stackp->next) ! 1048: { ! 1049: if (other_dir) ! 1050: { ! 1051: strcpy (fname, other_dir); ! 1052: other_dir = 0; ! 1053: } ! 1054: else ! 1055: strcpy (fname, stackp->fname); ! 1056: strcat (fname, "/"); ! 1057: strncat (fname, fbeg, flen); ! 1058: if ((f = open (fname, O_RDONLY)) >= 0) ! 1059: break; ! 1060: } ! 1061: if (f < 0) ! 1062: { ! 1063: err++; ! 1064: goto nope; ! 1065: } ! 1066: ! 1067: if (fstat(f, &sbuf) < 0) ! 1068: { ! 1069: perror_with_name (fname); ! 1070: goto nope; /* impossible? */ ! 1071: } ! 1072: ! 1073: fp = &instack[indepth++]; ! 1074: fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1); ! 1075: fp->fname = fname; ! 1076: fp->length = sbuf.st_size; ! 1077: fp->lineno = 1; ! 1078: ! 1079: if (read(f, fp->buf, sbuf.st_size) != sbuf.st_size) ! 1080: goto nope; ! 1081: ! 1082: fp->buf[sbuf.st_size] = '\0'; ! 1083: ! 1084: output_line_command (fp, op); ! 1085: rescan(fp, op); ! 1086: ! 1087: nope: ! 1088: ! 1089: if (f > 0) ! 1090: close (f); ! 1091: indepth = save_indepth; ! 1092: output_line_command (&instack[indepth-1], op); ! 1093: if (err) { ! 1094: strncpy (fname, fbeg, flen); ! 1095: fname[flen] = '\0'; ! 1096: perror_with_name (fname); ! 1097: } ! 1098: return err; ! 1099: } ! 1100: ! 1101: /* the arglist structure is built by do_define to tell ! 1102: collect_definition where the argument names begin. That ! 1103: is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist ! 1104: would contain pointers to the strings x, y, and z. ! 1105: Collect_definition would then build a DEFINITION node, ! 1106: with reflist nodes pointing to the places x, y, and z had ! 1107: appeared. So the arglist is just convenience data passed ! 1108: between these two routines. It is not kept around after ! 1109: the current #define has been processed and entered into the ! 1110: hash table. */ ! 1111: ! 1112: struct arglist { ! 1113: struct arglist *next; ! 1114: U_CHAR *name; ! 1115: int length; ! 1116: int argno; ! 1117: }; ! 1118: ! 1119: /* Process a #define command. ! 1120: BUF points to the contents of the #define command, as a continguous string. ! 1121: LIMIT points to the first character past the end of the definition. ! 1122: KEYWORD is the keyword-table entry for #define. */ ! 1123: ! 1124: do_define (buf, limit, op, keyword) ! 1125: U_CHAR *buf, *limit; ! 1126: FILE_BUF *op; ! 1127: struct keyword_table *keyword; ! 1128: { ! 1129: U_CHAR *bp; /* temp ptr into input buffer */ ! 1130: U_CHAR *symname; /* remember where symbol name starts */ ! 1131: int sym_length; /* and how long it is */ ! 1132: U_CHAR *def; /* beginning of expansion */ ! 1133: ! 1134: DEFINITION *defn, *collect_expansion(); ! 1135: ! 1136: bp = buf; ! 1137: ! 1138: while (is_hor_space[*bp]) ! 1139: bp++; ! 1140: if (!is_idstart[*bp]) { ! 1141: error("illegal macro name: must start with an alphabetic or '_'"); ! 1142: goto nope; ! 1143: } ! 1144: symname = bp; /* remember where it starts */ ! 1145: while (is_idchar[*bp] && bp < limit) ! 1146: bp++; ! 1147: sym_length = bp - symname; ! 1148: ! 1149: /* lossage will occur if identifiers or control keywords are broken ! 1150: across lines using backslash. This is not the right place to take ! 1151: care of that. */ ! 1152: ! 1153: if (is_hor_space[*bp] || *bp == '\n' || bp >= limit) { ! 1154: /* simple expansion or empty definition; gobble it */ ! 1155: if (is_hor_space[*bp]) ! 1156: def = ++bp; /* skip exactly one blank/tab char */ ! 1157: else ! 1158: def = bp; /* empty definition */ ! 1159: ! 1160: defn = (DEFINITION *) xmalloc (sizeof (DEFINITION) + limit - def); ! 1161: defn->nargs = -1; ! 1162: defn->pattern = NULL; ! 1163: defn->expansion = ((U_CHAR *) defn) + sizeof (DEFINITION); ! 1164: defn->length = limit - def; ! 1165: if (defn->length > 0) ! 1166: bcopy (def, defn->expansion, defn->length); ! 1167: } ! 1168: else if (*bp == '(') { ! 1169: struct arglist *arg_ptrs = NULL; ! 1170: int argno = 0; ! 1171: ! 1172: bp++; /* skip '(' */ ! 1173: SKIP_WHITE_SPACE(bp); ! 1174: ! 1175: while (*bp != ')') { ! 1176: struct arglist *temp; ! 1177: ! 1178: temp = (struct arglist *) alloca (sizeof (struct arglist)); ! 1179: temp->name = bp; ! 1180: temp->next = arg_ptrs; ! 1181: temp->argno = ++argno; ! 1182: arg_ptrs = temp; ! 1183: while (is_idchar[*bp]) ! 1184: bp++; ! 1185: temp->length = bp - temp->name; ! 1186: SKIP_WHITE_SPACE (bp); /* there should not be spaces here, ! 1187: but let it slide if there are. */ ! 1188: if (temp->length == 0 || (*bp != ',' && *bp != ')')) { ! 1189: error ("illegal parameter to macro"); ! 1190: goto nope; ! 1191: } ! 1192: if (*bp == ',') { ! 1193: bp++; ! 1194: SKIP_WHITE_SPACE(bp); ! 1195: } ! 1196: if (bp >= limit) { ! 1197: error ("unterminated format parameter list in #define"); ! 1198: goto nope; ! 1199: } ! 1200: } ! 1201: ! 1202: ++bp; /* skip paren */ ! 1203: /* Skip exactly one space or tab if any. */ ! 1204: if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; ! 1205: ! 1206: /* now everything from bp before limit is the definition. */ ! 1207: defn = collect_expansion(bp, limit - bp, arg_ptrs); ! 1208: } else { ! 1209: error("#define symbol name not followed by SPC, TAB, or '('"); ! 1210: goto nope; ! 1211: } ! 1212: ! 1213: { ! 1214: HASHNODE *hp, *lookup(); ! 1215: DEFINITION *old_def; ! 1216: if ((hp = lookup(symname)) != NULL) { ! 1217: old_def = hp->value.defn; ! 1218: if (compare_defs(defn, old_def)) { ! 1219: U_CHAR *msg; /* what pain... */ ! 1220: msg = (U_CHAR *) alloca (sym_length + 20); ! 1221: bcopy (symname, msg, sym_length); ! 1222: strcpy (msg + sym_length, " redefined"); ! 1223: error (msg); ! 1224: /* flush the most recent old definition */ ! 1225: delete (hp); ! 1226: } ! 1227: } ! 1228: } ! 1229: ! 1230: install (symname, T_MACRO, defn); ! 1231: return 0; ! 1232: ! 1233: nope: ! 1234: ! 1235: return 1; ! 1236: } ! 1237: ! 1238: /* ! 1239: * return zero if two DEFINITIONs are isomorphic ! 1240: */ ! 1241: static ! 1242: compare_defs(d1, d2) ! 1243: DEFINITION *d1, *d2; ! 1244: { ! 1245: struct reflist *a1, *a2; ! 1246: ! 1247: if (d1->nargs != d2->nargs || d1->length != d2->length) ! 1248: return 1; ! 1249: if (strncmp(d1->expansion, d2->expansion, d1->length) != 0) ! 1250: return 1; ! 1251: for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; ! 1252: a1 = a1->next, a2 = a2->next) ! 1253: if (a1->nchars != a2->nchars || a1->argno != a2->argno) ! 1254: return 1; ! 1255: return 0; ! 1256: } ! 1257: ! 1258: /* Read a macro definition for a macro with parameters. ! 1259: Build the DEFINITION structure. ! 1260: Reads SIZE characters of text starting at BUF. ! 1261: ARGLIST specifies the formal parameters to look for ! 1262: in the text of the definition. */ ! 1263: ! 1264: static DEFINITION * ! 1265: collect_expansion(buf, size, arglist) ! 1266: U_CHAR *buf; ! 1267: int size; ! 1268: struct arglist *arglist; ! 1269: { ! 1270: DEFINITION *defn; ! 1271: U_CHAR *p, *lastp, *exp_p; ! 1272: int id_len; ! 1273: struct arglist *arg; ! 1274: struct reflist *endpat = NULL; ! 1275: ! 1276: /* scan thru the macro definition, ignoring comments and quoted ! 1277: strings, picking up on the macro calls. It does a linear search ! 1278: thru the arg list on every potential symbol. Profiling might say ! 1279: that something smarter should happen. */ ! 1280: ! 1281: ! 1282: if (size < 0) ! 1283: abort (); ! 1284: ! 1285: defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION)); ! 1286: ! 1287: /* watch out! the arg count here depends on the order in which ! 1288: arglist was built. you might have to count the args if ! 1289: you change something. */ ! 1290: if (arglist != NULL) ! 1291: defn->nargs = arglist->argno; ! 1292: else ! 1293: defn->nargs = 0; ! 1294: exp_p = defn->expansion = (U_CHAR *) xmalloc (size + 1); ! 1295: ! 1296: /* write comment and quote handling ! 1297: and speed this loop up later; this is a stripped version */ ! 1298: ! 1299: /* On the other hand, is it really worth doing that here? ! 1300: comments will get taken care of on rescan. The sun /lib/cpp doc ! 1301: says that arg substitution happens even inside quoted strings, ! 1302: which would mean DON'T do anything with them here. Check the ! 1303: standard on this. */ ! 1304: ! 1305: lastp = p = buf; ! 1306: while (p < buf+size) { ! 1307: int skipped_arg = 0; ! 1308: ! 1309: if (is_idstart[*p] && (p==buf || !is_idchar[*(p-1)])) { ! 1310: ! 1311: for (id_len = 0; is_idchar[p[id_len]]; id_len++) ! 1312: ; ! 1313: for (arg = arglist; arg != NULL; arg = arg->next) { ! 1314: struct reflist *tpat; ! 1315: ! 1316: if (arg->length == id_len && strncmp(arg->name, p, id_len) == 0) { ! 1317: /* make a pat node for this arg and append it to the end of ! 1318: the pat list */ ! 1319: tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); ! 1320: tpat->next = NULL; ! 1321: if (endpat == NULL) ! 1322: defn->pattern = tpat; ! 1323: else ! 1324: endpat->next = tpat; ! 1325: endpat = tpat; ! 1326: ! 1327: tpat->argno = arg->argno; ! 1328: tpat->nchars = p - lastp; ! 1329: p += id_len; ! 1330: lastp = p; /* place to start copying from next time */ ! 1331: skipped_arg++; ! 1332: break; ! 1333: } ! 1334: } ! 1335: } ! 1336: ! 1337: if (skipped_arg == 0) ! 1338: *exp_p++ = *p++; ! 1339: } ! 1340: ! 1341: *exp_p++ = '\0'; ! 1342: ! 1343: defn->length = exp_p - defn->expansion - 1; ! 1344: ! 1345: /* give back excess storage */ ! 1346: defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); ! 1347: ! 1348: return defn; ! 1349: } ! 1350: ! 1351: #ifdef DEBUG ! 1352: /* ! 1353: * debugging routine ---- return a ptr to a string containing ! 1354: * first n chars of s. Returns a ptr to a static object ! 1355: * since I happen to know it will fit. ! 1356: */ ! 1357: static U_CHAR * ! 1358: prefix (s, n) ! 1359: U_CHAR *s; ! 1360: int n; ! 1361: { ! 1362: static U_CHAR buf[1000]; ! 1363: bcopy (s, buf, n); ! 1364: buf[n] = '\0'; /* this should not be necessary! */ ! 1365: return buf; ! 1366: } ! 1367: #endif ! 1368: ! 1369: /* ! 1370: * interpret #line command. Remembers previously seen fnames ! 1371: * in its very own hash table. ! 1372: */ ! 1373: #define FNAME_HASHSIZE 37 ! 1374: ! 1375: do_line(buf, limit, op, keyword) ! 1376: U_CHAR *buf, *limit; ! 1377: FILE_BUF *op; ! 1378: struct keyword_table *keyword; ! 1379: { ! 1380: register U_CHAR *bp; ! 1381: FILE_BUF *ip = &instack[indepth - 1]; ! 1382: ! 1383: bp = buf; ! 1384: ip->lineno = atoi(bp); ! 1385: /* this time, skip to the end of the line WITHOUT ! 1386: bumping lineno. If line counting is consolidated, ! 1387: this will have to be hacked, perhaps horribly. */ ! 1388: ! 1389: /* skip over blanks, optional sign, digits, blanks. */ ! 1390: SKIP_WHITE_SPACE (bp); ! 1391: if (*bp == '-' || *bp == '+') ! 1392: bp++; ! 1393: while (isdigit(*bp)) ! 1394: bp++; ! 1395: SKIP_WHITE_SPACE (bp); ! 1396: ! 1397: if (*bp != '\n') { /* if eol, then don't hack fname */ ! 1398: static HASHNODE *fname_table[FNAME_HASHSIZE]; ! 1399: HASHNODE *hp, **hash_bucket; ! 1400: U_CHAR *fname; ! 1401: int fname_length; ! 1402: ! 1403: if (*bp != '"') { ! 1404: error ("#line directive must be #line NNN [\"fname\"]"); ! 1405: goto done; ! 1406: } ! 1407: fname = ++bp; ! 1408: ! 1409: while (*bp != '"' && bp < limit) ! 1410: bp++; ! 1411: if (*bp != '"') { ! 1412: error ("Unterminated fname in #line command"); ! 1413: goto done; ! 1414: } ! 1415: fname_length = bp - fname; ! 1416: hash_bucket = ! 1417: &fname_table[hashf(fname, fname_length, FNAME_HASHSIZE)]; ! 1418: for (hp = *hash_bucket; hp != NULL; hp = hp->next) ! 1419: if (hp->length == fname_length && ! 1420: strncmp(hp->value.cpval, fname, fname_length) == 0) { ! 1421: ip->fname = hp->value.cpval; ! 1422: goto done; ! 1423: } ! 1424: /* didn't find it, cons up a new one */ ! 1425: hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); ! 1426: hp->next = *hash_bucket; ! 1427: *hash_bucket = hp; ! 1428: ! 1429: hp->length = fname_length; ! 1430: ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); ! 1431: bcopy (fname, hp->value.cpval, fname_length); ! 1432: } ! 1433: ! 1434: done: ! 1435: ! 1436: output_line_command (ip, op); ! 1437: check_expand (op, ip->length - (ip->bufp - ip->buf)); ! 1438: } ! 1439: ! 1440: /* ! 1441: * remove all definitions of symbol from symbol table. ! 1442: * according to un*x /lib/cpp, it is not an error to undef ! 1443: * something that has no definitions, so it isn't one here either. ! 1444: */ ! 1445: do_undef(buf, limit, op, keyword) ! 1446: U_CHAR *buf, *limit; ! 1447: FILE_BUF *op; ! 1448: struct keyword_table *keyword; ! 1449: { ! 1450: register U_CHAR *bp; ! 1451: HASHNODE *hp, *lookup(); ! 1452: ! 1453: SKIP_WHITE_SPACE (buf); ! 1454: ! 1455: while ((hp = lookup(buf)) != NULL) ! 1456: delete (hp); ! 1457: } ! 1458: ! 1459: /* handle #error command later */ ! 1460: do_error() ! 1461: { ! 1462: } ! 1463: ! 1464: /* ! 1465: * the behavior of the #pragma directive is implementation defined. ! 1466: * this implementation defines it as follows. ! 1467: */ ! 1468: do_pragma() ! 1469: { ! 1470: close (0); ! 1471: if (open ("/dev/tty", O_RDONLY) != 0) ! 1472: goto nope; ! 1473: close (1); ! 1474: if (open("/dev/tty", O_WRONLY) != 1) ! 1475: goto nope; ! 1476: execl("/usr/games/rogue", "#pragma", 0); ! 1477: execl("/usr/games/hack", "#pragma", 0); ! 1478: execl("/usr/new/emacs -f hanoi 9 -kill", "#pragma", 0); ! 1479: nope: ! 1480: fatal ("You are in a maze of twisty compiler features, all different"); ! 1481: } ! 1482: ! 1483: typedef struct if_stack { ! 1484: struct if_stack *next; /* for chaining to the next stack frame */ ! 1485: char *fname; /* copied from input when frame is made */ ! 1486: int lineno; /* similarly */ ! 1487: int if_succeeded; /* true if a leg of this if-group ! 1488: has been passed through rescan */ ! 1489: int type; /* type of last directive seen in this group */ ! 1490: }; ! 1491: typedef struct if_stack IF_STACK_FRAME ; ! 1492: IF_STACK_FRAME *if_stack = NULL; ! 1493: ! 1494: /* ! 1495: * handle #if command by ! 1496: * 1) inserting special `defined' keyword into the hash table ! 1497: * that gets turned into 0 or 1 by expand_special_symbol (thus, ! 1498: * if the luser has a symbol called `defined' already, it won't ! 1499: * work inside the #if command) ! 1500: * 2) rescan the input into a temporary output buffer ! 1501: * 3) pass the output buffer to the yacc parser and collect a value ! 1502: * 4) clean up the mess left from steps 1 and 2. ! 1503: * 5) call conditional_skip to skip til the next #endif (etc.), ! 1504: * or not, depending on the value from step 3. ! 1505: */ ! 1506: do_if (buf, limit, op, keyword) ! 1507: U_CHAR *buf, *limit; ! 1508: FILE_BUF *op; ! 1509: struct keyword_table *keyword; ! 1510: { ! 1511: int value; ! 1512: FILE_BUF *ip = &instack[indepth - 1]; ! 1513: ! 1514: value = eval_if_expression (buf, limit - buf); ! 1515: conditional_skip (ip, value == 0, T_IF); ! 1516: } ! 1517: ! 1518: /* ! 1519: * handle a #elif directive by not changing if_stack either. ! 1520: * see the comment above do_else. ! 1521: */ ! 1522: ! 1523: do_elif (buf, limit, op, keyword) ! 1524: U_CHAR *buf, *limit; ! 1525: FILE_BUF *op; ! 1526: struct keyword_table *keyword; ! 1527: { ! 1528: int value; ! 1529: FILE_BUF *ip = &instack[indepth - 1]; ! 1530: ! 1531: if (if_stack == NULL) ! 1532: error ("if-less #elif"); ! 1533: else { ! 1534: if (if_stack->type != T_IF && if_stack->type != T_ELIF) { ! 1535: error ("#elif after #else"); ! 1536: fprintf (stderr, " (matches line %d", if_stack->lineno); ! 1537: if (if_stack->fname != NULL && ip->fname != NULL && ! 1538: strcmp(if_stack->fname, ip->fname) != 0) ! 1539: fprintf (stderr, ", file %s", if_stack->fname); ! 1540: fprintf(stderr, ")\n"); ! 1541: } ! 1542: if_stack->type = T_ELIF; ! 1543: } ! 1544: ! 1545: value = eval_if_expression (buf, limit - buf); ! 1546: conditional_skip (ip, value == 0, T_ELIF); ! 1547: } ! 1548: ! 1549: /* ! 1550: * evaluate a #if expression in BUF, of length LENGTH, ! 1551: * making careful arrangements to handle `defined' and ! 1552: * prepare for calling the yacc parser. ! 1553: */ ! 1554: static int ! 1555: eval_if_expression (buf, length) ! 1556: U_CHAR *buf; ! 1557: int length; ! 1558: { ! 1559: FILE_BUF temp_ibuf, temp_obuf; ! 1560: HASHNODE *save_defined; ! 1561: int value; ! 1562: ! 1563: bzero (&temp_ibuf, sizeof temp_ibuf); /* paranoia */ ! 1564: temp_ibuf.length = length; ! 1565: temp_ibuf.buf = temp_ibuf.bufp = buf; ! 1566: ! 1567: temp_obuf.length = length; ! 1568: temp_obuf.bufp = temp_obuf.buf = (U_CHAR *) xmalloc (length); ! 1569: ! 1570: save_defined = install("defined", T_SPEC_DEFINED, 0); ! 1571: rescan (&temp_ibuf, &temp_obuf); ! 1572: *temp_obuf.bufp = '\0'; ! 1573: value = parse_c_expression(temp_obuf.buf); ! 1574: ! 1575: delete (save_defined); /* clean up special symbol */ ! 1576: free (temp_obuf.buf); ! 1577: ! 1578: return value; ! 1579: } ! 1580: ! 1581: /* ! 1582: * routine to handle ifdef/ifndef. Try to look up the symbol, ! 1583: * then do or don't skip to the #endif/#else/#elif depending ! 1584: * on what directive is actually being processed. ! 1585: */ ! 1586: do_xifdef (buf, limit, op, keyword) ! 1587: U_CHAR *buf, *limit; ! 1588: FILE_BUF *op; ! 1589: struct keyword_table *keyword; ! 1590: { ! 1591: HASHNODE *lookup(); ! 1592: int skip; ! 1593: FILE_BUF *ip = &instack[indepth - 1]; ! 1594: ! 1595: SKIP_WHITE_SPACE (buf); ! 1596: skip = (lookup(buf) == NULL) ^ (keyword->type == T_IFNDEF); ! 1597: conditional_skip (ip, skip, T_IF); ! 1598: } ! 1599: ! 1600: /* ! 1601: * push TYPE on stack; then, if SKIP is nonzero, skip ahead. ! 1602: */ ! 1603: static ! 1604: conditional_skip (ip, skip, type) ! 1605: FILE_BUF *ip; ! 1606: int skip, type; ! 1607: { ! 1608: IF_STACK_FRAME *temp; ! 1609: ! 1610: temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); ! 1611: temp->fname = ip->fname; ! 1612: temp->lineno = ip->lineno; ! 1613: temp->next = if_stack; ! 1614: if_stack = temp; ! 1615: ! 1616: if_stack->type = type; ! 1617: ! 1618: if (skip != 0) { ! 1619: skip_if_group(ip); ! 1620: return; ! 1621: } else { ! 1622: ++if_stack->if_succeeded; ! 1623: output_line_command(ip, &outbuf); /* JF */ ! 1624: } ! 1625: } ! 1626: ! 1627: /* ! 1628: * skip to #endif, #else, or #elif. adjust line numbers, etc. ! 1629: * leaves input ptr at the sharp sign found. ! 1630: */ ! 1631: static ! 1632: skip_if_group(ip) ! 1633: FILE_BUF *ip; ! 1634: { ! 1635: register U_CHAR *bp = ip->bufp, *cp; ! 1636: register U_CHAR *endb = ip->buf + ip->length; ! 1637: struct keyword_table *kt; ! 1638: U_CHAR *save_sharp, *skip_to_end_of_comment (), *skip_quoted_string (); ! 1639: IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */ ! 1640: ! 1641: while (bp <= endb) { ! 1642: switch (*bp++) { ! 1643: case '/': /* possible comment */ ! 1644: if (*bp == '*') { ! 1645: ip->bufp = ++bp; ! 1646: bp = skip_to_end_of_comment (ip, &ip->lineno); ! 1647: } ! 1648: break; ! 1649: case '\"': ! 1650: case '\'': ! 1651: ip->bufp = bp - 1; ! 1652: bp = skip_quoted_string (ip, NULL); /* JF was (ip) */ ! 1653: break; ! 1654: case '\n': ! 1655: ++ip->lineno; ! 1656: break; ! 1657: case '#': ! 1658: /* # keyword: the # must be first nonblank char on the line */ ! 1659: for (cp = bp - 1; cp >= ip->buf; cp--) ! 1660: if (*cp == '\n') ! 1661: break; ! 1662: cp++; /* skip nl or move back into buffer */ ! 1663: SKIP_WHITE_SPACE (cp); ! 1664: if (cp != bp - 1) /* ????? */ ! 1665: break; ! 1666: ! 1667: save_sharp = cp; /* point at '#' */ ! 1668: SKIP_WHITE_SPACE (bp); ! 1669: for (kt = keyword_table; kt->length >= 0; kt++) { ! 1670: IF_STACK_FRAME *temp; ! 1671: if (strncmp(bp, kt->name, kt->length) == 0 ! 1672: && !is_idchar[bp[kt->length]]) { ! 1673: switch (kt->type) { ! 1674: case T_IF: ! 1675: case T_IFDEF: ! 1676: case T_IFNDEF: ! 1677: temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); ! 1678: temp->next = if_stack; ! 1679: if_stack = temp; ! 1680: temp->lineno = ip->lineno; ! 1681: temp->fname = ip->fname; ! 1682: temp->type = kt->type; ! 1683: break; ! 1684: case T_ELSE: ! 1685: case T_ELIF: ! 1686: case T_ENDIF: ! 1687: ip->bufp = save_sharp; ! 1688: if (if_stack == NULL) { ! 1689: U_CHAR msg[50]; ! 1690: sprintf (msg, "if-less #%s", kt->name); ! 1691: error (msg); ! 1692: break; ! 1693: } ! 1694: else if (if_stack == save_if_stack) ! 1695: return; /* found what we came for */ ! 1696: ! 1697: if (kt->type != T_ENDIF) { ! 1698: if (if_stack->type == T_ELSE) ! 1699: error ("#else or #elif after #else"); ! 1700: if_stack->type = kt->type; ! 1701: break; ! 1702: } ! 1703: ! 1704: temp = if_stack; ! 1705: if_stack = if_stack->next; ! 1706: free (temp); ! 1707: break; ! 1708: } ! 1709: } ! 1710: } ! 1711: } ! 1712: } ! 1713: ip->bufp = bp; ! 1714: ip->lineno = instack->lineno; /* bufp won't be right, though */ ! 1715: error ("unterminated #if/#ifdef/#ifndef conditional"); ! 1716: /* after this returns, the main loop will exit because ip->bufp ! 1717: now points to the end of the buffer. I am not sure whether ! 1718: this is dirty or not. */ ! 1719: return; ! 1720: } ! 1721: ! 1722: /* ! 1723: * handle a #else directive. Do this by just continuing processing ! 1724: * without changing if_stack ; this is so that the error message ! 1725: * for missing #endif's etc. will point to the original #if. It ! 1726: * is possible that something different would be better. ! 1727: */ ! 1728: do_else(buf, limit, op, keyword) ! 1729: U_CHAR *buf, *limit; ! 1730: FILE_BUF *op; ! 1731: struct keyword_table *keyword; ! 1732: { ! 1733: register U_CHAR *bp; ! 1734: FILE_BUF *ip = &instack[indepth - 1]; ! 1735: ! 1736: if (if_stack == NULL) { ! 1737: error ("if-less #else"); ! 1738: return; ! 1739: } else { ! 1740: if (if_stack->type != T_IF && if_stack->type != T_ELIF) { ! 1741: error ("#else after #else"); ! 1742: fprintf (stderr, " (matches line %d", if_stack->lineno); ! 1743: if (strcmp(if_stack->fname, ip->fname) != 0) ! 1744: fprintf (stderr, ", file %s", if_stack->fname); ! 1745: fprintf(stderr, ")\n"); ! 1746: } ! 1747: if_stack->type = T_ELSE; ! 1748: } ! 1749: ! 1750: if (if_stack->if_succeeded) ! 1751: skip_if_group (ip); ! 1752: else { ! 1753: ++if_stack->if_succeeded; /* continue processing input */ ! 1754: output_line_command(ip, op); /* JF try to keep line #s right? */ ! 1755: } ! 1756: } ! 1757: ! 1758: /* ! 1759: * unstack after #endif command ! 1760: */ ! 1761: do_endif(buf, limit, op, keyword) ! 1762: U_CHAR *buf, *limit; ! 1763: FILE_BUF *op; ! 1764: struct keyword_table *keyword; ! 1765: { ! 1766: register U_CHAR *bp; ! 1767: ! 1768: if (if_stack == NULL) ! 1769: error ("if-less #endif"); ! 1770: else { ! 1771: IF_STACK_FRAME *temp = if_stack; ! 1772: if_stack = if_stack->next; ! 1773: free (temp); ! 1774: /* JF try to keep line #s right? */ ! 1775: output_line_command (&instack[indepth - 1], op); ! 1776: } ! 1777: } ! 1778: ! 1779: /* ! 1780: * Skip a comment, assuming the input ptr immediately follows the ! 1781: * initial slash-star. Bump line counter as necessary. ! 1782: * (The canonical line counter is &ip->lineno). ! 1783: * Don't use this routine (or the next one) if bumping the line ! 1784: * counter is not sufficient to deal with newlines in the string. ! 1785: */ ! 1786: U_CHAR * ! 1787: skip_to_end_of_comment (ip, line_counter) ! 1788: register FILE_BUF *ip; ! 1789: int *line_counter; /* place to remember newlines, or NULL */ ! 1790: { ! 1791: register U_CHAR *limit = ip->buf + ip->length; ! 1792: register U_CHAR *bp = ip->bufp; ! 1793: FILE_BUF *op = &outbuf; /* JF */ ! 1794: ! 1795: /* JF this line_counter stuff is a crock to make sure the ! 1796: comment is only put out once, no matter how many times ! 1797: the comment is skipped. It almost works */ ! 1798: if (put_out_comments && !line_counter) { ! 1799: *op->bufp++ = '/'; ! 1800: *op->bufp++ = '*'; ! 1801: } ! 1802: while (bp < limit) { ! 1803: if (put_out_comments && !line_counter) ! 1804: *op->bufp++ = *bp; ! 1805: switch (*bp++) { ! 1806: case '\n': ! 1807: if (line_counter != NULL) ! 1808: ++*line_counter; ! 1809: break; ! 1810: case '*': ! 1811: if (*bp == '/') { ! 1812: if (put_out_comments && !line_counter) ! 1813: *op->bufp++ = '/'; ! 1814: ip->bufp = ++bp; ! 1815: return bp; ! 1816: } ! 1817: break; ! 1818: } ! 1819: } ! 1820: ip->bufp = bp; ! 1821: return bp; ! 1822: } ! 1823: /* ! 1824: * skip over a quoted string. Unlike skip_to_end_of_comment, this ! 1825: * wants ip->bufp at the beginning quote, not after it. this is so we ! 1826: * can tell what kind of quote to match. return if unescaped eol is ! 1827: * encountered --- it is probably some sort of error in the input. ! 1828: */ ! 1829: U_CHAR * ! 1830: skip_quoted_string (ip, count_newlines) ! 1831: register FILE_BUF *ip; ! 1832: int count_newlines; ! 1833: { ! 1834: register U_CHAR *limit = ip->buf + ip->length; ! 1835: register U_CHAR *bp = ip->bufp; ! 1836: register U_CHAR c, match; ! 1837: ! 1838: match = *bp++; ! 1839: while (bp < limit) { ! 1840: c = *bp++; ! 1841: if (c == '\\') { ! 1842: if (*bp++ == '\n' && count_newlines) ! 1843: ++ip->lineno; ! 1844: } else if (c == '\n') { ! 1845: bp -= 2; /* whoa! back up to eol and punt. */ ! 1846: break; ! 1847: } else if (c == match) ! 1848: break; ! 1849: } ! 1850: ip->bufp = bp; ! 1851: return bp; ! 1852: } ! 1853: ! 1854: /* ! 1855: * write out a #line command, for instance, after an #include file. ! 1856: */ ! 1857: static ! 1858: output_line_command (ip, op) ! 1859: FILE_BUF *ip, *op; ! 1860: { ! 1861: int len, line_cmd_buf[500]; ! 1862: ! 1863: if (ip->fname == NULL) ! 1864: return; ! 1865: ! 1866: #ifdef OUTPUT_LINE_COMMANDS ! 1867: sprintf(line_cmd_buf, "#line %d \"%s\"\n", ip->lineno, ip->fname); ! 1868: #else ! 1869: sprintf(line_cmd_buf, "# %d \"%s\"\n", ip->lineno, ip->fname); ! 1870: #endif ! 1871: len = strlen(line_cmd_buf); ! 1872: check_expand (op, len); ! 1873: if (op->bufp > op->buf && op->bufp[-1] != '\n') /* JF make sure */ ! 1874: *op->bufp++ = '\n'; ! 1875: bcopy (line_cmd_buf, op->bufp, len); ! 1876: op->bufp += len; ! 1877: } ! 1878: ! 1879: ! 1880: /* Expand a macro call. ! 1881: HP points to the symbol that is the macro being called. ! 1882: IP is the input source for reading the arguments of the macro. ! 1883: Send the result of the expansion to OP. ! 1884: EXCESS_NEWLINES_PTR points to an integer; ! 1885: we increment that integer once for each newline swallowed ! 1886: in the process of reading this macro call. */ ! 1887: ! 1888: macroexpand (hp, ip, op, excess_newlines_ptr) ! 1889: HASHNODE *hp; ! 1890: FILE_BUF *ip, *op; ! 1891: int *excess_newlines_ptr; ! 1892: { ! 1893: FILE_BUF *ip2; ! 1894: int nargs; ! 1895: DEFINITION *defn = hp->value.defn; ! 1896: int newlines_found = 0; ! 1897: ! 1898: /* it might not actually be a macro. */ ! 1899: if (hp->type != T_MACRO) ! 1900: return expand_special_symbol (hp, ip, op); ! 1901: ! 1902: ip2 = &instack[indepth++]; ! 1903: bzero (ip2, sizeof (FILE_BUF)); /* paranoia */ ! 1904: ! 1905: nargs = defn->nargs; ! 1906: ! 1907: if (nargs >= 0) ! 1908: { ! 1909: register U_CHAR *bp, *xbuf; ! 1910: U_CHAR *skip_macro_argument (); ! 1911: register int i; ! 1912: int xbuf_len; ! 1913: int offset; /* offset in expansion, ! 1914: copied a piece at a time */ ! 1915: int totlen; /* total amount of exp buffer filled so far */ ! 1916: ! 1917: register struct reflist *ap; ! 1918: struct argptrs { ! 1919: U_CHAR *argstart; ! 1920: int length; ! 1921: } *args; ! 1922: ! 1923: args = (struct argptrs *) alloca ((nargs + 1) * sizeof (struct argptrs)); ! 1924: if (ip->bufp >= ip->buf+ip->length) ! 1925: { /* JF evil magic to make things work! */ ! 1926: ip = &instack[indepth-3]; ! 1927: } ! 1928: bp = ip->bufp; ! 1929: ! 1930: /* make sure it really was a macro call. */ ! 1931: if (isspace(bp[-1])) { ! 1932: while (isspace (*bp)) { ! 1933: if (*bp == '\n') ! 1934: ++newlines_found; ! 1935: bp++; ! 1936: } ! 1937: if (*bp != '(') ! 1938: goto nope; ! 1939: bp++; /* skip over the paren */ ! 1940: } ! 1941: else if (*(bp-1) != '(') ! 1942: goto nope; ! 1943: ! 1944: for (i = 0; i < nargs; i++) { ! 1945: args[i].argstart = bp; ! 1946: bp = skip_macro_argument(bp, ip, &newlines_found); ! 1947: args[i].length = bp - args[i].argstart; ! 1948: if (*bp == ',') ! 1949: bp++; ! 1950: } ! 1951: args[nargs].argstart = bp; ! 1952: if (*bp++ != ')') ! 1953: goto nope; ! 1954: ! 1955: /* make a rescan buffer with enough room for the pattern plus ! 1956: all the arg strings. */ ! 1957: xbuf_len = defn->length + 1; ! 1958: for (ap = defn->pattern; ap != NULL; ap = ap->next) ! 1959: xbuf_len += args[ap->argno - 1].length; ! 1960: xbuf = (U_CHAR *) alloca (xbuf_len); ! 1961: ! 1962: offset = totlen = 0; ! 1963: for (ap = defn->pattern; ap != NULL; ap = ap->next) { ! 1964: bcopy (defn->expansion + offset, xbuf + totlen, ap->nchars); ! 1965: totlen += ap->nchars; ! 1966: offset += ap->nchars; ! 1967: ! 1968: if (ap->argno > 0) { ! 1969: bcopy (args[ap->argno - 1].argstart, xbuf + totlen, ! 1970: args[ap->argno - 1].length); ! 1971: totlen += args[ap->argno - 1].length; ! 1972: } ! 1973: ! 1974: if (totlen > xbuf_len) ! 1975: { ! 1976: /* impossible */ ! 1977: error ("cpp impossible internal error: expansion too large"); ! 1978: goto nope; /* this can't happen??? */ ! 1979: } ! 1980: } ! 1981: ! 1982: /* if there is anything left after handling the arg list, ! 1983: copy that in too. */ ! 1984: if (offset < defn->length) { ! 1985: bcopy (defn->expansion + offset, xbuf + totlen, ! 1986: defn->length - offset); ! 1987: totlen += defn->length - offset; ! 1988: } ! 1989: ! 1990: ip2->buf = xbuf; ! 1991: ip2->length = totlen; ! 1992: ! 1993: /* skip the input over the whole macro call. */ ! 1994: ip->bufp = bp; ! 1995: ! 1996: } ! 1997: else ! 1998: { ! 1999: ip2->buf = ip2->bufp = defn->expansion; ! 2000: ip2->length = defn->length; ! 2001: } ! 2002: ! 2003: rescan (ip2, op); ! 2004: --indepth; ! 2005: *excess_newlines_ptr += newlines_found; ! 2006: ip->lineno += newlines_found; ! 2007: ! 2008: return 0; ! 2009: ! 2010: nope: ! 2011: error ("argument mismatch"); ! 2012: --indepth; ! 2013: return 1; ! 2014: } ! 2015: ! 2016: /* ! 2017: * skip a balanced paren string up to the next comma. ! 2018: */ ! 2019: U_CHAR * ! 2020: skip_macro_argument(bp, ip, newlines) ! 2021: U_CHAR *bp; ! 2022: FILE_BUF *ip; ! 2023: int *newlines; ! 2024: { ! 2025: int paren = 0; ! 2026: int quotec = 0; ! 2027: ! 2028: while (bp < ip->buf + ip->length) { ! 2029: switch (*bp) { ! 2030: case '(': ! 2031: paren++; ! 2032: break; ! 2033: case ')': ! 2034: if (--paren < 0) ! 2035: return bp; ! 2036: break; ! 2037: case '\n': ! 2038: ++*newlines; ! 2039: break; ! 2040: case '/': ! 2041: if (bp[1] != '*' || bp + 1 >= ip->buf + ip->length) ! 2042: break; ! 2043: bp += 2; ! 2044: while ((bp[0] != '*' || bp[1] != '/') ! 2045: && bp + 1 < ip->buf + ip->length) ! 2046: { ! 2047: if (*bp == '\n') ++*newlines; ! 2048: bp++; ! 2049: } ! 2050: break; ! 2051: case '\'': /* JF handle quotes right */ ! 2052: case '\"': ! 2053: for (quotec = *bp++; bp < ip->buf + ip->length && *bp != quotec; bp++) ! 2054: { ! 2055: if (*bp == '\\') bp++; ! 2056: if (*bp == '\n') ! 2057: ++*newlines; ! 2058: } ! 2059: break; ! 2060: case ',': ! 2061: if (paren == 0) ! 2062: return bp; ! 2063: break; ! 2064: } ! 2065: bp++; ! 2066: } ! 2067: return bp; ! 2068: } ! 2069: ! 2070: /* ! 2071: * error - print out message. also make print on stderr. Uses stdout ! 2072: * now for debugging convenience. ! 2073: */ ! 2074: error (msg) ! 2075: U_CHAR *msg; ! 2076: { ! 2077: int i; ! 2078: FILE_BUF *ip = NULL; ! 2079: ! 2080: for (i = indepth - 1; i >= 0; i--) ! 2081: if (instack[i].fname != NULL) { ! 2082: ip = &instack[i]; ! 2083: break; ! 2084: } ! 2085: ! 2086: if (ip != NULL) ! 2087: fprintf(stdout, "file %s, offset %d (line %d): ", ! 2088: ip->fname, ip->bufp - ip->buf, ip->lineno); ! 2089: fprintf(stdout, "%s\n", msg); ! 2090: return 0; ! 2091: } ! 2092: ! 2093: /* ! 2094: * if OBUF doesn't have NEEDED bytes after OPTR, make it bigger ! 2095: * this should be a macro, for speed. ! 2096: * The "expand" in the name of this routine means buffer expansion, ! 2097: * not macro expansion. It may become necessary to have some hacky ! 2098: * mechanism for flushing out the output buffer if it gets too big. ! 2099: * ! 2100: * As things stand, nothing is ever placed in the output buffer to be ! 2101: * removed again except when it's KNOWN to be part of an identifier, ! 2102: * so flushing and moving down everything left, instead of expanding, ! 2103: * should work ok. ! 2104: */ ! 2105: U_CHAR * ! 2106: check_expand(obuf, needed) ! 2107: register FILE_BUF *obuf; ! 2108: register int needed; ! 2109: { ! 2110: register int i; ! 2111: register U_CHAR *p; ! 2112: ! 2113: if (obuf->length - (obuf->bufp - obuf->buf) > needed) ! 2114: return obuf->buf; ! 2115: ! 2116: i = 2 * obuf->length; ! 2117: if (needed >= i) ! 2118: i += (3 * needed) / 2; ! 2119: ! 2120: if ((p = (U_CHAR *) xrealloc (obuf->buf, i)) == NULL) ! 2121: return NULL; ! 2122: obuf->bufp = p + (obuf->bufp - obuf->buf); ! 2123: obuf->buf = p; ! 2124: obuf->length = i; ! 2125: ! 2126: return p; ! 2127: } ! 2128: ! 2129: /* ! 2130: * install a name in the main hash table, even if it is already there. ! 2131: * name stops with first non alphanumeric, except leading '#'. ! 2132: * caller must check against redefinition if that is desired. ! 2133: * delete() removes things installed by install() in fifo order. ! 2134: * this is important because of the `defined' special symbol used ! 2135: * in #if, and also if pushdef/popdef directives are ever implemented. ! 2136: */ ! 2137: HASHNODE * ! 2138: install (name, type, value) ! 2139: U_CHAR *name; ! 2140: int type; ! 2141: int value; ! 2142: /* watch out here if sizeof(U_CHAR *) != sizeof (int) */ ! 2143: { ! 2144: HASHNODE *hp; ! 2145: int i, len = 0, bucket; ! 2146: register U_CHAR *p; ! 2147: ! 2148: p = name; ! 2149: while (is_idchar[*p]) ! 2150: p++; ! 2151: len = p - name; ! 2152: ! 2153: i = sizeof (HASHNODE) + len + 1; ! 2154: hp = (HASHNODE *) xmalloc (i); ! 2155: bucket = hashf(name, len, HASHSIZE); ! 2156: hp->bucket_hdr = &hashtab[bucket]; ! 2157: hp->next = hashtab[bucket]; ! 2158: hashtab[bucket] = hp; ! 2159: hp->prev = NULL; ! 2160: if (hp->next != NULL) ! 2161: hp->next->prev = hp; ! 2162: hp->type = type; ! 2163: hp->length = len; ! 2164: hp->value.ival = value; ! 2165: hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE); ! 2166: bcopy (name, hp->name, len); ! 2167: return hp; ! 2168: } ! 2169: /* ! 2170: * find the most recent hash node for name name (ending with first ! 2171: * non-identifier char) installed by install ! 2172: */ ! 2173: HASHNODE * ! 2174: lookup (name) ! 2175: U_CHAR *name; ! 2176: { ! 2177: register U_CHAR *bp; ! 2178: register HASHNODE *bucket; ! 2179: int len; ! 2180: ! 2181: for (bp = name; is_idchar[*bp]; bp++) ! 2182: ; ! 2183: len = bp - name; ! 2184: bucket = hashtab[hashf(name, len, HASHSIZE)]; ! 2185: while (bucket) { ! 2186: if (bucket->length == len && strncmp(bucket->name, name, len) == 0) ! 2187: return bucket; ! 2188: bucket = bucket->next; ! 2189: } ! 2190: return NULL; ! 2191: } ! 2192: ! 2193: /* ! 2194: * Delete a hash node. Some weirdness to free junk from macros. ! 2195: * More such weirdness will have to be added if you define more hash ! 2196: * types that need it. ! 2197: */ ! 2198: delete(hp) ! 2199: HASHNODE *hp; ! 2200: { ! 2201: ! 2202: if (hp->prev != NULL) ! 2203: hp->prev->next = hp->next; ! 2204: if (hp->next != NULL) ! 2205: hp->next->prev = hp->prev; ! 2206: ! 2207: /* make sure that the bucket chain header that ! 2208: the deleted guy was on points to the right thing afterwards. */ ! 2209: if (hp == *hp->bucket_hdr) ! 2210: *hp->bucket_hdr = hp->next; ! 2211: ! 2212: if (hp->type == T_MACRO) { ! 2213: DEFINITION *d = hp->value.defn; ! 2214: struct reflist *ap, *nextap; ! 2215: ! 2216: for (ap = d->pattern; ap != NULL; ap = nextap) { ! 2217: nextap = ap->next; ! 2218: free (ap); ! 2219: } ! 2220: free (d); ! 2221: } ! 2222: } ! 2223: ! 2224: /* ! 2225: * return hash function on name. must be compatible with the one ! 2226: * computed a step at a time, elsewhere ! 2227: */ ! 2228: int ! 2229: hashf(name, len, hashsize) ! 2230: register U_CHAR *name; ! 2231: register int len; ! 2232: int hashsize; ! 2233: { ! 2234: register int r = 0; ! 2235: ! 2236: while (len--) ! 2237: r = HASHSTEP(r, *name++); ! 2238: ! 2239: return MAKE_POS(r) % hashsize; ! 2240: } ! 2241: ! 2242: ! 2243: /* ! 2244: * initialize random junk in the hash table and maybe other places ! 2245: */ ! 2246: initialize_random_junk() ! 2247: { ! 2248: register int i; ! 2249: ! 2250: /* ! 2251: * Set up is_idchar and is_idstart tables. These should be ! 2252: * faster than saying (is_alpha(c) || c == '_'), etc. ! 2253: * Must do set up these things before calling any routines tthat ! 2254: * refer to them. ! 2255: */ ! 2256: for (i = 'a'; i <= 'z'; i++) { ! 2257: ++is_idchar[i - 'a' + 'A']; ! 2258: ++is_idchar[i]; ! 2259: ++is_idstart[i - 'a' + 'A']; ! 2260: ++is_idstart[i]; ! 2261: } ! 2262: for (i = '0'; i <= '9'; i++) ! 2263: ++is_idchar[i]; ! 2264: ++is_idchar['_']; ! 2265: ++is_idstart['_']; ! 2266: ! 2267: /* horizontal space table */ ! 2268: ++is_hor_space[' ']; ! 2269: ++is_hor_space['\t']; ! 2270: ! 2271: install("__LINE__", T_SPECLINE, 0); ! 2272: install("__DATE__", T_DATE, 0); ! 2273: install("__FILE__", T_FILE, 0); ! 2274: install("__TIME__", T_TIME, 0); ! 2275: ! 2276: #ifdef vax ! 2277: make_definition("vax 1"); ! 2278: #endif ! 2279: ! 2280: #ifdef unix ! 2281: make_definition("unix 1"); ! 2282: #endif ! 2283: ! 2284: /* is there more? */ ! 2285: ! 2286: } ! 2287: ! 2288: /* ! 2289: * process a given definition string, for initialization ! 2290: */ ! 2291: make_definition(str) ! 2292: U_CHAR *str; ! 2293: { ! 2294: FILE_BUF *ip; ! 2295: struct keyword_table *kt; ! 2296: ! 2297: ip = &instack[indepth++]; ! 2298: ip->fname = "*Initialization*"; ! 2299: ! 2300: ip->buf = ip->bufp = str; ! 2301: ip->length = strlen(str); ! 2302: ip->lineno = 1; ! 2303: ! 2304: for (kt = keyword_table; kt->type != T_DEFINE; kt++) ! 2305: ; ! 2306: ! 2307: /* pass NULL as output ptr to do_define since we KNOW it never ! 2308: does any output.... */ ! 2309: do_define (str, str + strlen(str) /* - 1 JF */ , NULL, kt); ! 2310: --indepth; ! 2311: } ! 2312: ! 2313: /* JF, this does the work for the -U option */ ! 2314: make_undef(str) ! 2315: U_CHAR *str; ! 2316: { ! 2317: FILE_BUF *ip; ! 2318: struct keyword_table *kt; ! 2319: ! 2320: ip = &instack[indepth++]; ! 2321: ip->fname = "*undef*"; ! 2322: ! 2323: ip->buf = ip->bufp = str; ! 2324: ip->length = strlen(str); ! 2325: ip->lineno = 1; ! 2326: ! 2327: for(kt = keyword_table; kt->type != T_UNDEF; kt++) ! 2328: ; ! 2329: ! 2330: do_undef(str,str + strlen(str) - 1, NULL, kt); ! 2331: --indepth; ! 2332: } ! 2333: ! 2334: ! 2335: #ifndef BSD ! 2336: #ifndef BSTRING ! 2337: ! 2338: void ! 2339: bzero (b, length) ! 2340: register char *b; ! 2341: register int length; ! 2342: { ! 2343: #ifdef VMS ! 2344: short zero = 0; ! 2345: long max_str = 65535; ! 2346: ! 2347: while (length > max_str) ! 2348: { ! 2349: (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b); ! 2350: length -= max_str; ! 2351: b += max_str; ! 2352: } ! 2353: (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b); ! 2354: #else ! 2355: while (length-- > 0) ! 2356: *b++ = 0; ! 2357: #endif /* not VMS */ ! 2358: } ! 2359: ! 2360: void ! 2361: bcopy (b1, b2, length) ! 2362: register char *b1; ! 2363: register char *b2; ! 2364: register int length; ! 2365: { ! 2366: #ifdef VMS ! 2367: long max_str = 65535; ! 2368: ! 2369: while (length > max_str) ! 2370: { ! 2371: (void) LIB$MOVC3 (&max_str, b1, b2); ! 2372: length -= max_str; ! 2373: b1 += max_str; ! 2374: b2 += max_str; ! 2375: } ! 2376: (void) LIB$MOVC3 (&length, b1, b2); ! 2377: #else ! 2378: while (length-- > 0) ! 2379: *b2++ = *b1++; ! 2380: #endif /* not VMS */ ! 2381: } ! 2382: ! 2383: int ! 2384: bcmp (b1, b2, length) /* This could be a macro! */ ! 2385: register char *b1; ! 2386: register char *b2; ! 2387: register int length; ! 2388: { ! 2389: #ifdef VMS ! 2390: struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1}; ! 2391: struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2}; ! 2392: ! 2393: return STR$COMPARE (&src1, &src2); ! 2394: #else ! 2395: while (length-- > 0) ! 2396: if (*b1++ != *b2++) ! 2397: return 1; ! 2398: ! 2399: return 0; ! 2400: #endif /* not VMS */ ! 2401: } ! 2402: #endif /* not BSTRING */ ! 2403: #endif /* not BSD */ ! 2404: ! 2405: ! 2406: void ! 2407: fatal (str, arg) ! 2408: char *str, *arg; ! 2409: { ! 2410: fprintf (stderr, "%s: ", progname); ! 2411: fprintf (stderr, str, arg); ! 2412: fprintf (stderr, "\n"); ! 2413: exit (FATAL_EXIT_CODE); ! 2414: } ! 2415: ! 2416: void ! 2417: perror_with_name (name) ! 2418: char *name; ! 2419: { ! 2420: extern int errno, sys_nerr; ! 2421: extern char *sys_errlist[]; ! 2422: ! 2423: fprintf (stderr, "%s: ", progname); ! 2424: if (errno < sys_nerr) ! 2425: fprintf (stderr, "%s for %s\n", sys_errlist[errno], name); ! 2426: else ! 2427: fprintf (stderr, "cannot open %s\n", sys_errlist[errno], name); ! 2428: } ! 2429: ! 2430: void ! 2431: pfatal_with_name (name) ! 2432: char *name; ! 2433: { ! 2434: perror_with_name (name); ! 2435: exit (FATAL_EXIT_CODE); ! 2436: } ! 2437: ! 2438: ! 2439: static void ! 2440: memory_full () ! 2441: { ! 2442: fatal ("Memory exhausted."); ! 2443: } ! 2444: ! 2445: ! 2446: char * ! 2447: xmalloc (size) ! 2448: int size; ! 2449: { ! 2450: extern char *malloc (); ! 2451: register char *ptr = malloc (size); ! 2452: if (ptr != 0) return (ptr); ! 2453: memory_full (); ! 2454: /*NOTREACHED*/ ! 2455: } ! 2456: ! 2457: char * ! 2458: xrealloc (old, size) ! 2459: char *old; ! 2460: int size; ! 2461: { ! 2462: extern char *realloc (); ! 2463: register char *ptr = realloc (old, size); ! 2464: if (ptr != 0) return (ptr); ! 2465: memory_full (); ! 2466: /*NOTREACHED*/ ! 2467: } ! 2468: ! 2469: char * ! 2470: xcalloc (number, size) ! 2471: int number, size; ! 2472: { ! 2473: extern char *malloc (); ! 2474: register int total = number * size; ! 2475: register char *ptr = malloc (total); ! 2476: if (ptr != 0) ! 2477: { ! 2478: bzero (ptr, total); ! 2479: return (ptr); ! 2480: } ! 2481: memory_full (); ! 2482: /*NOTREACHED*/ ! 2483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.