Annotation of 43BSDReno/contrib/emacs-18.55/cpp/cccp.c, revision 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.