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