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

unix.superglobalmegacorp.com

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