Annotation of GNUtools/emacs/cpp/cccp.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.