Annotation of researchv10dc/cmd/gcc/cccp.c, revision 1.1

1.1     ! root        1: /* C Compatible Compiler Preprocessor (CCCP)
        !             2: Copyright (C) 1986, 1987, Free Software Foundation, Inc.
        !             3:                     Written by Paul Rubin, June 1986
        !             4:                    Adapted to ANSI C, Richard Stallman, Jan 1987
        !             5: 
        !             6:                           NO WARRANTY
        !             7: 
        !             8:   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
        !             9: NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
        !            10: WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
        !            11: RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
        !            12: WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
        !            13: BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
        !            14: FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
        !            15: AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
        !            16: DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
        !            17: CORRECTION.
        !            18: 
        !            19:  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
        !            20: STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
        !            21: WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
        !            22: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
        !            23: OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
        !            24: USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
        !            25: DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
        !            26: A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
        !            27: PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
        !            28: DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
        !            29: 
        !            30:                GENERAL PUBLIC LICENSE TO COPY
        !            31: 
        !            32:   1. You may copy and distribute verbatim copies of this source file
        !            33: as you receive it, in any medium, provided that you conspicuously
        !            34: and appropriately publish on each copy a valid copyright notice
        !            35: "Copyright (C) 1987, Free Software Foundation"; and include
        !            36: following the copyright notice a verbatim copy of the above disclaimer
        !            37: of warranty and of this License.  You may charge a distribution fee for the
        !            38: physical act of transferring a copy.
        !            39: 
        !            40:   2. You may modify your copy or copies of this source file or
        !            41: any portion of it, and copy and distribute such modifications under
        !            42: the terms of Paragraph 1 above, provided that you also do the following:
        !            43: 
        !            44:     a) cause the modified files to carry prominent notices stating
        !            45:     that you changed the files and the date of any change; and
        !            46: 
        !            47:     b) cause the whole of any work that you distribute or publish,
        !            48:     that in whole or in part contains or is a derivative of this
        !            49:     program or any part thereof, to be licensed at no charge to all
        !            50:     third parties on terms identical to those contained in this
        !            51:     License Agreement (except that you may choose to grant more extensive
        !            52:     warranty protection to some or all third parties, at your option).
        !            53: 
        !            54:     c) You may charge a distribution fee for the physical act of
        !            55:     transferring a copy, and you may at your option offer warranty
        !            56:     protection in exchange for a fee.
        !            57: 
        !            58: Mere aggregation of another unrelated program with this program (or its
        !            59: derivative) on a volume of a storage or distribution medium does not bring
        !            60: the other program under the scope of these terms.
        !            61: 
        !            62:   3. You may copy and distribute this program (or a portion or derivative
        !            63: of it, under Paragraph 2) in object code or executable form under the terms
        !            64: of Paragraphs 1 and 2 above provided that you also do one of the following:
        !            65: 
        !            66:     a) accompany it with the complete corresponding machine-readable
        !            67:     source code, which must be distributed under the terms of
        !            68:     Paragraphs 1 and 2 above; or,
        !            69: 
        !            70:     b) accompany it with a written offer, valid for at least three
        !            71:     years, to give any third party free (except for a nominal
        !            72:     shipping charge) a complete machine-readable copy of the
        !            73:     corresponding source code, to be distributed under the terms of
        !            74:     Paragraphs 1 and 2 above; or,
        !            75: 
        !            76:     c) accompany it with the information you received as to where the
        !            77:     corresponding source code may be obtained.  (This alternative is
        !            78:     allowed only for noncommercial distribution and only if you
        !            79:     received the program in object code or executable form alone.)
        !            80: 
        !            81: For an executable file, complete source code means all the source code for
        !            82: all modules it contains; but, as a special exception, it need not include
        !            83: source code for modules which are standard libraries that accompany the
        !            84: operating system on which the executable file runs.
        !            85: 
        !            86:   4. You may not copy, sublicense, distribute or transfer this program
        !            87: except as expressly provided under this License Agreement.  Any attempt
        !            88: otherwise to copy, sublicense, distribute or transfer this program is void and
        !            89: your rights to use the program under this License agreement shall be
        !            90: automatically terminated.  However, parties who have received computer
        !            91: software programs from you with this License Agreement will not have
        !            92: their licenses terminated so long as such parties remain in full compliance.
        !            93: 
        !            94:   5. If you wish to incorporate parts of this program into other free
        !            95: programs whose distribution conditions are different, write to the Free
        !            96: Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
        !            97: worked out a simple rule that can be stated here, but we will often permit
        !            98: this.  We will be guided by the two goals of preserving the free status of
        !            99: all derivatives of our free software and of promoting the sharing and reuse of
        !           100: software.
        !           101: 
        !           102: 
        !           103:  In other words, you are welcome to use, share and improve this program.
        !           104:  You are forbidden to forbid anyone else to use, share and improve
        !           105:  what you give them.   Help stamp out software-hoarding!  */
        !           106: 
        !           107: typedef unsigned char U_CHAR;
        !           108: 
        !           109: #ifdef EMACS
        !           110: #define NO_SHORTNAMES
        !           111: #include "../src/config.h"
        !           112: #ifdef open
        !           113: #undef open
        !           114: #undef read
        !           115: #undef write
        !           116: #endif /* open */
        !           117: #endif /* EMACS */
        !           118: 
        !           119: #ifndef EMACS
        !           120: #include "config.h"
        !           121: #endif /* not EMACS */
        !           122: 
        !           123: /* In case config.h defines these.  */
        !           124: #undef bcopy
        !           125: #undef bzero
        !           126: #undef bcmp
        !           127: 
        !           128: #include <sys/types.h>
        !           129: #include <sys/stat.h>
        !           130: #include <ctype.h>
        !           131: #include <stdio.h>
        !           132: 
        !           133: #ifndef VMS
        !           134: #include <sys/file.h>
        !           135: #ifndef USG
        !           136: #include <sys/time.h>          /* for __DATE__ and __TIME__ */
        !           137: #include <sys/resource.h>
        !           138: #else
        !           139: #define index strchr
        !           140: #define rindex strrchr
        !           141: #include <time.h>
        !           142: #include <fcntl.h>
        !           143: #endif /* USG */
        !           144: #endif /* not VMS */
        !           145:   
        !           146: /* VMS-specific definitions */
        !           147: #ifdef VMS
        !           148: #include <time.h>
        !           149: #include <errno.h>             /* This defines "errno" properly */
        !           150: #include <perror.h>            /* This defines sys_errlist/sys_nerr properly */
        !           151: #define O_RDONLY       0       /* Open arg for Read/Only  */
        !           152: #define O_WRONLY       1       /* Open arg for Write/Only */
        !           153: #define read(fd,buf,size)      VAX11_C_read(fd,buf,size)
        !           154: #define write(fd,buf,size)     VAX11_C_write(fd,buf,size)
        !           155: #ifdef __GNUC__
        !           156: #define BSTRING                        /* VMS/GCC supplies the bstring routines */
        !           157: #endif __GNUC__
        !           158: #endif /* VMS */
        !           159: 
        !           160: /* External declarations.  */
        !           161: 
        !           162: void bcopy (), bzero ();
        !           163: int bcmp ();
        !           164: extern char version_string[];
        !           165: 
        !           166: /* Forward declarations.  */
        !           167: 
        !           168: int do_define (), do_line (), do_include (), do_undef (), do_error (),
        !           169:   do_pragma (), do_if (), do_xifdef (), do_else (),
        !           170:   do_elif (), do_endif (), do_sccs ();
        !           171: 
        !           172: struct hashnode *install ();
        !           173: struct hashnode *lookup ();
        !           174: 
        !           175: char *xmalloc (), *xrealloc (), *xcalloc ();
        !           176: void fatal (), pfatal_with_name (), perror_with_name ();
        !           177: 
        !           178: int grow_outbuf ();
        !           179: int handle_directive ();
        !           180: void memory_full ();
        !           181: 
        !           182: U_CHAR *macarg1 ();
        !           183: char *macarg ();
        !           184: 
        !           185: U_CHAR *skip_to_end_of_comment ();
        !           186: U_CHAR *skip_quoted_string ();
        !           187: 
        !           188: #ifndef FATAL_EXIT_CODE
        !           189: #define FATAL_EXIT_CODE 33     /* gnu cc command understands this */
        !           190: #endif
        !           191: 
        !           192: #ifndef SUCCESS_EXIT_CODE
        !           193: #define SUCCESS_EXIT_CODE 0    /* 0 means success on Unix.  */
        !           194: #endif
        !           195: 
        !           196: /* Name under which this program was invoked.  */
        !           197: 
        !           198: char *progname;
        !           199: 
        !           200: /* Current maximum length of directory names in the search path
        !           201:    for include files.  (Altered as we get more of them.)  */
        !           202: 
        !           203: int max_include_len = sizeof("/usr/local/lib/gcc-include");
        !           204: 
        !           205: /* Nonzero means copy comments into the output file.  */
        !           206: 
        !           207: int put_out_comments = 0;
        !           208: 
        !           209: /* Nonzero means don't process the ANSI trigraph sequences.  */
        !           210: 
        !           211: int no_trigraphs = 0;
        !           212: 
        !           213: /* Nonzero means print the names of included files rather than
        !           214:    the preprocessed output.  1 means just the #include "...",
        !           215:    2 means #include <...> as well.  */
        !           216: 
        !           217: int print_deps = 0;
        !           218: 
        !           219: /* Nonzero means don't output line number information.  */
        !           220: 
        !           221: int no_line_commands;
        !           222: 
        !           223: /* Nonzero means inhibit output of the preprocessed text
        !           224:    and instead output the definitions of all user-defined macros
        !           225:    in a form suitable for use as input to cccp.  */
        !           226: 
        !           227: int dump_macros;
        !           228: 
        !           229: /* Nonzero means give all the error messages the ANSI standard requires.  */
        !           230: 
        !           231: int pedantic;
        !           232: 
        !           233: /* Nonzero means warn if slash-star appears in a comment.  */
        !           234: 
        !           235: int warn_comments;
        !           236: 
        !           237: /* Nonzero means try to imitate old fashioned non-ANSI preprocessor.  */
        !           238: 
        !           239: int traditional;
        !           240: 
        !           241: /* Nonzero causes output not to be done,
        !           242:    but directives such as #define that have side effects
        !           243:    are still obeyed.  */
        !           244: 
        !           245: int no_output;
        !           246: 
        !           247: /* I/O buffer structure.
        !           248:    The `fname' field is nonzero for source files and #include files
        !           249:    and for the dummy text used for -D and -U.
        !           250:    It is zero for rescanning results of macro expansion
        !           251:    and for expanding macro arguments.  */
        !           252: #define INPUT_STACK_MAX 200
        !           253: struct file_buf {
        !           254:   char *fname;
        !           255:   int lineno;
        !           256:   int length;
        !           257:   U_CHAR *buf;
        !           258:   U_CHAR *bufp;
        !           259:   /* Macro that this level is the expansion of.
        !           260:      Included so that we can reenable the macro
        !           261:      at the end of this level.  */
        !           262:   struct hashnode *macro;
        !           263:   /* Value of if_stack at start of this file.
        !           264:      Used to prohibit unmatched #endif (etc) in an include file.  */
        !           265:   struct if_stack *if_stack;
        !           266:   /* Object to be freed at end of input at this level.  */
        !           267:   U_CHAR *free;
        !           268: } instack[INPUT_STACK_MAX];
        !           269: 
        !           270: /* Current nesting level of input sources.
        !           271:    `instack[indepth]' is the level currently being read.  */
        !           272: int indepth = -1;
        !           273: 
        !           274: typedef struct file_buf FILE_BUF;
        !           275: 
        !           276: /* The output buffer.  Its LENGTH field is the amount of room allocated
        !           277:    for the buffer, not the number of chars actually present.  To get
        !           278:    that, subtract outbuf.buf from outbuf.bufp. */
        !           279: 
        !           280: #define OUTBUF_SIZE 10 /* initial size of output buffer */
        !           281: FILE_BUF outbuf;
        !           282: 
        !           283: /* Grow output buffer OBUF points at
        !           284:    so it can hold at least NEEDED more chars.  */
        !           285: 
        !           286: #define check_expand(OBUF, NEEDED)  \
        !           287:   (((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED))   \
        !           288:    ? grow_outbuf ((OBUF), (NEEDED)) : 0)
        !           289: 
        !           290: struct directory_stack
        !           291:   {
        !           292:     struct directory_stack *next;
        !           293:     char *fname;
        !           294:   };
        !           295: 
        !           296: /* #include "file" looks in source file dir, then stack. */
        !           297: /* #include <file> just looks in the stack. */
        !           298: /* -I directories are added to the end, then the defaults are added. */
        !           299: struct directory_stack include_defaults[] =
        !           300:   {
        !           301: #ifndef VMS
        !           302: #ifdef CPLUSPLUS
        !           303:     /* Pick up GNU C++ specific include files.  */
        !           304:     { &include_defaults[1], "/usr/local/lib/g++-include" },
        !           305:     /* Borrow AT&T C++ head files, if available.  */
        !           306:     { &include_defaults[2], "/usr/include/CC" },
        !           307:     /* Use GNU CC specific header files.  */
        !           308:     { &include_defaults[3], "/usr/local/lib/gcc-include" },
        !           309: #else
        !           310:     { &include_defaults[1], "/usr/local/lib/gcc-include" },
        !           311: #endif
        !           312:     { 0, "/usr/include" }
        !           313: #else
        !           314:     { &include_defaults[1], "GNU_CC_INCLUDE:" },       /* GNU includes */
        !           315:     { &include_defaults[2], "SYS$SYSROOT:[SYSLIB.]" }, /* VAX-11 "C" includes */
        !           316:     { 0, "" }, /* This makes normal VMS filespecs work OK */
        !           317: #endif /* VMS */
        !           318:   };
        !           319: 
        !           320: struct directory_stack *include = 0;   /* First dir to search */
        !           321:        /* First dir to search for <file> */
        !           322: struct directory_stack *first_bracket_include = 0;
        !           323: struct directory_stack *last_include = 0;      /* Last in chain */
        !           324: 
        !           325: /* Structure allocated for every #define.  For a simple replacement
        !           326:    such as
        !           327:        #define foo bar ,
        !           328:    nargs = -1, the `pattern' list is null, and the expansion is just
        !           329:    the replacement text.  Nargs = 0 means a functionlike macro with no args,
        !           330:    e.g.,
        !           331:        #define getchar() getc (stdin) .
        !           332:    When there are args, the expansion is the replacement text with the
        !           333:    args squashed out, and the reflist is a list describing how to
        !           334:    build the output from the input: e.g., "3 chars, then the 1st arg,
        !           335:    then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
        !           336:    The chars here come from the expansion.  Whatever is left of the
        !           337:    expansion after the last arg-occurrence is copied after that arg.
        !           338:    Note that the reflist can be arbitrarily long---
        !           339:    its length depends on the number of times the arguments appear in
        !           340:    the replacement text, not how many args there are.  Example:
        !           341:    #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
        !           342:    pattern list
        !           343:      { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
        !           344:    where (x, y) means (nchars, argno). */
        !           345: 
        !           346: typedef struct definition DEFINITION;
        !           347: struct definition {
        !           348:   int nargs;
        !           349:   int length;                  /* length of expansion string */
        !           350:   U_CHAR *expansion;
        !           351:   struct reflist {
        !           352:     struct reflist *next;
        !           353:     char stringify;            /* nonzero if this arg was preceded by a
        !           354:                                   # operator. */
        !           355:     char raw_before;           /* Nonzero if a ## operator before arg. */
        !           356:     char raw_after;            /* Nonzero if a ## operator after arg. */
        !           357:     int nchars;                        /* Number of literal chars to copy before
        !           358:                                   this arg occurrence.  */
        !           359:     int argno;                 /* Number of arg to substitute (origin-0) */
        !           360:   } *pattern;
        !           361:   /* Names of macro args, concatenated in reverse order
        !           362:      with comma-space between them.
        !           363:      The only use of this is that we warn on redefinition
        !           364:      if this differs between the old and new definitions.  */
        !           365:   U_CHAR *argnames;
        !           366: };
        !           367: 
        !           368: /* different kinds of things that can appear in the value field
        !           369:    of a hash node.  Actually, this may be useless now. */
        !           370: union hashval {
        !           371:   int ival;
        !           372:   char *cpval;
        !           373:   DEFINITION *defn;
        !           374: };
        !           375: 
        !           376: 
        !           377: /* The structure of a node in the hash table.  The hash table
        !           378:    has entries for all tokens defined by #define commands (type T_MACRO),
        !           379:    plus some special tokens like __LINE__ (these each have their own
        !           380:    type, and the appropriate code is run when that type of node is seen.
        !           381:    It does not contain control words like "#define", which are recognized
        !           382:    by a separate piece of code. */
        !           383: 
        !           384: /* different flavors of hash nodes --- also used in keyword table */
        !           385: enum node_type {
        !           386:  T_DEFINE = 1, /* the `#define' keyword */
        !           387:  T_INCLUDE,    /* the `#include' keyword */
        !           388:  T_IFDEF,      /* the `#ifdef' keyword */
        !           389:  T_IFNDEF,     /* the `#ifndef' keyword */
        !           390:  T_IF,         /* the `#if' keyword */
        !           391:  T_ELSE,       /* `#else' */
        !           392: #if 0
        !           393:  /* cpp can pass #pragma through unchanged.  */
        !           394:  T_PRAGMA,     /* `#pragma' */
        !           395: #endif
        !           396:  T_ELIF,       /* `#else' */
        !           397:  T_UNDEF,      /* `#undef' */
        !           398:  T_LINE,       /* `#line' */
        !           399:  T_ERROR,      /* `#error' */
        !           400:  T_ENDIF,      /* `#endif' */
        !           401:  T_SCCS,       /* `#sccs', used on system V.  */
        !           402:  T_SPECLINE,   /* special symbol `__LINE__' */
        !           403:  T_DATE,       /* `__DATE__' */
        !           404:  T_FILE,       /* `__FILE__' */
        !           405:  T_VERSION,    /* `__VERSION__' */
        !           406:  T_TIME,       /* `__TIME__' */
        !           407:  T_CONST,      /* Constant value, used by `__STDC__' */
        !           408:  T_MACRO,      /* macro defined by `#define' */
        !           409:  T_DISABLED,   /* macro temporarily turned off for rescan */
        !           410:  T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
        !           411:  T_UNUSED      /* Used for something not defined.  */
        !           412:  };
        !           413: 
        !           414: struct hashnode {
        !           415:   struct hashnode *next;       /* double links for easy deletion */
        !           416:   struct hashnode *prev;
        !           417:   struct hashnode **bucket_hdr;        /* also, a back pointer to this node's hash
        !           418:                                   chain is kept, in case the node is the head
        !           419:                                   of the chain and gets deleted. */
        !           420:   enum node_type type;         /* type of special token */
        !           421:   int length;                  /* length of token, for quick comparison */
        !           422:   U_CHAR *name;                        /* the actual name */
        !           423:   union hashval value;         /* pointer to expansion, or whatever */
        !           424: };
        !           425: 
        !           426: typedef struct hashnode HASHNODE;
        !           427: 
        !           428: /* Some definitions for the hash table.  The hash function MUST be
        !           429:    computed as shown in hashf () below.  That is because the rescan
        !           430:    loop computes the hash value `on the fly' for most tokens,
        !           431:    in order to avoid the overhead of a lot of procedure calls to
        !           432:    the hashf () function.  Hashf () only exists for the sake of
        !           433:    politeness, for use when speed isn't so important. */
        !           434: 
        !           435: #define HASHSIZE 1403
        !           436: HASHNODE *hashtab[HASHSIZE];
        !           437: #define HASHSTEP(old, c) ((old << 2) + c)
        !           438: #define MAKE_POS(v) (v & ~0x80000000) /* make number positive */
        !           439: 
        !           440: /* Symbols to predefine.  */
        !           441: 
        !           442: #ifdef CPP_PREDEFINES
        !           443: char *predefs = CPP_PREDEFINES;
        !           444: #else
        !           445: char *predefs = "";
        !           446: #endif
        !           447: 
        !           448: /* `struct directive' defines one #-directive, including how to handle it.  */
        !           449: 
        !           450: struct directive {
        !           451:   int length;                  /* Length of name */
        !           452:   int (*func)();               /* Function to handle directive */
        !           453:   char *name;                  /* Name of directive */
        !           454:   enum node_type type;         /* Code which describes which directive. */
        !           455:   char angle_brackets;         /* Nonzero => don't delete comments.  */
        !           456: };
        !           457: 
        !           458: /* Here is the actual list of #-directives, most-often-used first.  */
        !           459: 
        !           460: struct directive directive_table[] = {
        !           461:   {  6, do_define, "define", T_DEFINE},
        !           462:   {  2, do_if, "if", T_IF},
        !           463:   {  5, do_xifdef, "ifdef", T_IFDEF},
        !           464:   {  6, do_xifdef, "ifndef", T_IFNDEF},
        !           465:   {  5, do_endif, "endif", T_ENDIF},
        !           466:   {  4, do_else, "else", T_ELSE},
        !           467:   {  4, do_elif, "elif", T_ELIF},
        !           468:   {  4, do_line, "line", T_LINE},
        !           469:   {  7, do_include, "include", T_INCLUDE, 1},
        !           470:   {  5, do_undef, "undef", T_UNDEF},
        !           471:   {  5, do_error, "error", T_ERROR},
        !           472: #ifdef SCCS_DIRECTIVE
        !           473:   {  4, do_sccs, "sccs", T_SCCS},
        !           474: #endif
        !           475: #if 0
        !           476:   {  6, do_pragma, "pragma", T_PRAGMA},
        !           477: #endif
        !           478:   {  -1, 0, "", T_UNUSED},
        !           479: };
        !           480: 
        !           481: /* table to tell if char can be part of a C identifier. */
        !           482: U_CHAR is_idchar[256];
        !           483: /* table to tell if char can be first char of a c identifier. */
        !           484: U_CHAR is_idstart[256];
        !           485: /* table to tell if c is horizontal space.  */
        !           486: U_CHAR is_hor_space[256];
        !           487: /* table to tell if c is horizontal or vertical space.  */
        !           488: U_CHAR is_space[256];
        !           489: 
        !           490: #define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
        !           491: #define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
        !           492:   
        !           493: int errors = 0;                        /* Error counter for exit code */
        !           494: 
        !           495: /* Nonzero if have already warned about use of `$'.  */
        !           496: int dollar_seen = 0;
        !           497: 
        !           498: FILE_BUF expand_to_temp_buffer ();
        !           499: 
        !           500: DEFINITION *collect_expansion ();
        !           501: 
        !           502: /* Stack of conditionals currently in progress
        !           503:    (including both successful and failing conditionals).  */
        !           504: 
        !           505: struct if_stack {
        !           506:   struct if_stack *next;       /* for chaining to the next stack frame */
        !           507:   char *fname;         /* copied from input when frame is made */
        !           508:   int lineno;                  /* similarly */
        !           509:   int if_succeeded;            /* true if a leg of this if-group
        !           510:                                    has been passed through rescan */
        !           511:   enum node_type type;         /* type of last directive seen in this group */
        !           512: };
        !           513: typedef struct if_stack IF_STACK_FRAME;
        !           514: IF_STACK_FRAME *if_stack = NULL;
        !           515: 
        !           516: /* Buffer of -M output.  */
        !           517: 
        !           518: char *deps_buffer;
        !           519: 
        !           520: /* Number of bytes allocated in above.  */
        !           521: int deps_allocated_size;
        !           522: 
        !           523: /* Number of bytes used.  */
        !           524: int deps_size;
        !           525: 
        !           526: /* Number of bytes since the last newline.  */
        !           527: int deps_column;
        !           528: 
        !           529: /* Nonzero means -I- has been seen,
        !           530:    so don't look for #include "foo" the source-file directory.  */
        !           531: int ignore_srcdir;
        !           532: 
        !           533: int
        !           534: main (argc, argv)
        !           535:      int argc;
        !           536:      char **argv;
        !           537: {
        !           538:   int st_mode;
        !           539:   long st_size;
        !           540:   char *in_fname, *out_fname;
        !           541:   int f, i;
        !           542:   FILE_BUF *fp;
        !           543:   char **pend_files = (char **) xmalloc (argc * sizeof (char *));
        !           544:   char **pend_defs = (char **) xmalloc (argc * sizeof (char *));
        !           545:   char **pend_undefs = (char **) xmalloc (argc * sizeof (char *));
        !           546:   int inhibit_predefs = 0;
        !           547:   int no_standard_includes = 0;
        !           548: 
        !           549: #ifdef RLIMIT_STACK
        !           550:   /* Get rid of any avoidable limit on stack size.  */
        !           551:   {
        !           552:     struct rlimit rlim;
        !           553: 
        !           554:     /* Set the stack limit huge so that alloca (particularly stringtab
        !           555:      * in dbxread.c) does not fail. */
        !           556:     getrlimit (RLIMIT_STACK, &rlim);
        !           557:     rlim.rlim_cur = rlim.rlim_max;
        !           558:     setrlimit (RLIMIT_STACK, &rlim);
        !           559:   }
        !           560: #endif /* RLIMIT_STACK defined */
        !           561: 
        !           562:   progname = argv[0];
        !           563:   in_fname = NULL;
        !           564:   out_fname = NULL;
        !           565:   initialize_random_junk ();
        !           566: 
        !           567:   no_line_commands = 0;
        !           568:   no_trigraphs = 1;
        !           569:   dump_macros = 0;
        !           570:   no_output = 0;
        !           571: 
        !           572:   bzero (pend_files, argc * sizeof (char *));
        !           573:   bzero (pend_defs, argc * sizeof (char *));
        !           574:   bzero (pend_undefs, argc * sizeof (char *));
        !           575: 
        !           576:   /* Process switches and find input file name.  */
        !           577: 
        !           578:   for (i = 1; i < argc; i++) {
        !           579:     if (argv[i][0] != '-') {
        !           580:       if (out_fname != NULL)
        !           581:        fatal ("Usage: %s [switches] input output\n", argv[0]);
        !           582:       else if (in_fname != NULL) {
        !           583:        out_fname = argv[i];
        !           584:        if (! freopen (out_fname, "w", stdout))
        !           585:          pfatal_with_name (out_fname);
        !           586:       } else
        !           587:        in_fname = argv[i];
        !           588:     } else {
        !           589:       switch (argv[i][1]) {
        !           590: 
        !           591:       case 'i':
        !           592:        if (argv[i][2] != 0)
        !           593:          pend_files[i] = argv[i] + 2;
        !           594:        else
        !           595:          pend_files[i] = argv[i+1], i++;
        !           596:        break;
        !           597: 
        !           598:       case 'o':
        !           599:        if (out_fname != NULL)
        !           600:          fatal ("Output filename specified twice\n");
        !           601:        out_fname = argv[++i];
        !           602:        if (! freopen (out_fname, "w", stdout))
        !           603:          pfatal_with_name (out_fname);
        !           604:        break;
        !           605: 
        !           606:       case 'p':
        !           607:        pedantic = 1;
        !           608:        break;
        !           609: 
        !           610:       case 't':
        !           611:        traditional = 1;
        !           612:        break;
        !           613: 
        !           614:       case 'W':
        !           615:        warn_comments = 1;
        !           616:        break;
        !           617: 
        !           618:       case 'M':
        !           619:        if (!strcmp (argv[i], "-M"))
        !           620:          print_deps = 2;
        !           621:        else if (!strcmp (argv[i], "-MM"))
        !           622:          print_deps = 1;
        !           623:        deps_allocated_size = 200;
        !           624:        deps_buffer = (char *) xmalloc (deps_allocated_size);
        !           625:        deps_buffer[0] = 0;
        !           626:        deps_size = 0;
        !           627:        deps_column = 0;
        !           628: 
        !           629:        break;
        !           630: 
        !           631:       case 'd':
        !           632:        dump_macros = 1;
        !           633:        no_output = 1;
        !           634:        break;
        !           635: 
        !           636:       case 'v':
        !           637:        {
        !           638:          fprintf (stderr, "GNU CPP version %s\n", version_string);
        !           639:        }
        !           640:        break;
        !           641: 
        !           642:       case 'D':
        !           643:        {
        !           644:          char *p, *p1;
        !           645: 
        !           646:          if (argv[i][2] != 0)
        !           647:            p = argv[i] + 2;
        !           648:          else
        !           649:            p = argv[++i];
        !           650: 
        !           651:          if ((p1 = (char *) index (p, '=')) != NULL)
        !           652:            *p1 = ' ';
        !           653:          pend_defs[i] = p;
        !           654:        }
        !           655:        break;
        !           656: 
        !           657:       case 'U':                /* JF #undef something */
        !           658:        if (argv[i][2] != 0)
        !           659:          pend_undefs[i] = argv[i] + 2;
        !           660:        else
        !           661:          pend_undefs[i] = argv[i+1], i++;
        !           662:        break;
        !           663: 
        !           664:       case 'C':
        !           665:        put_out_comments = 1;
        !           666:        break;
        !           667: 
        !           668:       case 'E':                        /* -E comes from cc -E; ignore it.  */
        !           669:        break;
        !           670: 
        !           671:       case 'P':
        !           672:        no_line_commands = 1;
        !           673:        break;
        !           674: 
        !           675:       case 'T':                        /* Enable ANSI trigraphs */
        !           676:        no_trigraphs = 0;
        !           677:        break;
        !           678: 
        !           679:       case 'I':                        /* Add directory to path for includes.  */
        !           680:        {
        !           681:          struct directory_stack *dirtmp;
        !           682: 
        !           683:          if (! ignore_srcdir && !strcmp (argv[i] + 2, "-"))
        !           684:            ignore_srcdir;
        !           685:          else {
        !           686:            dirtmp = (struct directory_stack *)
        !           687:              xmalloc (sizeof (struct directory_stack));
        !           688:            dirtmp->next = 0;           /* New one goes on the end */
        !           689:            if (include == 0)
        !           690:              include = dirtmp;
        !           691:            else
        !           692:              last_include->next = dirtmp;
        !           693:            last_include = dirtmp;      /* Tail follows the last one */
        !           694:            if (argv[i][2] != 0)
        !           695:              dirtmp->fname = argv[i] + 2;
        !           696:            else
        !           697:              dirtmp->fname = argv[++i];
        !           698:            if (strlen (dirtmp->fname) > max_include_len)
        !           699:              max_include_len = strlen (dirtmp->fname);
        !           700:            if (ignore_srcdir && first_bracket_include == 0)
        !           701:              first_bracket_include = dirtmp;
        !           702:            }
        !           703:        }
        !           704:        break;
        !           705: 
        !           706:       case 'n':
        !           707:        /* -nostdinc causes no default include directories.
        !           708:           You must specify all include-file directories with -I.  */
        !           709:        no_standard_includes = 1;
        !           710:        break;
        !           711: 
        !           712:       case 'u':
        !           713:        /* Sun compiler passes undocumented switch "-undef".
        !           714:           Let's assume it means to inhibit the predefined symbols.  */
        !           715:        inhibit_predefs = 1;
        !           716:        break;
        !           717: 
        !           718:       case '\0': /* JF handle '-' as file name meaning stdin or stdout */
        !           719:        if (in_fname == NULL) {
        !           720:          in_fname = "";
        !           721:          break;
        !           722:        } else if (out_fname == NULL) {
        !           723:          out_fname = "stdout";
        !           724:          break;
        !           725:        }       /* else fall through into error */
        !           726: 
        !           727:       default:
        !           728:        fatal ("Invalid option `%s'\n", argv[i]);
        !           729:       }
        !           730:     }
        !           731:   }
        !           732: 
        !           733:   /* Do standard #defines that identify processor type.  */
        !           734: 
        !           735:   if (!inhibit_predefs) {
        !           736:     char *p = (char *) alloca (strlen (predefs) + 1);
        !           737:     strcpy (p, predefs);
        !           738:     while (*p) {
        !           739:       char *q;
        !           740:       if (p[0] != '-' || p[1] != 'D')
        !           741:        abort ();
        !           742:       q = &p[2];
        !           743:       while (*p && *p != ' ') p++;
        !           744:       if (*p != 0)
        !           745:        *p++= 0;
        !           746:       make_definition (q);
        !           747:     }
        !           748:   }
        !           749: 
        !           750:   /* Do defines specified with -D.  */
        !           751:   for (i = 1; i < argc; i++)
        !           752:     if (pend_defs[i])
        !           753:       make_definition (pend_defs[i]);
        !           754: 
        !           755:   /* Do undefines specified with -U.  */
        !           756:   for (i = 1; i < argc; i++)
        !           757:     if (pend_undefs[i])
        !           758:       make_undef (pend_undefs[i]);
        !           759: 
        !           760:   /* Unless -fnostdinc,
        !           761:      tack on the standard include file dirs to the specified list */
        !           762:   if (!no_standard_includes) {
        !           763:     if (include == 0)
        !           764:       include = include_defaults;
        !           765:     else
        !           766:       last_include->next = include_defaults;
        !           767:   }
        !           768: 
        !           769:   /* Initialize output buffer */
        !           770: 
        !           771:   outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
        !           772:   outbuf.bufp = outbuf.buf;
        !           773:   outbuf.length = OUTBUF_SIZE;
        !           774: 
        !           775:   /* Scan the -i files before the main input.
        !           776:      Much like #including them, but with no_output set
        !           777:      so that only their macro definitions matter.  */
        !           778: 
        !           779:   no_output++;
        !           780:   for (i = 1; i < argc; i++)
        !           781:     if (pend_files[i]) {
        !           782:       int fd = open (pend_files[i], O_RDONLY, 0666);
        !           783:       if (fd < 0) {
        !           784:        perror_with_name (pend_files[i]);
        !           785:        return FATAL_EXIT_CODE;
        !           786:       }
        !           787:       finclude (fd, pend_files[i], &outbuf);
        !           788:     }
        !           789:   no_output--;
        !           790: 
        !           791:   /* Create an input stack level for the main input file
        !           792:      and copy the entire contents of the file into it.  */
        !           793: 
        !           794:   fp = &instack[++indepth];
        !           795: 
        !           796:   /* JF check for stdin */
        !           797:   if (in_fname == NULL || *in_fname == 0) {
        !           798:     in_fname = "";
        !           799:     f = 0;
        !           800:   } else if ((f = open (in_fname, O_RDONLY)) < 0)
        !           801:     goto perror;
        !           802: 
        !           803:   /* For -M, print the expected object file name
        !           804:      as the target of this Make-rule.  */
        !           805:   if (print_deps) {
        !           806:     if (*in_fname == 0)
        !           807:       deps_output ("-: ", 0);
        !           808:     else {
        !           809:       int len;
        !           810:       char *p = in_fname;
        !           811:       char *p1 = p;
        !           812:       /* Discard all directory prefixes from P.  */
        !           813:       while (*p1)
        !           814:        {
        !           815:          if (*p1 == '/')
        !           816:            p = p1;
        !           817:          p1++;
        !           818:        }
        !           819:       /* Output P, but remove known suffixes.  */
        !           820:       len = strlen (p);
        !           821:       if (p[len - 2] == '.' && p[len - 1] == 'c')
        !           822:        deps_output (p, len - 2);
        !           823:       else if (p[len - 3] == '.'
        !           824:               && p[len - 2] == 'c'
        !           825:               && p[len - 1] == 'c')
        !           826:        deps_output (p, len - 3);
        !           827:       else
        !           828:        deps_output (p, 0);
        !           829:       /* Supply our own suffix.  */
        !           830:       deps_output (".o : ", 0);
        !           831:       deps_output (in_fname, 0);
        !           832:       deps_output (" ", 0);
        !           833:     }
        !           834:   }
        !           835: 
        !           836:   file_size_and_mode (f, &st_mode, &st_size);
        !           837:   fp->fname = in_fname;
        !           838:   fp->lineno = 1;
        !           839:   /* JF all this is mine about reading pipes and ttys */
        !           840:   if ((st_mode & S_IFMT) != S_IFREG) {
        !           841:     /* Read input from a file that is not a normal disk file.
        !           842:        We cannot preallocate a buffer with the correct size,
        !           843:        so we must read in the file a piece at the time and make it bigger.  */
        !           844:     int size;
        !           845:     int bsize;
        !           846:     int cnt;
        !           847:     U_CHAR *bufp;
        !           848: 
        !           849:     bsize = 2000;
        !           850:     size = 0;
        !           851:     fp->buf = (U_CHAR *) xmalloc (bsize + 2);
        !           852:     bufp = fp->buf;
        !           853:     for (;;) {
        !           854:       cnt = read (f, bufp, bsize - size);
        !           855:       if (cnt < 0) goto perror;        /* error! */
        !           856:       if (cnt == 0) break;     /* End of file */
        !           857:       size += cnt;
        !           858:       bufp += cnt;
        !           859:       if (bsize == size) {     /* Buffer is full! */
        !           860:         bsize *= 2;
        !           861:         fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
        !           862:        bufp = fp->buf + size;  /* May have moved */
        !           863:       }
        !           864:     }
        !           865:     fp->length = size;
        !           866:   } else {
        !           867:     /* Read a file whose size we can determine in advance.
        !           868:        For the sake of VMS, st_size is just an upper bound.  */
        !           869:     long i;
        !           870:     fp->length = 0;
        !           871:     fp->buf = (U_CHAR *) xmalloc (st_size + 2);
        !           872: 
        !           873:     while (st_size > 0) {
        !           874:       i = read (f, fp->buf + fp->length, st_size);
        !           875:       if (i <= 0) {
        !           876:         if (i == 0) break;
        !           877:        goto perror;
        !           878:       }
        !           879:       fp->length += i;
        !           880:       st_size -= i;
        !           881:     }
        !           882:   }
        !           883:   fp->bufp = fp->buf;
        !           884:   fp->if_stack = if_stack;
        !           885: 
        !           886:   /* Unless inhibited, convert trigraphs in the input.  */
        !           887: 
        !           888:   if (!no_trigraphs)
        !           889:     trigraph_pcp (fp);
        !           890: 
        !           891:   /* Make sure data ends with a newline.  And put a null after it.  */
        !           892: 
        !           893:   if (fp->length > 0 && fp->buf[fp->length-1] != '\n')
        !           894:     fp->buf[fp->length++] = '\n';
        !           895:   fp->buf[fp->length] = '\0';
        !           896: 
        !           897:   output_line_command (fp, &outbuf, 0);
        !           898: 
        !           899:   /* Scan the input, processing macros and directives.  */
        !           900: 
        !           901:   rescan (&outbuf, 0);
        !           902: 
        !           903:   /* Now we have processed the entire input
        !           904:      Write whichever kind of output has been requested.  */
        !           905: 
        !           906: 
        !           907:   if (dump_macros)
        !           908:     dump_all_macros ();
        !           909:   else if (print_deps)
        !           910:     puts (deps_buffer);
        !           911:   else if (write (fileno (stdout), outbuf.buf, outbuf.bufp - outbuf.buf) < 0)
        !           912:     fatal ("I/O error on output");
        !           913: 
        !           914:   if (ferror (stdout))
        !           915:     fatal ("I/O error on output");
        !           916: 
        !           917:   if (errors)
        !           918:     exit (FATAL_EXIT_CODE);
        !           919:   exit (SUCCESS_EXIT_CODE);
        !           920: 
        !           921:  perror:
        !           922:   pfatal_with_name (in_fname);
        !           923: }
        !           924: 
        !           925: /* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF
        !           926:    before main CCCP processing.  Name `pcp' is also in honor of the
        !           927:    drugs the trigraph designers must have been on.
        !           928: 
        !           929:    Using an extra pass through the buffer takes a little extra time,
        !           930:    but is infinitely less hairy than trying to handle ??/" inside
        !           931:    strings, etc. everywhere, and also makes sure that trigraphs are
        !           932:    only translated in the top level of processing. */
        !           933: 
        !           934: trigraph_pcp (buf)
        !           935:      FILE_BUF *buf;
        !           936: {
        !           937:   register U_CHAR c, *fptr, *bptr, *sptr;
        !           938:   int len;
        !           939: 
        !           940:   fptr = bptr = sptr = buf->buf;
        !           941:   while ((sptr = (U_CHAR *) index (sptr, '?')) != NULL) {
        !           942:     if (*++sptr != '?')
        !           943:       continue;
        !           944:     switch (*++sptr) {
        !           945:       case '=':
        !           946:       c = '#';
        !           947:       break;
        !           948:     case '(':
        !           949:       c = '[';
        !           950:       break;
        !           951:     case '/':
        !           952:       c = '\\';
        !           953:       break;
        !           954:     case ')':
        !           955:       c = ']';
        !           956:       break;
        !           957:     case '\'':
        !           958:       c = '^';
        !           959:       break;
        !           960:     case '<':
        !           961:       c = '{';
        !           962:       break;
        !           963:     case '!':
        !           964:       c = '|';
        !           965:       break;
        !           966:     case '>':
        !           967:       c = '}';
        !           968:       break;
        !           969:     case '-':
        !           970:       c  = '~';
        !           971:       break;
        !           972:     case '?':
        !           973:       sptr--;
        !           974:       continue;
        !           975:     default:
        !           976:       continue;
        !           977:     }
        !           978:     len = sptr - fptr - 2;
        !           979:     if (bptr != fptr && len > 0)
        !           980:       bcopy (fptr, bptr, len); /* BSD doc says bcopy () works right
        !           981:                                   for overlapping strings.  In ANSI
        !           982:                                   C, this will be memmove (). */
        !           983:     bptr += len;
        !           984:     *bptr++ = c;
        !           985:     fptr = ++sptr;
        !           986:   }
        !           987:   len = buf->length - (fptr - buf->buf);
        !           988:   if (bptr != fptr && len > 0)
        !           989:     bcopy (fptr, bptr, len);
        !           990:   buf->length -= fptr - bptr;
        !           991:   buf->buf[buf->length] = '\0';
        !           992: }
        !           993: 
        !           994: /* Move all backslash-newline pairs out of embarrassing places.
        !           995:    Exchange all such pairs following BP
        !           996:    with any potentially-embarrasing characters that follow them.
        !           997:    Potentially-embarrassing characters are / and *
        !           998:    (because a backslash-newline inside a comment delimiter
        !           999:    would cause it not to be recognized).  */
        !          1000: 
        !          1001: newline_fix (bp)
        !          1002:      U_CHAR *bp;
        !          1003: {
        !          1004:   register U_CHAR *p = bp;
        !          1005:   register int count = 0;
        !          1006: 
        !          1007:   /* First count the backslash-newline pairs here.  */
        !          1008: 
        !          1009:   while (*p++ == '\\' && *p++ == '\n')
        !          1010:     count++;
        !          1011: 
        !          1012:   p = bp + count * 2;
        !          1013: 
        !          1014:   /* What follows the backslash-newlines is not embarrassing.  */
        !          1015: 
        !          1016:   if (count == 0 || (*p != '/' && *p != '*'))
        !          1017:     return;
        !          1018: 
        !          1019:   /* Copy all potentially embarrassing characters
        !          1020:      that follow the backslash-newline pairs
        !          1021:      down to where the pairs originally started.  */
        !          1022: 
        !          1023:   while (*p == '*' || *p == '/')
        !          1024:     *bp++ = *p++;
        !          1025: 
        !          1026:   /* Now write the same number of pairs after the embarrassing chars.  */
        !          1027:   while (count-- > 0) {
        !          1028:     *bp++ = '\\';
        !          1029:     *bp++ = '\n';
        !          1030:   }
        !          1031: }
        !          1032: 
        !          1033: /* Like newline_fix but for use within a directive-name.
        !          1034:    Move any backslash-newlines up past any following symbol constituents.  */
        !          1035: 
        !          1036: name_newline_fix (bp)
        !          1037:      U_CHAR *bp;
        !          1038: {
        !          1039:   register U_CHAR *p = bp;
        !          1040:   register int count = 0;
        !          1041: 
        !          1042:   /* First count the backslash-newline pairs here.  */
        !          1043: 
        !          1044:   while (*p++ == '\\' && *p++ == '\n')
        !          1045:     count++;
        !          1046: 
        !          1047:   p = bp + count * 2;
        !          1048: 
        !          1049:   /* What follows the backslash-newlines is not embarrassing.  */
        !          1050: 
        !          1051:   if (count == 0 || !is_idchar[*p])
        !          1052:     return;
        !          1053: 
        !          1054:   /* Copy all potentially embarrassing characters
        !          1055:      that follow the backslash-newline pairs
        !          1056:      down to where the pairs originally started.  */
        !          1057: 
        !          1058:   while (is_idchar[*p])
        !          1059:     *bp++ = *p++;
        !          1060: 
        !          1061:   /* Now write the same number of pairs after the embarrassing chars.  */
        !          1062:   while (count-- > 0) {
        !          1063:     *bp++ = '\\';
        !          1064:     *bp++ = '\n';
        !          1065:   }
        !          1066: }
        !          1067: 
        !          1068: /*
        !          1069:  * The main loop of the program.
        !          1070:  *
        !          1071:  * Read characters from the input stack, transferring them to the
        !          1072:  * output buffer OP.
        !          1073:  *
        !          1074:  * Macros are expanded and push levels on the input stack.
        !          1075:  * At the end of such a level it is popped off and we keep reading.
        !          1076:  * At the end of any other kind of level, we return.
        !          1077:  * #-directives are handled, except within macros.
        !          1078:  *
        !          1079:  * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input
        !          1080:  * and insert them when appropriate.  This is set while scanning macro
        !          1081:  * arguments before substitution.  It is zero when scanning for final output.
        !          1082:  *   There are three types of Newline markers:
        !          1083:  *   * Newline -  follows a macro name that was not expanded
        !          1084:  *     because it appeared inside an expansion of the same macro.
        !          1085:  *     This marker prevents future expansion of that identifier.
        !          1086:  *     When the input is rescanned into the final output, these are deleted.
        !          1087:  *     These are also deleted by ## concatenation.
        !          1088:  *   * Newline Space (or Newline and any other whitespace character)
        !          1089:  *     stands for a place that tokens must be separated or whitespace
        !          1090:  *     is otherwise desirable, but where the ANSI standard specifies there
        !          1091:  *     is no whitespace.  This marker turns into a Space (or whichever other
        !          1092:  *     whitespace char appears in the marker) in the final output,
        !          1093:  *     but it turns into nothing in an argument that is stringified with #.
        !          1094:  *     Such stringified arguments are the only place where the ANSI standard
        !          1095:  *     specifies with precision that whitespace may not appear.
        !          1096:  *
        !          1097:  * During this function, IP->bufp is kept cached in IBP for speed of access.
        !          1098:  * Likewise, OP->bufp is kept in OBP.  Before calling a subroutine
        !          1099:  * IBP, IP and OBP must be copied back to memory.  IP and IBP are
        !          1100:  * copied back with the RECACHE macro.  OBP must be copied back from OP->bufp
        !          1101:  * explicitly, and before RECACHE, since RECACHE uses OBP.
        !          1102:  */
        !          1103: 
        !          1104: rescan (op, output_marks)
        !          1105:      FILE_BUF *op;
        !          1106:      int output_marks;
        !          1107: {
        !          1108:   /* Character being scanned in main loop.  */
        !          1109:   register U_CHAR c;
        !          1110: 
        !          1111:   /* Length of pending accumulated identifier.  */
        !          1112:   register int ident_length = 0;
        !          1113: 
        !          1114:   /* Hash code of pending accumulated identifier.  */
        !          1115:   register int hash = 0;
        !          1116: 
        !          1117:   /* Current input level (&instack[indepth]).  */
        !          1118:   FILE_BUF *ip;
        !          1119: 
        !          1120:   /* Pointer for scanning input.  */
        !          1121:   register U_CHAR *ibp;
        !          1122: 
        !          1123:   /* Pointer to end of input.  End of scan is controlled by LIMIT.  */
        !          1124:   register U_CHAR *limit;
        !          1125: 
        !          1126:   /* Pointer for storing output.  */
        !          1127:   register U_CHAR *obp;
        !          1128: 
        !          1129:   /* REDO_CHAR is nonzero if we are processing an identifier
        !          1130:      after backing up over the terminating character.
        !          1131:      Sometimes we process an identifier without backing up over
        !          1132:      the terminating character, if the terminating character
        !          1133:      is not special.  Backing up is done so that the terminating character
        !          1134:      will be dispatched on again once the identifier is dealt with.  */
        !          1135:   int redo_char = 0;
        !          1136: 
        !          1137:   /* 1 if within an identifier inside of which a concatenation
        !          1138:      marker (Newline -) has been seen.  */
        !          1139:   int concatenated = 0;
        !          1140: 
        !          1141:   /* While scanning a comment or a string constant,
        !          1142:      this records the line it started on, for error messages.  */
        !          1143:   int start_line;
        !          1144: 
        !          1145:   /* Record position of last `real' newline.  */
        !          1146:   U_CHAR *beg_of_line;
        !          1147: 
        !          1148: /* Pop the innermost input stack level, assuming it is a macro expansion.  */
        !          1149: 
        !          1150: #define POPMACRO \
        !          1151: do { ip->macro->type = T_MACRO;                \
        !          1152:      if (ip->free) free (ip->free);    \
        !          1153:      --indepth; } while (0)
        !          1154: 
        !          1155: /* Reload `rescan's local variables that describe the current
        !          1156:    level of the input stack.  */
        !          1157: 
        !          1158: #define RECACHE  \
        !          1159: do { ip = &instack[indepth];           \
        !          1160:      ibp = ip->bufp;                   \
        !          1161:      limit = ip->buf + ip->length;     \
        !          1162:      op->bufp = obp;                   \
        !          1163:      check_expand (op, limit - ibp);   \
        !          1164:      beg_of_line = 0;                  \
        !          1165:      obp = op->bufp; } while (0)
        !          1166: 
        !          1167:   if (no_output && instack[indepth].fname != 0)
        !          1168:     skip_if_group (&instack[indepth], 1);
        !          1169: 
        !          1170:   obp = op->bufp;
        !          1171:   RECACHE;
        !          1172:   beg_of_line = ibp;
        !          1173: 
        !          1174:   /* Our caller must always put a null after the end of
        !          1175:      the input at each input stack level.  */
        !          1176:   if (*limit != 0)
        !          1177:     abort ();
        !          1178: 
        !          1179:   while (1) {
        !          1180:     c = *ibp++;
        !          1181:     *obp++ = c;
        !          1182: 
        !          1183:     switch (c) {
        !          1184:     case '\\':
        !          1185:       if (ibp >= limit)
        !          1186:        break;
        !          1187:       if (*ibp == '\n') {
        !          1188:        /* Always merge lines ending with backslash-newline,
        !          1189:           even in middle of identifier.  */
        !          1190:        ++ibp;
        !          1191:        ++ip->lineno;
        !          1192:        --obp;          /* remove backslash from obuf */
        !          1193:        break;
        !          1194:       }
        !          1195:       /* Otherwise, backslash suppresses specialness of following char,
        !          1196:         so copy it here to prevent the switch from seeing it.
        !          1197:         But first get any pending identifier processed.  */
        !          1198:       if (ident_length > 0)
        !          1199:        goto specialchar;
        !          1200:       *obp++ = *ibp++;
        !          1201:       break;
        !          1202: 
        !          1203:     case '#':
        !          1204:       /* If this is expanding a macro definition, don't recognize
        !          1205:         preprocessor directives.  */
        !          1206:       if (ip->macro != 0)
        !          1207:        goto randomchar;
        !          1208:       if (ident_length)
        !          1209:        goto specialchar;
        !          1210: 
        !          1211:       /* # keyword: a # must be first nonblank char on the line */
        !          1212:       if (beg_of_line == 0)
        !          1213:        goto randomchar;
        !          1214:       {
        !          1215:        U_CHAR *bp;
        !          1216: 
        !          1217:        /* Scan from start of line, skipping whitespace, comments
        !          1218:           and backslash-newlines, and see if we reach this #.
        !          1219:           If not, this # is not special.  */
        !          1220:        bp = beg_of_line;
        !          1221:        while (1) {
        !          1222:          if (is_hor_space[*bp])
        !          1223:            bp++;
        !          1224:          else if (*bp == '\\' && bp[1] == '\n')
        !          1225:            bp += 2;
        !          1226:          else if (*bp == '/' && bp[1] == '*') {
        !          1227:            bp += 2;
        !          1228:            while (!(*bp == '*' && bp[1] == '/'))
        !          1229:              bp++;
        !          1230:            bp += 2;
        !          1231:          }
        !          1232: #ifdef CPLUSPLUS
        !          1233:          else if (*bp == '/' && bp[1] == '/') {
        !          1234:            bp += 2;
        !          1235:            while (*bp++ != '\n') ;
        !          1236:          }
        !          1237: #endif
        !          1238:          else break;
        !          1239:        }
        !          1240:        if (bp + 1 != ibp)
        !          1241:          goto randomchar;
        !          1242:       }
        !          1243: 
        !          1244:       /* This # can start a directive.  */
        !          1245: 
        !          1246:       --obp;           /* Don't copy the '#' */
        !          1247: 
        !          1248:       ip->bufp = ibp;
        !          1249:       op->bufp = obp;
        !          1250:       if (! handle_directive (ip, op)) {
        !          1251:        /* Not a known directive: treat it as ordinary text.
        !          1252:           IP, OP, IBP, etc. have not been changed.  */
        !          1253:        if (no_output && instack[indepth].fname) {
        !          1254:          /* If not generating expanded output,
        !          1255:             what we do with ordinary text is skip it.
        !          1256:             Discard everything until next # directive.  */
        !          1257:          skip_if_group (&instack[indepth], 1);
        !          1258:          RECACHE;
        !          1259:          beg_of_line = ibp;
        !          1260:          break;
        !          1261:        }
        !          1262:        ++obp;          /* Copy the '#' after all */
        !          1263:        goto randomchar;
        !          1264:       }
        !          1265:       /* A # directive has been successfully processed.  */
        !          1266:       /* If not generating expanded output, ignore everything until
        !          1267:         next # directive.  */
        !          1268:       if (no_output && instack[indepth].fname)
        !          1269:        skip_if_group (&instack[indepth], 1);
        !          1270:       obp = op->bufp;
        !          1271:       RECACHE;
        !          1272:       beg_of_line = ibp;
        !          1273:       break;
        !          1274: 
        !          1275:     case '\"':                 /* skip quoted string */
        !          1276:     case '\'':
        !          1277:       /* A single quoted string is treated like a double -- some
        !          1278:         programs (e.g., troff) are perverse this way */
        !          1279: 
        !          1280:       if (ident_length)
        !          1281:        goto specialchar;
        !          1282: 
        !          1283:       start_line = ip->lineno;
        !          1284: 
        !          1285:       /* Skip ahead to a matching quote.  */
        !          1286: 
        !          1287:       while (1) {
        !          1288:        if (ibp >= limit)
        !          1289:          {
        !          1290:            error_with_line (line_for_error (start_line),
        !          1291:                             "unterminated string constant");
        !          1292:            break;
        !          1293:          }
        !          1294:        *obp++ = *ibp;
        !          1295:        switch (*ibp++) {
        !          1296:        case '\n':
        !          1297:          ++ip->lineno;
        !          1298:          ++op->lineno;
        !          1299:          break;
        !          1300: 
        !          1301:        case '\\':
        !          1302:          if (ibp >= limit)
        !          1303:            break;
        !          1304:          if (*ibp == '\n')
        !          1305:            {
        !          1306:              /* Backslash newline is replaced by nothing at all,
        !          1307:                 but keep the line counts correct.  */
        !          1308:              --obp;
        !          1309:              ++ibp;
        !          1310:              ++ip->lineno;
        !          1311:            }
        !          1312:          else {
        !          1313:            /* ANSI stupidly requires that in \\ the second \
        !          1314:               is *not* prevented from combining with a newline.  */
        !          1315:            while (*ibp == '\\' && ibp[1] == '\n') {
        !          1316:              ibp += 2;
        !          1317:              ++ip->lineno;
        !          1318:            }
        !          1319:            *obp++ = *ibp++;
        !          1320:          }
        !          1321:          break;
        !          1322: 
        !          1323:        case '\"':
        !          1324:        case '\'':
        !          1325:          if (ibp[-1] == c)
        !          1326:            goto while2end;
        !          1327:          break;
        !          1328:        }
        !          1329:       }
        !          1330:     while2end:
        !          1331:       break;
        !          1332: 
        !          1333:     case '/':
        !          1334:       if (*ibp == '\\' && ibp[1] == '\n')
        !          1335:        newline_fix (ibp);
        !          1336: #ifdef CPLUSPLUS
        !          1337:       if (*ibp == '/')
        !          1338:        {
        !          1339:          /* C++ style comment... */
        !          1340:          start_line = ip->lineno;
        !          1341: 
        !          1342:          --ibp;                /* Back over the slash */
        !          1343:          --obp;
        !          1344: 
        !          1345:          /* Comments are equivalent to spaces. */
        !          1346:          if (! put_out_comments)
        !          1347:            *obp++ = ' ';
        !          1348:          else {
        !          1349:            /* must fake up a comment here */
        !          1350:            *obp++ = '/';
        !          1351:            *obp++ = '/';
        !          1352:          }
        !          1353:          {
        !          1354:            U_CHAR *before_bp = ibp+2;
        !          1355: 
        !          1356:            while (ibp < limit) {
        !          1357:              if (*ibp++ == '\n') {
        !          1358:                ibp--;
        !          1359:                if (put_out_comments) {
        !          1360:                  bcopy (before_bp, obp, ibp - before_bp);
        !          1361:                  obp += ibp - before_bp;
        !          1362:                }
        !          1363:                break;
        !          1364:              }
        !          1365:            }
        !          1366:            break;
        !          1367:          }
        !          1368:        }
        !          1369: #endif
        !          1370:       if (*ibp != '*')
        !          1371:        goto randomchar;
        !          1372:       if (ip->macro != 0)
        !          1373:        goto randomchar;
        !          1374:       if (ident_length)
        !          1375:        goto specialchar;
        !          1376: 
        !          1377:       /* We have a comment.  Skip it, optionally copying it to output.  */
        !          1378: 
        !          1379:       start_line = ip->lineno;
        !          1380: 
        !          1381:       ++ibp;                   /* Skip the star. */
        !          1382: 
        !          1383:       /* Comments are equivalent to spaces.
        !          1384:         Note that we already output the slash; we might not want it.
        !          1385:         For -traditional, a comment is equivalent to nothing.  */
        !          1386:       if (! put_out_comments)
        !          1387:        {
        !          1388:          if (traditional)
        !          1389:            obp--;
        !          1390:          else
        !          1391:            obp[-1] = ' ';
        !          1392:        }
        !          1393:       else
        !          1394:        *obp++ = '*';
        !          1395: 
        !          1396:       {
        !          1397:        U_CHAR *before_bp = ibp;
        !          1398: 
        !          1399:        while (ibp < limit) {
        !          1400:          switch (*ibp++) {
        !          1401:          case '/':
        !          1402:            if (warn_comments && ibp < limit && *ibp == '*')
        !          1403:              warning("`/*' within comment");
        !          1404:            break;
        !          1405:          case '*':
        !          1406:            if (*ibp == '\\' && ibp[1] == '\n')
        !          1407:              newline_fix (ibp);
        !          1408:            if (ibp >= limit || *ibp == '/')
        !          1409:              goto comment_end;
        !          1410:            break;
        !          1411:          case '\n':
        !          1412:            ++ip->lineno;
        !          1413:            /* Copy the newline into the output buffer, in order to
        !          1414:               avoid the pain of a #line every time a multiline comment
        !          1415:               is seen.  */
        !          1416:            if (!put_out_comments)
        !          1417:              *obp++ = '\n';
        !          1418:            ++op->lineno;
        !          1419:          }
        !          1420:        }
        !          1421:       comment_end:
        !          1422: 
        !          1423:        if (ibp >= limit)
        !          1424:          error_with_line (line_for_error (start_line),
        !          1425:                           "unterminated comment");
        !          1426:        else {
        !          1427:          ibp++;
        !          1428:          if (put_out_comments) {
        !          1429:            bcopy (before_bp, obp, ibp - before_bp);
        !          1430:            obp += ibp - before_bp;
        !          1431:          }
        !          1432:        }
        !          1433:       }
        !          1434:       break;
        !          1435: 
        !          1436:     case '$':
        !          1437:       if (pedantic)
        !          1438:        {
        !          1439:          if (! dollar_seen)
        !          1440:            warning ("ANSI C forbids `$' in identifier (first use here)");
        !          1441:          dollar_seen = 1;
        !          1442:        }
        !          1443:       goto letter;
        !          1444: 
        !          1445:     case '0': case '1': case '2': case '3': case '4':
        !          1446:     case '5': case '6': case '7': case '8': case '9':
        !          1447:       /* If digit is not part of identifier, it starts a number,
        !          1448:         which means that following letters are not an identifier.
        !          1449:         "0x5" does not refer to an identifier "x5".
        !          1450:         So copy all alphanumerics that follow without accumulating
        !          1451:         as an identifier.  Periods also, for sake of "3.e7".  */
        !          1452: 
        !          1453:       if (ident_length == 0) {
        !          1454:        while (ibp < limit) {
        !          1455:          c = *ibp++;
        !          1456:          if (!isalnum (c) && c != '.') {
        !          1457:            --ibp;
        !          1458:            break;
        !          1459:          }
        !          1460:          *obp++ = c;
        !          1461:        }
        !          1462:        break;
        !          1463:       }
        !          1464:       /* fall through */
        !          1465: 
        !          1466:     case '_':
        !          1467:     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
        !          1468:     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
        !          1469:     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
        !          1470:     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
        !          1471:     case 'y': case 'z':
        !          1472:     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        !          1473:     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
        !          1474:     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
        !          1475:     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
        !          1476:     case 'Y': case 'Z':
        !          1477:     letter:
        !          1478:       ident_length++;
        !          1479:       /* Compute step of hash function, to avoid a proc call on every token */
        !          1480:       hash = HASHSTEP (hash, c);
        !          1481:       break;
        !          1482: 
        !          1483:     case '\n':
        !          1484:       /* If reprocessing a macro expansion, newline is a special marker.  */
        !          1485:       if (ip->macro != 0) {
        !          1486:        /* Newline White is a "funny space" to separate tokens that are
        !          1487:           supposed to be separate but without space between.
        !          1488:           Here While means any horizontal whitespace character.
        !          1489:           Newline - marks a recursive macro use that is not
        !          1490:           supposed to be expandable.  */
        !          1491: 
        !          1492:        if (*ibp == '-') {
        !          1493:          /* Newline - inhibits expansion of preceding token.
        !          1494:             If expanding a macro arg, we keep the newline -.
        !          1495:             In final output, it is deleted.  */
        !          1496:          if (! concatenated) {
        !          1497:            ident_length = 0;
        !          1498:            hash = 0;
        !          1499:          }
        !          1500:          ibp++;
        !          1501:          if (!output_marks) {
        !          1502:            obp--;
        !          1503:          } else {
        !          1504:            /* If expanding a macro arg, keep the newline -.  */
        !          1505:            *obp++ = '-';
        !          1506:          }
        !          1507:        } else if (is_space[*ibp]) {
        !          1508:          /* Newline Space does not prevent expansion of preceding token
        !          1509:             so expand the preceding token and then come back.  */
        !          1510:          if (ident_length > 0)
        !          1511:            goto specialchar;
        !          1512: 
        !          1513:          /* If generating final output, newline space makes a space.  */
        !          1514:          if (!output_marks) {
        !          1515:            obp[-1] = *ibp++;
        !          1516:            /* And Newline Newline makes a newline, so count it.  */
        !          1517:            if (obp[-1] == '\n')
        !          1518:              op->lineno++;
        !          1519:          } else {
        !          1520:            /* If expanding a macro arg, keep the newline space.
        !          1521:               If the arg gets stringified, newline space makes nothing.  */
        !          1522:            *obp++ = *ibp++;
        !          1523:          }
        !          1524:        } else abort ();        /* Newline followed by something random?  */
        !          1525:        break;
        !          1526:       }
        !          1527: 
        !          1528:       /* If there is a pending identifier, handle it and come back here.  */
        !          1529:       if (ident_length > 0)
        !          1530:        goto specialchar;
        !          1531: 
        !          1532:       beg_of_line = ibp;
        !          1533: 
        !          1534:       /* Update the line counts and output a #line if necessary.  */
        !          1535:       ++ip->lineno;
        !          1536:       ++op->lineno;
        !          1537:       if (ip->lineno != op->lineno) {
        !          1538:        op->bufp = obp;
        !          1539:        output_line_command (ip, op, 1);
        !          1540:        check_expand (op, ip->length - (ip->bufp - ip->buf));
        !          1541:        obp = op->bufp;
        !          1542:       }
        !          1543:       break;
        !          1544: 
        !          1545:       /* Come here either after (1) a null character that is part of the input
        !          1546:         or (2) at the end of the input, because there is a null there.  */
        !          1547:     case 0:
        !          1548:       if (ibp <= limit)
        !          1549:        /* Our input really contains a null character.  */
        !          1550:        goto randomchar;
        !          1551: 
        !          1552:       /* At end of a macro-expansion level, pop it and read next level.  */
        !          1553:       if (ip->macro != 0) {
        !          1554:        obp--;
        !          1555:        ibp--;
        !          1556:        POPMACRO;
        !          1557:        RECACHE;
        !          1558:        break;
        !          1559:       }
        !          1560: 
        !          1561:       /* If we don't have a pending identifier,
        !          1562:         return at end of input.  */
        !          1563:       if (ident_length == 0)
        !          1564:        {
        !          1565:          obp--;
        !          1566:          ibp--;
        !          1567:          op->bufp = obp;
        !          1568:          ip->bufp = ibp;
        !          1569:          goto ending;
        !          1570:        }
        !          1571: 
        !          1572:       /* If we do have a pending identifier, just consider this null
        !          1573:         a special character and arrange to dispatch on it again.
        !          1574:         The second time, IDENT_LENGTH will be zero so we will return.  */
        !          1575: 
        !          1576:       /* Fall through */
        !          1577: 
        !          1578: specialchar:
        !          1579: 
        !          1580:       /* Handle the case of a character such as /, ', " or null
        !          1581:         seen following an identifier.  Back over it so that
        !          1582:         after the identifier is processed the special char
        !          1583:         will be dispatched on again.  */
        !          1584: 
        !          1585:       ibp--;
        !          1586:       obp--;
        !          1587:       redo_char = 1;
        !          1588: 
        !          1589:     default:
        !          1590: 
        !          1591: randomchar:
        !          1592: 
        !          1593:       if (ident_length > 0) {
        !          1594:        register HASHNODE *hp;
        !          1595: 
        !          1596:        /* We have just seen an identifier end.  If it's a macro, expand it.
        !          1597: 
        !          1598:           IDENT_LENGTH is the length of the identifier
        !          1599:           and HASH is its hash code.
        !          1600: 
        !          1601:           The identifier has already been copied to the output,
        !          1602:           so if it is a macro we must remove it.
        !          1603: 
        !          1604:           If REDO_CHAR is 0, the char that terminated the identifier
        !          1605:           has been skipped in the output and the input.
        !          1606:           OBP-IDENT_LENGTH-1 points to the identifier.
        !          1607:           If the identifier is a macro, we must back over the terminator.
        !          1608: 
        !          1609:           If REDO_CHAR is 1, the terminating char has already been
        !          1610:           backed over.  OBP-IDENT_LENGTH points to the identifier.  */
        !          1611: 
        !          1612:        for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL;
        !          1613:             hp = hp->next) {
        !          1614: 
        !          1615:          if (hp->length == ident_length) {
        !          1616:            U_CHAR *obufp_before_macroname;
        !          1617:            int op_lineno_before_macroname;
        !          1618:            register int i = ident_length;
        !          1619:            register U_CHAR *p = hp->name;
        !          1620:            register U_CHAR *q = obp - i;
        !          1621:            int disabled;
        !          1622: 
        !          1623:            if (! redo_char)
        !          1624:              q--;
        !          1625: 
        !          1626:            do {                /* All this to avoid a strncmp () */
        !          1627:              if (*p++ != *q++)
        !          1628:                goto hashcollision;
        !          1629:            } while (--i);
        !          1630: 
        !          1631:            /* We found a use of a macro name.
        !          1632:               see if the context shows it is a macro call.  */
        !          1633: 
        !          1634:            /* Back up over terminating character if not already done.  */
        !          1635:            if (! redo_char)
        !          1636:              {
        !          1637:                ibp--;
        !          1638:                obp--;
        !          1639:              }
        !          1640: 
        !          1641:            obufp_before_macroname = obp - ident_length;
        !          1642:            op_lineno_before_macroname = op->lineno;
        !          1643: 
        !          1644:            /* Record whether the macro is disabled.  */
        !          1645:            disabled = hp->type == T_DISABLED;
        !          1646: 
        !          1647:            /* This looks like a macro ref, but if the macro was disabled,
        !          1648:               just copy its name and put in a marker if requested.  */
        !          1649: 
        !          1650:            if (disabled)
        !          1651:              {
        !          1652:                if (output_marks) {
        !          1653:                  check_expand (op, limit - ibp + 2);
        !          1654:                  *obp++ = '\n';
        !          1655:                  *obp++ = '-';
        !          1656:                }
        !          1657:                break;
        !          1658:              }
        !          1659: 
        !          1660:            /* If macro wants an arglist, verify that a '(' follows.
        !          1661:               first skip all whitespace, copying it to the output
        !          1662:               after the macro name.  Then, if there is no '(',
        !          1663:               decide this is not a macro call and leave things that way.  */
        !          1664:            if ((hp->type == T_MACRO || hp->type == T_DISABLED)
        !          1665:                && hp->value.defn->nargs >= 0)
        !          1666:              {
        !          1667:                while (1) {
        !          1668:                  /* Scan forward over whitespace, copying it to the output.  */
        !          1669:                  if (ibp == limit && ip->macro != 0) {
        !          1670:                    POPMACRO;
        !          1671:                    RECACHE;
        !          1672:                  }
        !          1673:                  else if (is_space[*ibp]) {
        !          1674:                    *obp++ = *ibp++;
        !          1675:                    if (ibp[-1] == '\n')
        !          1676:                      {
        !          1677:                        if (ip->macro == 0) {
        !          1678:                          /* Newline in a file.  Count it.  */
        !          1679:                          ++ip->lineno;
        !          1680:                          ++op->lineno;
        !          1681:                        } else if (!output_marks) {
        !          1682:                          /* A newline mark, and we don't want marks
        !          1683:                             in the output.  If it is newline-hyphen,
        !          1684:                             discard it entirely.  Otherwise, it is
        !          1685:                             newline-whitechar, so keep the whitechar.  */
        !          1686:                          obp--;
        !          1687:                          if (*ibp == '-')
        !          1688:                            ibp++;
        !          1689:                          else {
        !          1690:                            if (*ibp == '\n')
        !          1691:                              ++op->lineno;
        !          1692:                            *obp++ = *ibp++;
        !          1693:                          }
        !          1694:                        } else {
        !          1695:                          /* A newline mark; copy both chars to the output.  */
        !          1696:                          *obp++ = *ibp++;
        !          1697:                        }
        !          1698:                      }
        !          1699:                  }
        !          1700:                  else break;
        !          1701:                }
        !          1702:                if (*ibp != '(')
        !          1703:                  break;
        !          1704:              }
        !          1705: 
        !          1706:            /* This is now known to be a macro call.
        !          1707:               Discard the macro name from the output,
        !          1708:               along with any following whitespace just copied.  */
        !          1709:            obp = obufp_before_macroname;
        !          1710:            op->lineno = op_lineno_before_macroname;
        !          1711: 
        !          1712:            /* Expand the macro, reading arguments as needed,
        !          1713:               and push the expansion on the input stack.  */
        !          1714:            ip->bufp = ibp;
        !          1715:            op->bufp = obp;
        !          1716:            macroexpand (hp, op);
        !          1717: 
        !          1718:            /* Reexamine input stack, since macroexpand has pushed
        !          1719:               a new level on it.  */
        !          1720:            obp = op->bufp;
        !          1721:            RECACHE;
        !          1722:            break;
        !          1723:          }
        !          1724: hashcollision:
        !          1725:               ;
        !          1726:        }                       /* End hash-table-search loop */
        !          1727:        ident_length = hash = 0; /* Stop collecting identifier */
        !          1728:        redo_char = 0;
        !          1729:        concatenated = 0;
        !          1730:       }                                /* End if (ident_length > 0) */
        !          1731:     }                          /* End switch */
        !          1732:   }                            /* End per-char loop */
        !          1733: 
        !          1734:   /* Come here to return -- but first give an error message
        !          1735:      if there was an unterminated successful conditional.  */
        !          1736:  ending:
        !          1737:   if (if_stack != ip->if_stack) {
        !          1738:     char *str;
        !          1739:     switch (if_stack->type) {
        !          1740:     case T_IF:
        !          1741:       str = "if";
        !          1742:       break;
        !          1743:     case T_IFDEF:
        !          1744:       str = "ifdef";
        !          1745:       break;
        !          1746:     case T_IFNDEF:
        !          1747:       str = "ifndef";
        !          1748:       break;
        !          1749:     case T_ELSE:
        !          1750:       str = "else";
        !          1751:       break;
        !          1752:     case T_ELIF:
        !          1753:       str = "elif";
        !          1754:       break;
        !          1755:     }
        !          1756:     error_with_line (line_for_error (if_stack->lineno),
        !          1757:                     "unterminated #%s conditional", str);
        !          1758:   }
        !          1759:   if_stack = ip->if_stack;
        !          1760: }
        !          1761: 
        !          1762: /*
        !          1763:  * Rescan a string into a temporary buffer and return the result
        !          1764:  * as a FILE_BUF.  Note this function returns a struct, not a pointer.
        !          1765:  *
        !          1766:  * OUTPUT_MARKS nonzero means keep Newline markers found in the input
        !          1767:  * and insert such markers when appropriate.  See `rescan' for details.
        !          1768:  * OUTPUT_MARKS is 1 for macroexpanding a macro argument separately
        !          1769:  * before substitution; it is 0 for other uses.
        !          1770:  */
        !          1771: static FILE_BUF
        !          1772: expand_to_temp_buffer (buf, limit, output_marks)
        !          1773:      U_CHAR *buf, *limit;
        !          1774:      int output_marks;
        !          1775: {
        !          1776:   register FILE_BUF *ip;
        !          1777:   FILE_BUF obuf;
        !          1778:   int length = limit - buf;
        !          1779:   U_CHAR *buf1;
        !          1780:   int odepth = indepth;
        !          1781: 
        !          1782:   if (length < 0)
        !          1783:     abort ();
        !          1784: 
        !          1785:   /* Set up the input on the input stack.  */
        !          1786: 
        !          1787:   buf1 = (U_CHAR *) alloca (length + 1);
        !          1788:   {
        !          1789:     register U_CHAR *p1 = buf;
        !          1790:     register U_CHAR *p2 = buf1;
        !          1791: 
        !          1792:     while (p1 != limit)
        !          1793:       *p2++ = *p1++;
        !          1794:   }
        !          1795:   buf1[length] = 0;
        !          1796: 
        !          1797:   ++indepth;
        !          1798: 
        !          1799:   ip = &instack[indepth];
        !          1800:   ip->fname = 0;
        !          1801:   ip->macro = 0;
        !          1802:   ip->free = 0;
        !          1803:   ip->length = length;
        !          1804:   ip->buf = ip->bufp = buf1;
        !          1805:   ip->if_stack = if_stack;
        !          1806: 
        !          1807:   /* Set up to receive the output.  */
        !          1808: 
        !          1809:   obuf.length = length * 2 + 100; /* Usually enough.  Why be stingy?  */
        !          1810:   obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
        !          1811:   obuf.fname = 0;
        !          1812:   obuf.macro = 0;
        !          1813:   obuf.free = 0;
        !          1814: 
        !          1815:   ip->lineno = obuf.lineno = 1;
        !          1816: 
        !          1817:   /* Scan the input, create the output.  */
        !          1818: 
        !          1819:   rescan (&obuf, output_marks);
        !          1820: 
        !          1821:   /* Pop input stack to original state.  */
        !          1822:   --indepth;
        !          1823: 
        !          1824:   if (indepth != odepth)
        !          1825:     abort ();
        !          1826: 
        !          1827:   /* Record the output.  */
        !          1828:   obuf.length = obuf.bufp - obuf.buf;
        !          1829: 
        !          1830:   return obuf;
        !          1831: }
        !          1832: 
        !          1833: /*
        !          1834:  * Process a # directive.  Expects IP->bufp to point to the '#', as in
        !          1835:  * `#define foo bar'.  Passes to the command handler
        !          1836:  * (do_define, do_include, etc.): the addresses of the 1st and
        !          1837:  * last chars of the command (starting immediately after the #
        !          1838:  * keyword), plus op and the keyword table pointer.  If the command
        !          1839:  * contains comments it is copied into a temporary buffer sans comments
        !          1840:  * and the temporary buffer is passed to the command handler instead.
        !          1841:  * Likewise for backslash-newlines.
        !          1842:  *
        !          1843:  * Returns nonzero if this was a known # directive.
        !          1844:  * Otherwise, returns zero, without advancing the input pointer.
        !          1845:  */
        !          1846: 
        !          1847: int
        !          1848: handle_directive (ip, op)
        !          1849:      FILE_BUF *ip, *op;
        !          1850: {
        !          1851:   register U_CHAR *bp, *cp;
        !          1852:   register struct directive *kt;
        !          1853:   register int ident_length;
        !          1854:   U_CHAR *resume_p;
        !          1855: 
        !          1856:   /* Nonzero means we must copy the entire command
        !          1857:      to get rid of comments or backslash-newlines.  */
        !          1858:   int copy_command = 0;
        !          1859: 
        !          1860:   U_CHAR *ident, *after_ident;
        !          1861: 
        !          1862:   bp = ip->bufp;
        !          1863:   /* Skip whitespace and \-newline.  */
        !          1864:   while (1) {
        !          1865:     if (is_hor_space[*bp])
        !          1866:       bp++;
        !          1867:     else if (*bp == '\\' && bp[1] == '\n') {
        !          1868:       bp += 2; ip->lineno++;
        !          1869:     } else break;
        !          1870:   }
        !          1871: 
        !          1872:   /* Now find end of directive name.
        !          1873:      If we encounter a backslash-newline, exchange it with any following
        !          1874:      symbol-constituents so that we end up with a contiguous name.  */
        !          1875: 
        !          1876:   cp = bp;
        !          1877:   while (1) {
        !          1878:     if (is_idchar[*cp])
        !          1879:       cp++;
        !          1880:     else {
        !          1881:       if (*cp == '\\' && cp[1] == '\n')
        !          1882:        name_newline_fix (cp);
        !          1883:       if (is_idchar[*cp])
        !          1884:        cp++;
        !          1885:       else break;
        !          1886:     }
        !          1887:   }
        !          1888:   ident_length = cp - bp;
        !          1889:   ident = bp;
        !          1890:   after_ident = cp;
        !          1891: 
        !          1892:   /*
        !          1893:    * Decode the keyword and call the appropriate expansion
        !          1894:    * routine, after moving the input pointer up to the next line.
        !          1895:    */
        !          1896:   for (kt = directive_table; kt->length > 0; kt++) {
        !          1897:     if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length)) {
        !          1898:       register U_CHAR *buf;
        !          1899:       register U_CHAR *limit = ip->buf + ip->length;
        !          1900:       int unterminated = 0;
        !          1901: 
        !          1902:       /* Find the end of this command (first newline not backslashed
        !          1903:         and not in a string or comment).
        !          1904:         Set COPY_COMMAND if the command must be copied
        !          1905:         (it contains a backslash-newline or a comment).  */
        !          1906: 
        !          1907:       buf = bp = after_ident;
        !          1908:       while (bp < limit) {
        !          1909:        register U_CHAR c = *bp++;
        !          1910:        switch (c) {
        !          1911:        case '\\':
        !          1912:          if (bp < limit) {
        !          1913:            if (*bp == '\n')
        !          1914:              {
        !          1915:                ip->lineno++;
        !          1916:                copy_command = 1;
        !          1917:              }
        !          1918:            bp++;
        !          1919:          }
        !          1920:          break;
        !          1921: 
        !          1922:        case '\'':
        !          1923:        case '\"':
        !          1924:          bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, &copy_command, &unterminated);
        !          1925:          /* Don't bother calling the directive if we already got an error
        !          1926:             message due to unterminated string.  Skip everything and pretend
        !          1927:             we called the directive.  */
        !          1928:          if (unterminated) {
        !          1929:            ip->bufp = bp;
        !          1930:            return 1;
        !          1931:          }
        !          1932:          break;
        !          1933: 
        !          1934:          /* <...> is special for #include.  */
        !          1935:        case '<':
        !          1936:          if (!kt->angle_brackets)
        !          1937:            break;
        !          1938:          while (*bp && *bp != '>') bp++;
        !          1939:          break;
        !          1940: 
        !          1941:        case '/':
        !          1942:          if (*bp == '\\' && bp[1] == '\n')
        !          1943:            newline_fix (bp);
        !          1944:          if (*bp == '*'
        !          1945: #ifdef CPLUSPLUS
        !          1946:              || *bp == '/'
        !          1947: #endif
        !          1948:              ) {
        !          1949:            U_CHAR *obp = bp - 1;
        !          1950:            ip->bufp = bp + 1;
        !          1951:            skip_to_end_of_comment (ip, &ip->lineno);
        !          1952:            bp = ip->bufp;
        !          1953:            /* No need to copy the command because of a comment at the end;
        !          1954:               just don't include the comment in the directive.  */
        !          1955:            if (bp == limit || *bp == '\n') {
        !          1956:              bp = obp;
        !          1957:              goto endloop1;
        !          1958:            }
        !          1959:            copy_command++;
        !          1960:          }
        !          1961:          break;
        !          1962: 
        !          1963:        case '\n':
        !          1964:          --bp;         /* Point to the newline */
        !          1965:          ip->bufp = bp;
        !          1966:          goto endloop1;
        !          1967:        }
        !          1968:       }
        !          1969:       ip->bufp = bp;
        !          1970: 
        !          1971:     endloop1:
        !          1972:       resume_p = ip->bufp;
        !          1973:       /* BP is the end of the directive.
        !          1974:         RESUME_P is the next interesting data after the directive.
        !          1975:         A comment may come between.  */
        !          1976: 
        !          1977:       if (copy_command) {
        !          1978:        register U_CHAR *xp = buf;
        !          1979:        /* Need to copy entire command into temp buffer before dispatching */
        !          1980: 
        !          1981:        cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus
        !          1982:                                                  some slop */
        !          1983:        buf = cp;
        !          1984: 
        !          1985:        /* Copy to the new buffer, deleting comments
        !          1986:           and backslash-newlines (and whitespace surrounding the latter).  */
        !          1987: 
        !          1988:        while (xp < bp) {
        !          1989:          register U_CHAR c = *xp++;
        !          1990:          *cp++ = c;
        !          1991: 
        !          1992:          switch (c) {
        !          1993:          case '\n':
        !          1994:            break;
        !          1995: 
        !          1996:            /* <...> is special for #include.  */
        !          1997:          case '<':
        !          1998:            if (!kt->angle_brackets)
        !          1999:              break;
        !          2000:            while (*bp && *bp != '>') bp++;
        !          2001:            break;
        !          2002: 
        !          2003:          case '\\':
        !          2004:            if (*xp == '\n') {
        !          2005:              xp++;
        !          2006:              cp--;
        !          2007:              if (cp != buf && is_space[cp[-1]]) {
        !          2008:                while (cp != buf && is_space[cp[-1]]) cp--;
        !          2009:                cp++;
        !          2010:                SKIP_WHITE_SPACE (xp);
        !          2011:              } else if (is_space[*xp]) {
        !          2012:                *cp++ = *xp++;
        !          2013:                SKIP_WHITE_SPACE (xp);
        !          2014:              }
        !          2015:            }
        !          2016:            break;
        !          2017: 
        !          2018:          case '\'':
        !          2019:          case '\"':
        !          2020:            {
        !          2021:              register U_CHAR *bp1
        !          2022:                = skip_quoted_string (xp - 1, limit, ip->lineno, 0, 0, 0);
        !          2023:              while (xp != bp1)
        !          2024:                *cp++ = *xp++;
        !          2025:            }
        !          2026:            break;
        !          2027: 
        !          2028:          case '/':
        !          2029:            if (*xp == '*'
        !          2030: #ifdef CPLUSPLUS
        !          2031:                || *xp == '/'
        !          2032: #endif
        !          2033:                ) {
        !          2034:              if (traditional)
        !          2035:                cp--;
        !          2036:              else
        !          2037:                cp[-1] = ' ';
        !          2038:              ip->bufp = xp + 1;
        !          2039:              skip_to_end_of_comment (ip, 0);
        !          2040:              xp = ip->bufp;
        !          2041:            }
        !          2042:          }
        !          2043:        }
        !          2044: 
        !          2045:        /* Null-terminate the copy.  */
        !          2046: 
        !          2047:        *cp = 0;
        !          2048:       }
        !          2049:       else
        !          2050:        cp = bp;
        !          2051: 
        !          2052:       ip->bufp = resume_p;
        !          2053: 
        !          2054:       /* Call the appropriate command handler.  buf now points to
        !          2055:         either the appropriate place in the input buffer, or to
        !          2056:         the temp buffer if it was necessary to make one.  cp
        !          2057:         points to the first char after the contents of the (possibly
        !          2058:         copied) command, in either case. */
        !          2059:       (*kt->func) (buf, cp, op, kt);
        !          2060:       check_expand (op, ip->length - (ip->bufp - ip->buf));
        !          2061: 
        !          2062:       return 1;
        !          2063:     }
        !          2064:   }
        !          2065: 
        !          2066:   return 0;
        !          2067: }
        !          2068: 
        !          2069: static char *monthnames[] = {"jan", "feb", "mar", "apr", "may", "jun",
        !          2070:                             "jul", "aug", "sep", "oct", "nov", "dec",
        !          2071:                            };
        !          2072: 
        !          2073: /*
        !          2074:  * expand things like __FILE__.  Place the expansion into the output
        !          2075:  * buffer *without* rescanning.
        !          2076:  */
        !          2077: special_symbol (hp, op)
        !          2078:      HASHNODE *hp;
        !          2079:      FILE_BUF *op;
        !          2080: {
        !          2081:   char *buf;
        !          2082:   int i, len;
        !          2083:   FILE_BUF *ip = NULL;
        !          2084:   static struct tm *timebuf = NULL;
        !          2085:   struct tm *localtime ();
        !          2086: 
        !          2087:   int paren = 0;               /* For special `defined' keyword */
        !          2088: 
        !          2089:   for (i = indepth; i >= 0; i--)
        !          2090:     if (instack[i].fname != NULL) {
        !          2091:       ip = &instack[i];
        !          2092:       break;
        !          2093:     }
        !          2094:   if (ip == NULL) {
        !          2095:     error ("cccp error: not in any file?!");
        !          2096:     return;                    /* the show must go on */
        !          2097:   }
        !          2098: 
        !          2099:   switch (hp->type) {
        !          2100:   case T_FILE:
        !          2101:     buf = (char *) alloca (3 + strlen (ip->fname));
        !          2102:     sprintf (buf, "\"%s\"", ip->fname);
        !          2103:     break;
        !          2104: 
        !          2105:   case T_VERSION:
        !          2106:     buf = (char *) alloca (3 + strlen (version_string));
        !          2107:     sprintf (buf, "\"%s\"", version_string);
        !          2108:     break;
        !          2109: 
        !          2110:   case T_CONST:
        !          2111:     buf = (char *) alloca (4 * sizeof (int));
        !          2112:     sprintf (buf, "%d", hp->value.ival);
        !          2113:     break;
        !          2114: 
        !          2115:   case T_SPECLINE:
        !          2116:     buf = (char *) alloca (10);
        !          2117:     sprintf (buf, "%d", ip->lineno);
        !          2118:     break;
        !          2119: 
        !          2120:   case T_DATE:
        !          2121:   case T_TIME:
        !          2122:     if (timebuf == NULL) {
        !          2123:       i = time (0);
        !          2124:       timebuf = localtime (&i);
        !          2125:     }
        !          2126:     buf = (char *) alloca (20);
        !          2127:     if (hp->type == T_DATE)
        !          2128:       sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],
        !          2129:              timebuf->tm_mday, timebuf->tm_year + 1900);
        !          2130:     else
        !          2131:       sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
        !          2132:              timebuf->tm_sec);
        !          2133:     break;
        !          2134: 
        !          2135:   case T_SPEC_DEFINED:
        !          2136:     buf = " 0 ";               /* Assume symbol is not defined */
        !          2137:     ip = &instack[indepth];
        !          2138:     SKIP_WHITE_SPACE (ip->bufp);
        !          2139:     if (*ip->bufp == '(') {
        !          2140:       paren++;
        !          2141:       ip->bufp++;                      /* Skip over the paren */
        !          2142:       SKIP_WHITE_SPACE (ip->bufp);
        !          2143:     }
        !          2144: 
        !          2145:     if (!is_idstart[*ip->bufp])
        !          2146:       goto oops;
        !          2147:     if (lookup (ip->bufp, -1, -1))
        !          2148:       buf = " 1 ";
        !          2149:     while (is_idchar[*ip->bufp])
        !          2150:       ++ip->bufp;
        !          2151:     SKIP_WHITE_SPACE (ip->bufp);
        !          2152:     if (paren) {
        !          2153:       if (*ip->bufp != ')')
        !          2154:        goto oops;
        !          2155:       ++ip->bufp;
        !          2156:     }
        !          2157:     break;
        !          2158: 
        !          2159: oops:
        !          2160: 
        !          2161:     error ("`defined' must be followed by ident or (ident)");
        !          2162:     break;
        !          2163: 
        !          2164:   default:
        !          2165:     error ("cccp error: invalid special hash type"); /* time for gdb */
        !          2166:     abort ();
        !          2167:   }
        !          2168:   len = strlen (buf);
        !          2169:   check_expand (op, len);
        !          2170:   bcopy (buf, op->bufp, len);
        !          2171:   op->bufp += len;
        !          2172: 
        !          2173:   return;
        !          2174: }
        !          2175: 
        !          2176: 
        !          2177: /* Routines to handle #directives */
        !          2178: 
        !          2179: /*
        !          2180:  * Process include file by reading it in and calling rescan.
        !          2181:  * Expects to see "fname" or <fname> on the input.
        !          2182:  */
        !          2183: 
        !          2184: do_include (buf, limit, op, keyword)
        !          2185:      U_CHAR *buf, *limit;
        !          2186:      FILE_BUF *op;
        !          2187:      struct directive *keyword;
        !          2188: {
        !          2189:   char *fname;         /* Dynamically allocated fname buffer */
        !          2190:   U_CHAR *fbeg, *fend;         /* Beginning and end of fname */
        !          2191: 
        !          2192:   struct directory_stack *stackp = include; /* Chain of dirs to search */
        !          2193:   struct directory_stack dsp[1];       /* First in chain, if #include "..." */
        !          2194:   int flen;
        !          2195: 
        !          2196:   int f;                       /* file number */
        !          2197: 
        !          2198:   int retried = 0;             /* Have already tried macro
        !          2199:                                   expanding the include line*/
        !          2200:   FILE_BUF trybuf;             /* It got expanded into here */
        !          2201:   int system_header_p = 0;     /* 0 for "...", 1 for <...> */
        !          2202: 
        !          2203:   f= -1;                       /* JF we iz paranoid! */
        !          2204: 
        !          2205: get_filename:
        !          2206: 
        !          2207:   fbeg = buf;
        !          2208:   SKIP_WHITE_SPACE (fbeg);
        !          2209:   /* Discard trailing whitespace so we can easily see
        !          2210:      if we have parsed all the significant chars we were given.  */
        !          2211:   while (limit != fbeg && is_hor_space[limit[-1]]) limit--;
        !          2212: 
        !          2213:   switch (*fbeg++) {
        !          2214:   case '\"':
        !          2215:     fend = fbeg;
        !          2216:     while (fend != limit && *fend != '\"')
        !          2217:       fend++;
        !          2218:     if (*fend == '\"' && fend + 1 == limit) {
        !          2219:       FILE_BUF *fp;
        !          2220: 
        !          2221:       /* We have "filename".  Figure out directory this source
        !          2222:         file is coming from and put it on the front of the list. */
        !          2223: 
        !          2224:       /* If -I- was specified, don't search current dir, only spec'd ones. */
        !          2225:       if (ignore_srcdir) break;
        !          2226: 
        !          2227:       for (fp = &instack[indepth]; fp >= instack; fp--)
        !          2228:        {
        !          2229:          int n;
        !          2230:          char *ep,*nam;
        !          2231:          extern char *rindex ();
        !          2232: 
        !          2233:          if ((nam = fp->fname) != NULL)
        !          2234:            {
        !          2235:              /* Found a named file.  Figure out dir of the file,
        !          2236:                 and put it in front of the search list.  */
        !          2237:              dsp[0].next = stackp;
        !          2238:              stackp = dsp;
        !          2239: #ifndef VMS
        !          2240:              ep = rindex (nam, '/');
        !          2241: #else /* VMS */
        !          2242:              ep = rindex (nam, ']');
        !          2243:              if (ep == NULL) ep = rindex (nam, '>');
        !          2244:              if (ep == NULL) ep = rindex (nam, ':');
        !          2245:              if (ep != NULL) ep++;
        !          2246: #endif /* VMS */
        !          2247:              if (ep != NULL) {
        !          2248:                n = ep - nam;
        !          2249:                dsp[0].fname = (char *) alloca (n + 1);
        !          2250:                strncpy (dsp[0].fname, nam, n);
        !          2251:                dsp[0].fname[n] = '\0';
        !          2252:                if (n > max_include_len) max_include_len = n;
        !          2253:              } else {
        !          2254:                dsp[0].fname = 0; /* Current directory */
        !          2255:              }
        !          2256:              break;
        !          2257:            }
        !          2258:        }
        !          2259:       break;
        !          2260:     }
        !          2261:     goto fail;
        !          2262: 
        !          2263:   case '<':
        !          2264:     fend = fbeg;
        !          2265:     while (fend != limit && *fend != '>') fend++;
        !          2266:     if (*fend == '>' && fend + 1 == limit) {
        !          2267:       system_header_p = 1;
        !          2268:       /* If -I-, start with the first -I dir after the -I-.  */
        !          2269:       if (first_bracket_include)
        !          2270:        stackp = first_bracket_include;
        !          2271:       break;
        !          2272:     }
        !          2273:     goto fail;
        !          2274: 
        !          2275:   default:
        !          2276:   fail:
        !          2277:     if (retried) {
        !          2278:       error ("#include expects \"fname\" or <fname>");
        !          2279:       return;
        !          2280:     } else {
        !          2281:       trybuf = expand_to_temp_buffer (buf, limit, 0);
        !          2282:       buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
        !          2283:       bcopy (trybuf.buf, buf, trybuf.bufp - trybuf.buf);
        !          2284:       limit = buf + (trybuf.bufp - trybuf.buf);
        !          2285:       free (trybuf.buf);
        !          2286:       retried++;
        !          2287:       goto get_filename;
        !          2288:     }
        !          2289:   }
        !          2290: 
        !          2291:   flen = fend - fbeg;
        !          2292:   fname = (char *) alloca (max_include_len + flen + 2);
        !          2293:   /* + 2 above for slash and terminating null.  */
        !          2294: 
        !          2295:   /* If specified file name is absolute, just open it.  */
        !          2296: 
        !          2297:   if (*fbeg == '/') {
        !          2298:     strncpy (fname, fbeg, flen);
        !          2299:     fname[flen] = 0;
        !          2300:     f = open (fname, O_RDONLY);
        !          2301:   } else {
        !          2302:     /* Search directory path, trying to open the file.
        !          2303:        Copy each filename tried into FNAME.  */
        !          2304: 
        !          2305:     for (; stackp; stackp = stackp->next) {
        !          2306:       if (stackp->fname) {
        !          2307:        strcpy (fname, stackp->fname);
        !          2308:        strcat (fname, "/");
        !          2309:        fname[strlen (fname) + flen] = 0;
        !          2310:       } else {
        !          2311:        fname[0] = 0;
        !          2312:       }
        !          2313:       strncat (fname, fbeg, flen);
        !          2314: #ifdef VMS
        !          2315:       /* Change this 1/2 Unix 1/2 VMS file specification into a
        !          2316:          full VMS file specification */
        !          2317:       if (stackp->fname && (stackp->fname[0] != 0)) {
        !          2318:        /* Fix up the filename */
        !          2319:        hack_vms_include_specification (fname);
        !          2320:       } else {
        !          2321:        /* This is a normal VMS filespec, so use it unchanged.  */
        !          2322:        strncpy (fname, fbeg, flen);
        !          2323:        fname[flen] = 0;
        !          2324:       }
        !          2325: #endif /* VMS */
        !          2326:       if ((f = open (fname, O_RDONLY)) >= 0)
        !          2327:        break;
        !          2328:     }
        !          2329:   }
        !          2330: 
        !          2331:   /* For -M, print the name of the included file.  */
        !          2332:   if (print_deps > system_header_p)
        !          2333:     {
        !          2334:       deps_output (fname, strlen (fname));
        !          2335:       deps_output (" ", 0);
        !          2336:     }
        !          2337: 
        !          2338:   if (f < 0) {
        !          2339:     strncpy (fname, fbeg, flen);
        !          2340:     fname[flen] = 0;
        !          2341:     error ("can't find include file `%s'", fname);
        !          2342:   } else {
        !          2343:     finclude (f, fname, op);
        !          2344:     close (f);
        !          2345:   }
        !          2346: }
        !          2347: 
        !          2348: /* Process the contents of include file FNAME, already open on descriptor F,
        !          2349:    with output to OP.  */
        !          2350: 
        !          2351: finclude (f, fname, op)
        !          2352:      int f;
        !          2353:      char *fname;
        !          2354:      FILE_BUF *op;
        !          2355: {
        !          2356:   long st_size;
        !          2357:   long i;
        !          2358:   FILE_BUF *fp;                        /* For input stack frame */
        !          2359:   int success = 0;
        !          2360: 
        !          2361:   if (file_size_and_mode (f, (int *)0, &st_size) < 0)
        !          2362:     goto nope;         /* Impossible? */
        !          2363: 
        !          2364:   fp = &instack[indepth + 1];
        !          2365:   bzero (fp, sizeof (FILE_BUF));
        !          2366:   fp->buf = (U_CHAR *) alloca (st_size + 2);
        !          2367:   fp->fname = fname;
        !          2368:   fp->length = 0;
        !          2369:   fp->lineno = 1;
        !          2370:   fp->bufp = fp->buf;
        !          2371:   fp->if_stack = if_stack;
        !          2372:   
        !          2373:   /* Read the file contents, knowing that st_size is an upper bound
        !          2374:      on the number of bytes we can read.  */
        !          2375:   while (st_size > 0) {
        !          2376:     i = read (f, fp->buf + fp->length, st_size);
        !          2377:     if (i <= 0) {
        !          2378:       if (i == 0) break;
        !          2379:       goto nope;
        !          2380:     }
        !          2381:     fp->length += i;
        !          2382:     st_size -= i;
        !          2383:   }
        !          2384: 
        !          2385:   if (!no_trigraphs)
        !          2386:     trigraph_pcp (fp);
        !          2387: 
        !          2388:   if (fp->length > 0 && fp->buf[fp->length-1] != '\n')
        !          2389:     fp->buf[fp->length++] = '\n';
        !          2390:   fp->buf[fp->length] = '\0';
        !          2391: 
        !          2392:   success = 1;
        !          2393:   indepth++;
        !          2394: 
        !          2395:   output_line_command (fp, op, 0);
        !          2396:   rescan (op, 0);
        !          2397:   indepth--;
        !          2398:   output_line_command (&instack[indepth], op, 0);
        !          2399: 
        !          2400: nope:
        !          2401: 
        !          2402:   close (f);
        !          2403:   if (!success) {
        !          2404:     perror_with_name (fname);
        !          2405:   }
        !          2406: }
        !          2407: 
        !          2408: /* The arglist structure is built by do_define to tell
        !          2409:    collect_definition where the argument names begin.  That
        !          2410:    is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
        !          2411:    would contain pointers to the strings x, y, and z.
        !          2412:    Collect_definition would then build a DEFINITION node,
        !          2413:    with reflist nodes pointing to the places x, y, and z had
        !          2414:    appeared.  So the arglist is just convenience data passed
        !          2415:    between these two routines.  It is not kept around after
        !          2416:    the current #define has been processed and entered into the
        !          2417:    hash table. */
        !          2418: 
        !          2419: struct arglist {
        !          2420:   struct arglist *next;
        !          2421:   U_CHAR *name;
        !          2422:   int length;
        !          2423:   int argno;
        !          2424: };
        !          2425: 
        !          2426: /* Process a #define command.
        !          2427: BUF points to the contents of the #define command, as a continguous string.
        !          2428: LIMIT points to the first character past the end of the definition.
        !          2429: KEYWORD is the keyword-table entry for #define.  */
        !          2430: 
        !          2431: do_define (buf, limit, op, keyword)
        !          2432:      U_CHAR *buf, *limit;
        !          2433:      FILE_BUF *op;
        !          2434:      struct directive *keyword;
        !          2435: {
        !          2436:   U_CHAR *bp;                  /* temp ptr into input buffer */
        !          2437:   U_CHAR *symname;             /* remember where symbol name starts */
        !          2438:   int sym_length;              /* and how long it is */
        !          2439: 
        !          2440:   DEFINITION *defn;
        !          2441:   int arglengths = 0;          /* Accumulate lengths of arg names
        !          2442:                                   plus number of args.  */
        !          2443:   int hashcode;
        !          2444: 
        !          2445:   bp = buf;
        !          2446: 
        !          2447:   while (is_hor_space[*bp])
        !          2448:     bp++;
        !          2449:   if (!is_idstart[*bp])
        !          2450:     warning ("macro name starts with a digit");
        !          2451: 
        !          2452:   symname = bp;                        /* remember where it starts */
        !          2453:   while (is_idchar[*bp] && bp < limit) {
        !          2454:     if (*bp == '$' && pedantic) {
        !          2455:       if (! dollar_seen)
        !          2456:        warning ("ANSI C forbids `$' in identifier (first use here)");
        !          2457:       dollar_seen = 1;
        !          2458:     }
        !          2459:     bp++;
        !          2460:   }
        !          2461:   sym_length = bp - symname;
        !          2462: 
        !          2463:   /* lossage will occur if identifiers or control keywords are broken
        !          2464:      across lines using backslash.  This is not the right place to take
        !          2465:      care of that. */
        !          2466: 
        !          2467:   if (*bp == '(') {
        !          2468:     struct arglist *arg_ptrs = NULL;
        !          2469:     int argno = 0;
        !          2470: 
        !          2471:     bp++;                      /* skip '(' */
        !          2472:     SKIP_WHITE_SPACE (bp);
        !          2473: 
        !          2474:     /* Loop over macro argument names.  */
        !          2475:     while (*bp != ')') {
        !          2476:       struct arglist *temp;
        !          2477: 
        !          2478:       temp = (struct arglist *) alloca (sizeof (struct arglist));
        !          2479:       temp->name = bp;
        !          2480:       temp->next = arg_ptrs;
        !          2481:       temp->argno = argno++;
        !          2482:       arg_ptrs = temp;
        !          2483: 
        !          2484:       if (!is_idstart[*bp])
        !          2485:        warning ("parameter name starts with a digit in #define");
        !          2486: 
        !          2487:       /* Find the end of the arg name.  */
        !          2488:       while (is_idchar[*bp]) {
        !          2489:        if (*bp == '$' && pedantic) {
        !          2490:          if (! dollar_seen)
        !          2491:            warning ("ANSI C forbids `$' in identifier (first use here)");
        !          2492:          dollar_seen = 1;
        !          2493:        }
        !          2494:        bp++;
        !          2495:       }
        !          2496:       temp->length = bp - temp->name;
        !          2497:       arglengths += temp->length + 2;
        !          2498:       SKIP_WHITE_SPACE (bp);
        !          2499:       if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
        !          2500:        error ("badly punctuated parameter list in #define");
        !          2501:        goto nope;
        !          2502:       }
        !          2503:       if (*bp == ',') {
        !          2504:        bp++;
        !          2505:        SKIP_WHITE_SPACE (bp);
        !          2506:       }
        !          2507:       if (bp >= limit) {
        !          2508:        error ("unterminated parameter list in #define");
        !          2509:        goto nope;
        !          2510:       }
        !          2511:     }
        !          2512: 
        !          2513:     ++bp;                      /* skip paren */
        !          2514:     /* Skip exactly one space or tab if any.  */
        !          2515:     if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
        !          2516:     /* now everything from bp before limit is the definition. */
        !          2517:     defn = collect_expansion (bp, limit, argno, arg_ptrs);
        !          2518: 
        !          2519:     /* Now set defn->argnames to the result of concatenating
        !          2520:        the argument names in reverse order
        !          2521:        with comma-space between them.  */
        !          2522:     defn->argnames = (U_CHAR *) xmalloc (arglengths + 1);
        !          2523:     {
        !          2524:       struct arglist *temp;
        !          2525:       int i = 0;
        !          2526:       for (temp = arg_ptrs; temp; temp = temp->next)
        !          2527:        {
        !          2528:          bcopy (temp->name, &defn->argnames[i], temp->length);
        !          2529:          i += temp->length;
        !          2530:          if (temp->next != 0) {
        !          2531:            defn->argnames[i++] = ',';
        !          2532:            defn->argnames[i++] = ' ';
        !          2533:          }
        !          2534:        }
        !          2535:       defn->argnames[i] = 0;
        !          2536:     }
        !          2537:   } else {
        !          2538:     /* simple expansion or empty definition; gobble it */
        !          2539:     if (is_hor_space[*bp])
        !          2540:       ++bp;            /* skip exactly one blank/tab char */
        !          2541:     /* now everything from bp before limit is the definition. */
        !          2542:     defn = collect_expansion (bp, limit, -1, 0);
        !          2543:     defn->argnames = (U_CHAR *) "";
        !          2544:   }
        !          2545: 
        !          2546:   hashcode = hashf (symname, sym_length, HASHSIZE);
        !          2547: 
        !          2548:   {
        !          2549:     HASHNODE *hp;
        !          2550:     if ((hp = lookup (symname, sym_length, hashcode)) != NULL) {
        !          2551:       if (hp->type != T_MACRO
        !          2552:          || compare_defs (defn, hp->value.defn)) {
        !          2553:        U_CHAR *msg;                    /* what pain... */
        !          2554:        msg = (U_CHAR *) alloca (sym_length + 20);
        !          2555:        bcopy (symname, msg, sym_length);
        !          2556:        strcpy (msg + sym_length, " redefined");
        !          2557:        warning (msg);
        !          2558:       }
        !          2559:       /* Replace the old definition.  */
        !          2560:       hp->type = T_MACRO;
        !          2561:       hp->value.defn = defn;
        !          2562:     } else
        !          2563:       install (symname, sym_length, T_MACRO, defn, hashcode);
        !          2564:   }
        !          2565: 
        !          2566:   return 0;
        !          2567: 
        !          2568: nope:
        !          2569: 
        !          2570:   return 1;
        !          2571: }
        !          2572: 
        !          2573: /*
        !          2574:  * return zero if two DEFINITIONs are isomorphic
        !          2575:  */
        !          2576: static
        !          2577: compare_defs (d1, d2)
        !          2578:      DEFINITION *d1, *d2;
        !          2579: {
        !          2580:   register struct reflist *a1, *a2;
        !          2581:   register U_CHAR *p1 = d1->expansion;
        !          2582:   register U_CHAR *p2 = d2->expansion;
        !          2583:   int first = 1;
        !          2584: 
        !          2585:   if (d1->nargs != d2->nargs)
        !          2586:     return 1;
        !          2587:   if (strcmp (d1->argnames, d2->argnames))
        !          2588:     return 1;
        !          2589:   for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
        !          2590:        a1 = a1->next, a2 = a2->next) {
        !          2591:     if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars))
        !          2592:          || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
        !          2593:        || a1->argno != a2->argno
        !          2594:        || a1->stringify != a2->stringify
        !          2595:        || a1->raw_before != a2->raw_before
        !          2596:        || a1->raw_after != a2->raw_after)
        !          2597:       return 1;
        !          2598:     first = 0;
        !          2599:     p1 += a1->nchars;
        !          2600:     p2 += a2->nchars;
        !          2601:   }
        !          2602:   if (a1 != a2)
        !          2603:     return 1;
        !          2604:   if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
        !          2605:                     p2, d2->length - (p2 - d2->expansion), 1))
        !          2606:     return 1;
        !          2607:   return 0;
        !          2608: }
        !          2609: 
        !          2610: /* Return 1 if two parts of two macro definitions are effectively different.
        !          2611:    One of the parts starts at BEG1 and has LEN1 chars;
        !          2612:    the other has LEN2 chars at BEG2.
        !          2613:    Any sequence of whitespace matches any other sequence of whitespace.
        !          2614:    FIRST means these parts are the first of a macro definition;
        !          2615:     so ignore leading whitespace entirely.
        !          2616:    LAST means these parts are the last of a macro definition;
        !          2617:     so ignore trailing whitespace entirely.  */
        !          2618: 
        !          2619: comp_def_part (first, beg1, len1, beg2, len2, last)
        !          2620:      int first;
        !          2621:      U_CHAR *beg1, *beg2;
        !          2622:      int len1, len2;
        !          2623:      int last;
        !          2624: {
        !          2625:   register U_CHAR *end1 = beg1 + len1;
        !          2626:   register U_CHAR *end2 = beg2 + len2;
        !          2627:   if (first) {
        !          2628:     while (beg1 != end1 && is_space[*beg1]) beg1++;
        !          2629:     while (beg2 != end2 && is_space[*beg2]) beg2++;
        !          2630:   }
        !          2631:   if (last) {
        !          2632:     while (beg1 != end1 && is_space[end1[-1]]) end1--;
        !          2633:     while (beg2 != end2 && is_space[end2[-1]]) end2--;
        !          2634:   }
        !          2635:   while (beg1 != end1 && beg2 != end2) {
        !          2636:     if (is_space[*beg1] && is_space[*beg2]) {
        !          2637:       while (beg1 != end1 && is_space[*beg1]) beg1++;
        !          2638:       while (beg2 != end2 && is_space[*beg2]) beg2++;
        !          2639:     } else if (*beg1 == *beg2) {
        !          2640:       beg1++; beg2++;
        !          2641:     } else break;
        !          2642:   }
        !          2643:   return (beg1 != end1) || (beg2 != end2);
        !          2644: }
        !          2645: 
        !          2646: /* Read a replacement list for a macro with parameters.
        !          2647:    Build the DEFINITION structure.
        !          2648:    Reads characters of text starting at BUF until LIMIT.
        !          2649:    ARGLIST specifies the formal parameters to look for
        !          2650:    in the text of the definition; NARGS is the number of args
        !          2651:    in that list, or -1 for a macro name that wants no argument list.
        !          2652:    MACRONAME is the macro name itself (so we can avoid recursive expansion)
        !          2653:    and NAMELEN is its length in characters.
        !          2654:    
        !          2655: Note that comments and backslash-newlines have already been deleted
        !          2656: from the argument.  */
        !          2657: 
        !          2658: /* Leading and trailing Space, Tab, etc. are converted to markers
        !          2659:    Newline Space, Newline Tab, etc.
        !          2660:    Newline Space makes a space in the final output
        !          2661:    but is discarded if stringified.  (Newline Tab is similar but
        !          2662:    makes a Tab instead.)
        !          2663: 
        !          2664:    If there is no trailing whitespace, a Newline Space is added at the end
        !          2665:    to prevent concatenation that would be contrary to the standard.  */
        !          2666: 
        !          2667: static DEFINITION *
        !          2668: collect_expansion (buf, end, nargs, arglist)
        !          2669:      U_CHAR *buf, *end;
        !          2670:      int nargs;
        !          2671:      struct arglist *arglist;
        !          2672: {
        !          2673:   DEFINITION *defn;
        !          2674:   register U_CHAR *p, *limit, *lastp, *exp_p;
        !          2675:   struct reflist *endpat = NULL;
        !          2676:   /* Pointer to first nonspace after last ## seen.  */
        !          2677:   U_CHAR *concat = 0;
        !          2678:   /* Pointer to first nonspace after last single-# seen.  */
        !          2679:   U_CHAR *stringify = 0;
        !          2680: 
        !          2681:   /* Scan thru the replacement list, ignoring comments and quoted
        !          2682:      strings, picking up on the macro calls.  It does a linear search
        !          2683:      thru the arg list on every potential symbol.  Profiling might say
        !          2684:      that something smarter should happen. */
        !          2685: 
        !          2686:   if (end < buf)
        !          2687:     abort ();
        !          2688: 
        !          2689:   defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION) + 2 * (end - buf + 2));
        !          2690: 
        !          2691:   defn->nargs = nargs;
        !          2692:   exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION);
        !          2693:   lastp = exp_p;
        !          2694: 
        !          2695:   /* Speed this loop up later? */
        !          2696: 
        !          2697:   p = buf;
        !          2698:   limit = end;
        !          2699: 
        !          2700:   /* Find the beginning of the trailing whitespace.  */
        !          2701:   while (p < limit && is_space[limit[-1]]) limit--;
        !          2702: 
        !          2703:   /* Convert leading whitespace to Newline-markers.  */
        !          2704:   while (p < limit && is_space[*p]) {
        !          2705:     *exp_p++ = '\n';
        !          2706:     *exp_p++ = *p++;
        !          2707:   }
        !          2708: 
        !          2709:   /* Process the main body of the definition.  */
        !          2710:   while (p < limit) {
        !          2711:     int skipped_arg = 0;
        !          2712:     register U_CHAR c = *p++;
        !          2713: 
        !          2714:     *exp_p++ = c;
        !          2715: 
        !          2716:     switch (c) {
        !          2717:     case '\'':
        !          2718:     case '\"':
        !          2719:       if (!traditional) {
        !          2720:        for (; p < limit && *p != c; p++) {
        !          2721:          *exp_p++ = *p;
        !          2722:          if (*p == '\\') {
        !          2723:            *exp_p++ = *++p;
        !          2724:          }
        !          2725:        }
        !          2726:        *exp_p++ = *p++;
        !          2727:       }
        !          2728:       break;
        !          2729: 
        !          2730:       /* Special hack: if a \# is written in the #define
        !          2731:         include a # in the definition.  This is useless for C code
        !          2732:         but useful for preprocessing other things.  */
        !          2733: 
        !          2734:     case '\\':
        !          2735:       if (p < limit && *p == '#') {
        !          2736:        /* Pass through this # */
        !          2737:        exp_p--;
        !          2738:        *exp_p++ = *p++;
        !          2739:       }
        !          2740:       break;
        !          2741: 
        !          2742:     case '#':
        !          2743:       if (p < limit && *p == '#') {
        !          2744:        /* ##: concatenate preceding and following tokens.  */
        !          2745:        /* Take out the first #, discard preceding whitespace.  */
        !          2746:        exp_p--;
        !          2747:        while (exp_p > lastp && is_hor_space[exp_p[-1]])
        !          2748:          --exp_p;
        !          2749:        /* Skip the second #.  */
        !          2750:        p++;
        !          2751:        /* Discard following whitespace.  */
        !          2752:        SKIP_WHITE_SPACE (p);
        !          2753:        concat = p;
        !          2754:       } else {
        !          2755:        /* Single #: stringify following argument ref.
        !          2756:           Don't leave the # in the expansion.  */
        !          2757:        exp_p--;
        !          2758:        SKIP_WHITE_SPACE (p);
        !          2759:        if (p == limit || ! is_idstart[*p] || nargs <= 0)
        !          2760:          error ("# operator should be followed by a macro argument name\n");
        !          2761:        else
        !          2762:          stringify = p;
        !          2763:       }
        !          2764:       break;
        !          2765:     }
        !          2766: 
        !          2767:     if (is_idchar[c] && nargs > 0) {
        !          2768:       U_CHAR *id_beg = p - 1;
        !          2769:       int id_len;
        !          2770: 
        !          2771:       --exp_p;
        !          2772:       while (p != limit && is_idchar[*p]) p++;
        !          2773:       id_len = p - id_beg;
        !          2774: 
        !          2775:       if (is_idstart[c]) {
        !          2776:        register struct arglist *arg;
        !          2777: 
        !          2778:        for (arg = arglist; arg != NULL; arg = arg->next) {
        !          2779:          struct reflist *tpat;
        !          2780: 
        !          2781:          if (arg->name[0] == c
        !          2782:              && arg->length == id_len
        !          2783:              && strncmp (arg->name, id_beg, id_len) == 0) {
        !          2784:            /* make a pat node for this arg and append it to the end of
        !          2785:               the pat list */
        !          2786:            tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
        !          2787:            tpat->next = NULL;
        !          2788:            tpat->stringify = stringify == id_beg;
        !          2789:            tpat->raw_before = concat == id_beg;
        !          2790:            tpat->raw_after = 0;
        !          2791: 
        !          2792:            if (endpat == NULL)
        !          2793:              defn->pattern = tpat;
        !          2794:            else
        !          2795:              endpat->next = tpat;
        !          2796:            endpat = tpat;
        !          2797: 
        !          2798:            tpat->argno = arg->argno;
        !          2799:            tpat->nchars = exp_p - lastp;
        !          2800:            {
        !          2801:              register U_CHAR *p1 = p;
        !          2802:              SKIP_WHITE_SPACE (p1);
        !          2803:              if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
        !          2804:                tpat->raw_after = 1;
        !          2805:            }
        !          2806:            lastp = exp_p;      /* place to start copying from next time */
        !          2807:            skipped_arg = 1;
        !          2808:            break;
        !          2809:          }
        !          2810:        }
        !          2811:       }
        !          2812: 
        !          2813:       /* If this was not a macro arg, copy it into the expansion.  */
        !          2814:       if (! skipped_arg) {
        !          2815:        register U_CHAR *lim1 = p;
        !          2816:        p = id_beg;
        !          2817:        while (p != lim1)
        !          2818:          *exp_p++ = *p++;
        !          2819:        if (stringify == id_beg)
        !          2820:          error ("# operator should be followed by a macro argument name\n");
        !          2821:       }
        !          2822:     }
        !          2823:   }
        !          2824: 
        !          2825:   if (limit < end) {
        !          2826:     /* Convert trailing whitespace to Newline-markers.  */
        !          2827:     while (limit < end && is_space[*limit]) {
        !          2828:       *exp_p++ = '\n';
        !          2829:       *exp_p++ = *limit++;
        !          2830:     }
        !          2831:   } else if (!traditional) {
        !          2832:     /* There is no trailing whitespace, so invent some.  */
        !          2833:     *exp_p++ = '\n';
        !          2834:     *exp_p++ = ' ';
        !          2835:   }
        !          2836: 
        !          2837:   *exp_p = '\0';
        !          2838: 
        !          2839:   defn->length = exp_p - defn->expansion;
        !          2840: 
        !          2841: #if 0
        !          2842: /* This isn't worth the time it takes.  */
        !          2843:   /* give back excess storage */
        !          2844:   defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
        !          2845: #endif
        !          2846: 
        !          2847:   return defn;
        !          2848: }
        !          2849: 
        !          2850: #ifdef DEBUG
        !          2851: /*
        !          2852:  * debugging routine ---- return a ptr to a string containing
        !          2853:  *   first n chars of s.  Returns a ptr to a static object
        !          2854:  *   since I happen to know it will fit.
        !          2855:  */
        !          2856: static U_CHAR *
        !          2857: prefix (s, n)
        !          2858:      U_CHAR *s;
        !          2859:      int n;
        !          2860: {
        !          2861:   static U_CHAR buf[1000];
        !          2862:   bcopy (s, buf, n);
        !          2863:   buf[n] = '\0';               /* this should not be necessary! */
        !          2864:   return buf;
        !          2865: }
        !          2866: #endif
        !          2867: 
        !          2868: /*
        !          2869:  * interpret #line command.  Remembers previously seen fnames
        !          2870:  * in its very own hash table.
        !          2871:  */
        !          2872: #define FNAME_HASHSIZE 37
        !          2873: 
        !          2874: do_line (buf, limit, op, keyword)
        !          2875:      U_CHAR *buf, *limit;
        !          2876:      FILE_BUF *op;
        !          2877:      struct directive *keyword;
        !          2878: {
        !          2879:   register U_CHAR *bp;
        !          2880:   FILE_BUF *ip = &instack[indepth];
        !          2881:   FILE_BUF tem;
        !          2882:   int new_lineno;
        !          2883: 
        !          2884:   /* Expand any macros.  */
        !          2885:   tem = expand_to_temp_buffer (buf, limit, 0);
        !          2886: 
        !          2887:   /* Point to macroexpanded line, which is null-terminated now.  */
        !          2888:   bp = tem.buf;
        !          2889:   SKIP_WHITE_SPACE (bp);
        !          2890: 
        !          2891:   if (!isdigit (*bp)) {
        !          2892:     error ("invalid format #line command");
        !          2893:     return;
        !          2894:   }
        !          2895: 
        !          2896:   /* The Newline at the end of this line remains to be processed.
        !          2897:      To put the next line at the specified line number,
        !          2898:      we must store a line number now that is one less.  */
        !          2899:   new_lineno = atoi (bp) - 1;
        !          2900: 
        !          2901:   /* skip over the line number.  */
        !          2902:   while (isdigit (*bp))
        !          2903:     bp++;
        !          2904:   if (*bp && !is_space[*bp]) {
        !          2905:     error ("invalid format #line command");
        !          2906:     return;
        !          2907:   }
        !          2908:     
        !          2909:   SKIP_WHITE_SPACE (bp);
        !          2910: 
        !          2911:   if (*bp == '\"') {
        !          2912:     static HASHNODE *fname_table[FNAME_HASHSIZE];
        !          2913:     HASHNODE *hp, **hash_bucket;
        !          2914:     U_CHAR *fname;
        !          2915:     int fname_length;
        !          2916: 
        !          2917:     fname = ++bp;
        !          2918: 
        !          2919:     while (*bp && *bp != '\"')
        !          2920:       bp++;
        !          2921:     if (*bp != '\"') {
        !          2922:       error ("invalid format #line command");
        !          2923:       return;
        !          2924:     }
        !          2925: 
        !          2926:     fname_length = bp - fname;
        !          2927: 
        !          2928:     bp++;
        !          2929:     SKIP_WHITE_SPACE (bp);
        !          2930:     if (*bp) {
        !          2931:       error ("invalid format #line command");
        !          2932:       return;
        !          2933:     }
        !          2934: 
        !          2935:     hash_bucket =
        !          2936:       &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
        !          2937:     for (hp = *hash_bucket; hp != NULL; hp = hp->next)
        !          2938:       if (hp->length == fname_length &&
        !          2939:          strncmp (hp->value.cpval, fname, fname_length) == 0) {
        !          2940:        ip->fname = hp->value.cpval;
        !          2941:        break;
        !          2942:       }
        !          2943:     if (hp == 0) {
        !          2944:       /* Didn't find it; cons up a new one.  */
        !          2945:       hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1);
        !          2946:       hp->next = *hash_bucket;
        !          2947:       *hash_bucket = hp;
        !          2948: 
        !          2949:       hp->length = fname_length;
        !          2950:       ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
        !          2951:       bcopy (fname, hp->value.cpval, fname_length);
        !          2952:     }
        !          2953:   } else if (*bp) {
        !          2954:     error ("invalid format #line command");
        !          2955:     return;
        !          2956:   }
        !          2957: 
        !          2958:   ip->lineno = new_lineno;
        !          2959:   output_line_command (ip, op, 0);
        !          2960:   check_expand (op, ip->length - (ip->bufp - ip->buf));
        !          2961: }
        !          2962: 
        !          2963: /*
        !          2964:  * remove all definitions of symbol from symbol table.
        !          2965:  * according to un*x /lib/cpp, it is not an error to undef
        !          2966:  * something that has no definitions, so it isn't one here either.
        !          2967:  */
        !          2968: do_undef (buf, limit, op, keyword)
        !          2969:      U_CHAR *buf, *limit;
        !          2970:      FILE_BUF *op;
        !          2971:      struct directive *keyword;
        !          2972: {
        !          2973:   HASHNODE *hp;
        !          2974: 
        !          2975:   SKIP_WHITE_SPACE (buf);
        !          2976: 
        !          2977:   while ((hp = lookup (buf, -1, -1)) != NULL) {
        !          2978:     if (hp->type != T_MACRO)
        !          2979:       error ("undefining `%s'", hp->name);
        !          2980:     delete_macro (hp);
        !          2981:   }
        !          2982: }
        !          2983: 
        !          2984: /*
        !          2985:  * Report a fatal error detected by the program we are processing.
        !          2986:  * Use the text of the line in the error message, then terminate.
        !          2987:  * (We use error() because it prints the filename & line#.)
        !          2988:  */
        !          2989: do_error (buf, limit, op, keyword)
        !          2990:      U_CHAR *buf, *limit;
        !          2991:      FILE_BUF *op;
        !          2992:      struct directive *keyword;
        !          2993: {
        !          2994:   int length = limit - buf;
        !          2995:   char *copy = (char *) xmalloc (length + 1);
        !          2996:   bcopy (buf, copy, length);
        !          2997:   copy[length] = 0;
        !          2998:   SKIP_WHITE_SPACE (copy);
        !          2999:   error ("#error %s", copy);
        !          3000:   exit (FATAL_EXIT_CODE);
        !          3001: }
        !          3002: 
        !          3003: #if 0
        !          3004: /* This was a fun hack, but #pragma seems to start to be useful.
        !          3005:    By failing to recognize it, we pass it through unchanged to cc1.  */
        !          3006: 
        !          3007: /*
        !          3008:  * the behavior of the #pragma directive is implementation defined.
        !          3009:  * this implementation defines it as follows.
        !          3010:  */
        !          3011: do_pragma ()
        !          3012: {
        !          3013:   close (0);
        !          3014:   if (open ("/dev/tty", O_RDONLY) != 0)
        !          3015:     goto nope;
        !          3016:   close (1);
        !          3017:   if (open ("/dev/tty", O_WRONLY) != 1)
        !          3018:     goto nope;
        !          3019:   execl ("/usr/games/hack", "#pragma", 0);
        !          3020:   execl ("/usr/games/rogue", "#pragma", 0);
        !          3021:   execl ("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0);
        !          3022:   execl ("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0);
        !          3023: nope:
        !          3024:   fatal ("You are in a maze of twisty compiler features, all different");
        !          3025: }
        !          3026: #endif
        !          3027: 
        !          3028: /* Just ignore #sccs, on systems where we define it at all.  */
        !          3029: do_sccs ()
        !          3030: {}
        !          3031: 
        !          3032: /*
        !          3033:  * handle #if command by
        !          3034:  *   1) inserting special `defined' keyword into the hash table
        !          3035:  *     that gets turned into 0 or 1 by special_symbol (thus,
        !          3036:  *     if the luser has a symbol called `defined' already, it won't
        !          3037:  *      work inside the #if command)
        !          3038:  *   2) rescan the input into a temporary output buffer
        !          3039:  *   3) pass the output buffer to the yacc parser and collect a value
        !          3040:  *   4) clean up the mess left from steps 1 and 2.
        !          3041:  *   5) call conditional_skip to skip til the next #endif (etc.),
        !          3042:  *      or not, depending on the value from step 3.
        !          3043:  */
        !          3044: 
        !          3045: do_if (buf, limit, op, keyword)
        !          3046:      U_CHAR *buf, *limit;
        !          3047:      FILE_BUF *op;
        !          3048:      struct directive *keyword;
        !          3049: {
        !          3050:   int value;
        !          3051:   FILE_BUF *ip = &instack[indepth];
        !          3052: 
        !          3053:   value = eval_if_expression (buf, limit - buf);
        !          3054:   conditional_skip (ip, value == 0, T_IF);
        !          3055: }
        !          3056: 
        !          3057: /*
        !          3058:  * handle a #elif directive by not changing  if_stack  either.
        !          3059:  * see the comment above do_else.
        !          3060:  */
        !          3061: 
        !          3062: do_elif (buf, limit, op, keyword)
        !          3063:      U_CHAR *buf, *limit;
        !          3064:      FILE_BUF *op;
        !          3065:      struct directive *keyword;
        !          3066: {
        !          3067:   int value;
        !          3068:   FILE_BUF *ip = &instack[indepth];
        !          3069: 
        !          3070:   if (if_stack == instack[indepth].if_stack) {
        !          3071:     error ("#elif not within a conditional");
        !          3072:     return;
        !          3073:   } else {
        !          3074:     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
        !          3075:       error ("#elif after #else");
        !          3076:       fprintf (stderr, " (matches line %d", if_stack->lineno);
        !          3077:       if (if_stack->fname != NULL && ip->fname != NULL &&
        !          3078:          strcmp (if_stack->fname, ip->fname) != 0)
        !          3079:        fprintf (stderr, ", file %s", if_stack->fname);
        !          3080:       fprintf (stderr, ")\n");
        !          3081:     }
        !          3082:     if_stack->type = T_ELIF;
        !          3083:   }
        !          3084: 
        !          3085:   if (if_stack->if_succeeded)
        !          3086:     skip_if_group (ip, 0);
        !          3087:   else {
        !          3088:     value = eval_if_expression (buf, limit - buf);
        !          3089:     if (value == 0)
        !          3090:       skip_if_group (ip, 0);
        !          3091:     else {
        !          3092:       ++if_stack->if_succeeded;        /* continue processing input */
        !          3093:       output_line_command (ip, op, 1);
        !          3094:     }
        !          3095:   }
        !          3096: }
        !          3097: 
        !          3098: /*
        !          3099:  * evaluate a #if expression in BUF, of length LENGTH,
        !          3100:  * then parse the result as a C expression and return the value as an int.
        !          3101:  */
        !          3102: static int
        !          3103: eval_if_expression (buf, length)
        !          3104:      U_CHAR *buf;
        !          3105:      int length;
        !          3106: {
        !          3107:   FILE_BUF temp_obuf;
        !          3108:   HASHNODE *save_defined;
        !          3109:   int value;
        !          3110: 
        !          3111:   save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, -1);
        !          3112:   temp_obuf = expand_to_temp_buffer (buf, buf + length, 0);
        !          3113:   delete_macro (save_defined); /* clean up special symbol */
        !          3114: 
        !          3115:   value = parse_c_expression (temp_obuf.buf);
        !          3116: 
        !          3117:   free (temp_obuf.buf);
        !          3118: 
        !          3119:   return value;
        !          3120: }
        !          3121: 
        !          3122: /*
        !          3123:  * routine to handle ifdef/ifndef.  Try to look up the symbol,
        !          3124:  * then do or don't skip to the #endif/#else/#elif depending
        !          3125:  * on what directive is actually being processed.
        !          3126:  */
        !          3127: do_xifdef (buf, limit, op, keyword)
        !          3128:      U_CHAR *buf, *limit;
        !          3129:      FILE_BUF *op;
        !          3130:      struct directive *keyword;
        !          3131: {
        !          3132:   int skip;
        !          3133:   FILE_BUF *ip = &instack[indepth];
        !          3134:   U_CHAR *end; 
        !          3135: 
        !          3136:   /* Discard leading and trailing whitespace.  */
        !          3137:   SKIP_WHITE_SPACE (buf);
        !          3138:   while (limit != buf && is_hor_space[limit[-1]]) limit--;
        !          3139: 
        !          3140:   /* Find the end of the identifier at the beginning.  */
        !          3141:   for (end = buf; is_idchar[*end]; end++);
        !          3142: 
        !          3143:   if (end == buf)
        !          3144:     {
        !          3145:       skip = (keyword->type == T_IFDEF);
        !          3146:       if (! traditional)
        !          3147:        warning (end == limit ? "#%s with no argument"
        !          3148:                 : "#%s argument starts with punctuation",
        !          3149:                 keyword->name);
        !          3150:     }
        !          3151:   else
        !          3152:     {
        !          3153:       if (pedantic && buf[0] >= '0' && buf[0] <= '9')
        !          3154:        warning ("#%s argument starts with a digit", keyword->name);
        !          3155:       else if (end != limit && !traditional)
        !          3156:        warning ("garbage at end of #%s argument", keyword->name);
        !          3157: 
        !          3158:       skip = (lookup (buf, end-buf, -1) == NULL) ^ (keyword->type == T_IFNDEF);
        !          3159:     }
        !          3160: 
        !          3161:   conditional_skip (ip, skip, T_IF);
        !          3162: }
        !          3163: 
        !          3164: /*
        !          3165:  * push TYPE on stack; then, if SKIP is nonzero, skip ahead.
        !          3166:  */
        !          3167: static
        !          3168: conditional_skip (ip, skip, type)
        !          3169:      FILE_BUF *ip;
        !          3170:      int skip;
        !          3171:      enum node_type type;
        !          3172: {
        !          3173:   IF_STACK_FRAME *temp;
        !          3174: 
        !          3175:   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
        !          3176:   temp->fname = ip->fname;
        !          3177:   temp->lineno = ip->lineno;
        !          3178:   temp->next = if_stack;
        !          3179:   if_stack = temp;
        !          3180: 
        !          3181:   if_stack->type = type;
        !          3182: 
        !          3183:   if (skip != 0) {
        !          3184:     skip_if_group (ip, 0);
        !          3185:     return;
        !          3186:   } else {
        !          3187:     ++if_stack->if_succeeded;
        !          3188:     output_line_command (ip, &outbuf, 1);
        !          3189:   }
        !          3190: }
        !          3191: 
        !          3192: /*
        !          3193:  * skip to #endif, #else, or #elif.  adjust line numbers, etc.
        !          3194:  * leaves input ptr at the sharp sign found.
        !          3195:  * If ANY is nonzero, return at next directive of any sort.
        !          3196:  */
        !          3197: static
        !          3198: skip_if_group (ip, any)
        !          3199:      FILE_BUF *ip;
        !          3200:      int any;
        !          3201: {
        !          3202:   register U_CHAR *bp = ip->bufp, *cp;
        !          3203:   register U_CHAR *endb = ip->buf + ip->length;
        !          3204:   struct directive *kt;
        !          3205:   IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */
        !          3206:   U_CHAR *beg_of_line = bp;
        !          3207: 
        !          3208:   while (bp < endb) {
        !          3209:     switch (*bp++) {
        !          3210:     case '/':                  /* possible comment */
        !          3211:       if (*bp == '\\' && bp[1] == '\n')
        !          3212:        newline_fix (bp);
        !          3213:       if (*bp == '*'
        !          3214: #ifdef CPLUSPLUS
        !          3215:          || *bp == '/'
        !          3216: #endif
        !          3217:          ) {
        !          3218:        ip->bufp = ++bp;
        !          3219:        bp = skip_to_end_of_comment (ip, &ip->lineno);
        !          3220:       }
        !          3221:       break;
        !          3222:     case '\"':
        !          3223:     case '\'':
        !          3224:       if (!traditional)
        !          3225:        bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno, 0, 0);
        !          3226:       break;
        !          3227:     case '\n':
        !          3228:       ++ip->lineno;
        !          3229:       beg_of_line = bp;
        !          3230:       break;
        !          3231:     case '#':
        !          3232:       ip->bufp = bp - 1;
        !          3233: 
        !          3234:       /* # keyword: a # must be first nonblank char on the line */
        !          3235:       if (beg_of_line == 0)
        !          3236:        break;
        !          3237:       /* Scan from start of line, skipping whitespace, comments
        !          3238:         and backslash-newlines, and see if we reach this #.
        !          3239:         If not, this # is not special.  */
        !          3240:       bp = beg_of_line;
        !          3241:       while (1) {
        !          3242:        if (is_hor_space[*bp])
        !          3243:          bp++;
        !          3244:        else if (*bp == '\\' && bp[1] == '\n')
        !          3245:          bp += 2;
        !          3246:        else if (*bp == '/' && bp[1] == '*') {
        !          3247:          bp += 2;
        !          3248:          while (!(*bp == '*' && bp[1] == '/'))
        !          3249:            bp++;
        !          3250:          bp += 2;
        !          3251:        }
        !          3252: #ifdef CPLUSPLUS
        !          3253:        else if (*bp == '/' && bp[1] == '/') {
        !          3254:          bp += 2;
        !          3255:          while (*bp++ != '\n') ;
        !          3256:         }
        !          3257: #endif
        !          3258:        else break;
        !          3259:       }
        !          3260:       if (bp != ip->bufp) {
        !          3261:        bp = ip->bufp + 1;      /* Reset bp to after the #.  */
        !          3262:        break;
        !          3263:       }
        !          3264: 
        !          3265:       bp = ip->bufp + 1;               /* point at '#' */
        !          3266: 
        !          3267:       /* Skip whitespace and \-newline.  */
        !          3268:       while (1) {
        !          3269:        if (is_hor_space[*bp])
        !          3270:          bp++;
        !          3271:        else if (*bp == '\\' && bp[1] == '\n')
        !          3272:          bp += 2;
        !          3273:        else break;
        !          3274:       }
        !          3275: 
        !          3276:       cp = bp;
        !          3277: 
        !          3278:       /* Now find end of directive name.
        !          3279:         If we encounter a backslash-newline, exchange it with any following
        !          3280:         symbol-constituents so that we end up with a contiguous name.  */
        !          3281: 
        !          3282:       while (1) {
        !          3283:        if (is_idchar[*bp])
        !          3284:          bp++;
        !          3285:        else {
        !          3286:          if (*bp == '\\' && bp[1] == '\n')
        !          3287:            name_newline_fix (bp);
        !          3288:          if (is_idchar[*bp])
        !          3289:            bp++;
        !          3290:          else break;
        !          3291:        }
        !          3292:       }
        !          3293: 
        !          3294:       for (kt = directive_table; kt->length >= 0; kt++) {
        !          3295:        IF_STACK_FRAME *temp;
        !          3296:        if (strncmp (cp, kt->name, kt->length) == 0
        !          3297:            && !is_idchar[cp[kt->length]]) {
        !          3298: 
        !          3299:          /* If we are asked to return on next directive,
        !          3300:             do so now.  */
        !          3301:          if (any)
        !          3302:            return;
        !          3303: 
        !          3304:          switch (kt->type) {
        !          3305:          case T_IF:
        !          3306:          case T_IFDEF:
        !          3307:          case T_IFNDEF:
        !          3308:            temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
        !          3309:            temp->next = if_stack;
        !          3310:            if_stack = temp;
        !          3311:            temp->lineno = ip->lineno;
        !          3312:            temp->fname = ip->fname;
        !          3313:            temp->type = kt->type;
        !          3314:            break;
        !          3315:          case T_ELSE:
        !          3316:          case T_ENDIF:
        !          3317:            if (pedantic && if_stack != save_if_stack)
        !          3318:              validate_else (bp);
        !          3319:          case T_ELIF:
        !          3320:            if (if_stack == instack[indepth].if_stack) {
        !          3321:              error ("#%s not within a conditional", kt->name);
        !          3322:              break;
        !          3323:            }
        !          3324:            else if (if_stack == save_if_stack)
        !          3325:              return;           /* found what we came for */
        !          3326: 
        !          3327:            if (kt->type != T_ENDIF) {
        !          3328:              if (if_stack->type == T_ELSE)
        !          3329:                error ("#else or #elif after #else");
        !          3330:              if_stack->type = kt->type;
        !          3331:              break;
        !          3332:            }
        !          3333: 
        !          3334:            temp = if_stack;
        !          3335:            if_stack = if_stack->next;
        !          3336:            free (temp);
        !          3337:            break;
        !          3338:          }
        !          3339:          break;
        !          3340:        }
        !          3341:       }
        !          3342:     }
        !          3343:   }
        !          3344:   ip->bufp = bp;
        !          3345:   /* after this returns, rescan will exit because ip->bufp
        !          3346:      now points to the end of the buffer.
        !          3347:      rescan is responsible for the error message also.  */
        !          3348: }
        !          3349: 
        !          3350: /*
        !          3351:  * handle a #else directive.  Do this by just continuing processing
        !          3352:  * without changing  if_stack ;  this is so that the error message
        !          3353:  * for missing #endif's etc. will point to the original #if.  It
        !          3354:  * is possible that something different would be better.
        !          3355:  */
        !          3356: do_else (buf, limit, op, keyword)
        !          3357:      U_CHAR *buf, *limit;
        !          3358:      FILE_BUF *op;
        !          3359:      struct directive *keyword;
        !          3360: {
        !          3361:   FILE_BUF *ip = &instack[indepth];
        !          3362: 
        !          3363:   if (pedantic) {
        !          3364:     SKIP_WHITE_SPACE (buf);
        !          3365:     if (buf != limit)
        !          3366:       warning ("text following #else violates ANSI standard");
        !          3367:   }
        !          3368: 
        !          3369:   if (if_stack == instack[indepth].if_stack) {
        !          3370:     error ("#else not within a conditional");
        !          3371:     return;
        !          3372:   } else {
        !          3373:     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
        !          3374:       error ("#else after #else");
        !          3375:       fprintf (stderr, " (matches line %d", if_stack->lineno);
        !          3376:       if (strcmp (if_stack->fname, ip->fname) != 0)
        !          3377:        fprintf (stderr, ", file %s", if_stack->fname);
        !          3378:       fprintf (stderr, ")\n");
        !          3379:     }
        !          3380:     if_stack->type = T_ELSE;
        !          3381:   }
        !          3382: 
        !          3383:   if (if_stack->if_succeeded)
        !          3384:     skip_if_group (ip, 0);
        !          3385:   else {
        !          3386:     ++if_stack->if_succeeded;  /* continue processing input */
        !          3387:     output_line_command (ip, op, 1);
        !          3388:   }
        !          3389: }
        !          3390: 
        !          3391: /*
        !          3392:  * unstack after #endif command
        !          3393:  */
        !          3394: do_endif (buf, limit, op, keyword)
        !          3395:      U_CHAR *buf, *limit;
        !          3396:      FILE_BUF *op;
        !          3397:      struct directive *keyword;
        !          3398: {
        !          3399:   if (pedantic) {
        !          3400:     SKIP_WHITE_SPACE (buf);
        !          3401:     if (buf != limit)
        !          3402:       warning ("text following #endif violates ANSI standard");
        !          3403:   }
        !          3404: 
        !          3405:   if (if_stack == instack[indepth].if_stack)
        !          3406:     error ("unbalanced #endif");
        !          3407:   else {
        !          3408:     IF_STACK_FRAME *temp = if_stack;
        !          3409:     if_stack = if_stack->next;
        !          3410:     free (temp);
        !          3411:     output_line_command (&instack[indepth], op, 1);
        !          3412:   }
        !          3413: }
        !          3414: 
        !          3415: /* When an #else or #endif is found while skipping failed conditional,
        !          3416:    if -pedantic was specified, this is called to warn about text after
        !          3417:    the command name.  P points to the first char after the command name.  */
        !          3418: 
        !          3419: validate_else (p)
        !          3420:      register U_CHAR *p;
        !          3421: {
        !          3422:   /* Advance P over whitespace and comments.  */
        !          3423:   while (1) {
        !          3424:     if (*p == '\\' && p[1] == '\n')
        !          3425:       p += 2;
        !          3426:     if (is_hor_space[*p])
        !          3427:       p++;
        !          3428:     else if (*p == '/') {
        !          3429:       if (p[1] == '\\' && p[2] == '\n')
        !          3430:        newline_fix (p + 1);
        !          3431:       if (p[1] == '*') {
        !          3432:        p += 2;
        !          3433:        /* Don't bother warning about unterminated comments
        !          3434:           since that will happen later.  Just be sure to exit.  */
        !          3435:        while (*p) {
        !          3436:          if (p[1] == '\\' && p[2] == '\n')
        !          3437:            newline_fix (p + 1);
        !          3438:          if (*p == '*' && p[1] == '/') {
        !          3439:            p += 2;
        !          3440:            break;
        !          3441:          }
        !          3442:          p++;
        !          3443:        }
        !          3444:       }
        !          3445: #ifdef CPLUSPLUS
        !          3446:       else if (p[1] == '/') {
        !          3447:        p += 2;
        !          3448:        while (*p && *p++ != '\n') ;
        !          3449:       }
        !          3450: #endif
        !          3451:     } else break;
        !          3452:   }
        !          3453:   if (*p && *p != '\n')
        !          3454:     warning ("text following #else or #endif violates ANSI standard");
        !          3455: }
        !          3456: 
        !          3457: /*
        !          3458:  * Skip a comment, assuming the input ptr immediately follows the
        !          3459:  * initial slash-star.  Bump line counter as necessary.
        !          3460:  * (The canonical line counter is &ip->lineno).
        !          3461:  * Don't use this routine (or the next one) if bumping the line
        !          3462:  * counter is not sufficient to deal with newlines in the string.
        !          3463:  */
        !          3464: U_CHAR *
        !          3465: skip_to_end_of_comment (ip, line_counter)
        !          3466:      register FILE_BUF *ip;
        !          3467:      int *line_counter;                /* place to remember newlines, or NULL */
        !          3468: {
        !          3469:   register U_CHAR *limit = ip->buf + ip->length;
        !          3470:   register U_CHAR *bp = ip->bufp;
        !          3471:   FILE_BUF *op = &outbuf;      /* JF */
        !          3472:   int output = put_out_comments && !line_counter;
        !          3473: 
        !          3474:        /* JF this line_counter stuff is a crock to make sure the
        !          3475:           comment is only put out once, no matter how many times
        !          3476:           the comment is skipped.  It almost works */
        !          3477:   if (output) {
        !          3478:     *op->bufp++ = '/';
        !          3479:     *op->bufp++ = '*';
        !          3480:   }
        !          3481: #ifdef CPLUSPLUS
        !          3482:   if (bp[-1] == '/') {
        !          3483:     if (output)
        !          3484:       {
        !          3485:        while (bp < limit)
        !          3486:          if ((*op->bufp++ = *bp++) == '\n')
        !          3487:            {
        !          3488:              bp--;
        !          3489:              break;
        !          3490:            }
        !          3491:        op->bufp[-1] = '*';
        !          3492:        *op->bufp++ = '/';
        !          3493:        *op->bufp++ = '\n';
        !          3494:       }
        !          3495:     else
        !          3496:       {
        !          3497:        while (bp < limit) {
        !          3498:          if (*bp++ == '\n')
        !          3499:            {
        !          3500:              bp--;
        !          3501:              break;
        !          3502:            }
        !          3503:        }
        !          3504:     }
        !          3505:     ip->bufp = bp;
        !          3506:     return bp;
        !          3507:   }
        !          3508: #endif
        !          3509:   while (bp < limit) {
        !          3510:     if (output)
        !          3511:       *op->bufp++ = *bp;
        !          3512:     switch (*bp++) {
        !          3513:     case '\n':
        !          3514:       if (line_counter != NULL)
        !          3515:        ++*line_counter;
        !          3516:       if (output)
        !          3517:        ++op->lineno;
        !          3518:       break;
        !          3519:     case '*':
        !          3520:       if (*bp == '\\' && bp[1] == '\n')
        !          3521:        newline_fix (bp);
        !          3522:       if (*bp == '/') {
        !          3523:         if (output)
        !          3524:          *op->bufp++ = '/';
        !          3525:        ip->bufp = ++bp;
        !          3526:        return bp;
        !          3527:       }
        !          3528:       break;
        !          3529:     }
        !          3530:   }
        !          3531:   ip->bufp = bp;
        !          3532:   return bp;
        !          3533: }
        !          3534: 
        !          3535: /*
        !          3536:  * Skip over a quoted string.  BP points to the opening quote.
        !          3537:  * Returns a pointer after the closing quote.  Don't go past LIMIT.
        !          3538:  * START_LINE is the line number of the starting point (but it need
        !          3539:  * not be valid if the starting point is inside a macro expansion).
        !          3540:  *
        !          3541:  * The input stack state is not changed.
        !          3542:  *
        !          3543:  * If COUNT_NEWLINES is nonzero, it points to an int to increment
        !          3544:  * for each newline passed.
        !          3545:  *
        !          3546:  * If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
        !          3547:  * if we pass a backslash-newline.
        !          3548:  *
        !          3549:  * If EOFP is nonzero, set *EOFP to 1 if the string is unterminated.
        !          3550:  */
        !          3551: U_CHAR *
        !          3552: skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp)
        !          3553:      register U_CHAR *bp;
        !          3554:      register U_CHAR *limit;
        !          3555:      int start_line;
        !          3556:      int *count_newlines;
        !          3557:      int *backslash_newlines_p;
        !          3558:      int *eofp;
        !          3559: {
        !          3560:   register U_CHAR c, match;
        !          3561: 
        !          3562:   match = *bp++;
        !          3563:   while (1) {
        !          3564:     if (bp >= limit) {
        !          3565:       error_with_line (line_for_error (start_line),
        !          3566:                       "unterminated string constant");
        !          3567:       if (eofp)
        !          3568:        *eofp = 1;
        !          3569:       break;
        !          3570:     }
        !          3571:     c = *bp++;
        !          3572:     if (c == '\\') {
        !          3573:       while (*bp == '\\' && bp[1] == '\n') {
        !          3574:        if (backslash_newlines_p)
        !          3575:          *backslash_newlines_p = 1;
        !          3576:        if (count_newlines)
        !          3577:          ++*count_newlines;
        !          3578:        bp += 2;
        !          3579:       }
        !          3580:       if (*bp == '\n' && count_newlines) {
        !          3581:        if (backslash_newlines_p)
        !          3582:          *backslash_newlines_p = 1;
        !          3583:        ++*count_newlines;
        !          3584:       }
        !          3585:       bp++;
        !          3586:     } else if (c == '\n') {
        !          3587:       if (count_newlines)
        !          3588:        ++*count_newlines;
        !          3589:     } else if (c == match)
        !          3590:       break;
        !          3591:   }
        !          3592:   return bp;
        !          3593: }
        !          3594: 
        !          3595: /*
        !          3596:  * write out a #line command, for instance, after an #include file.
        !          3597:  * If CONDITIONAL is nonzero, we can omit the #line if it would
        !          3598:  * appear to be a no-op, and we can output a few newlines instead
        !          3599:  * if we want to increase the line number by a small amount.
        !          3600:  */
        !          3601: static
        !          3602: output_line_command (ip, op, conditional)
        !          3603:      FILE_BUF *ip, *op;
        !          3604:      int conditional;
        !          3605: {
        !          3606:   int len;
        !          3607:   char line_cmd_buf[500];
        !          3608: 
        !          3609:   if (no_line_commands
        !          3610:       || ip->fname == NULL
        !          3611:       || no_output) {
        !          3612:     op->lineno = ip->lineno;
        !          3613:     return;
        !          3614:   }
        !          3615: 
        !          3616:   if (conditional) {
        !          3617:     if (ip->lineno == op->lineno)
        !          3618:       return;
        !          3619: 
        !          3620:     /* If the inherited line number is a little too small,
        !          3621:        output some newlines instead of a #line command.  */
        !          3622:     if (ip->lineno > op->lineno && ip->lineno < op->lineno + 8) {
        !          3623:       check_expand (op, 10);
        !          3624:       while (ip->lineno > op->lineno) {
        !          3625:        *op->bufp++ = '\n';
        !          3626:        op->lineno++;
        !          3627:       }
        !          3628:       return;
        !          3629:     }
        !          3630:   }
        !          3631: 
        !          3632: #ifdef OUTPUT_LINE_COMMANDS
        !          3633:   sprintf (line_cmd_buf, "#line %d \"%s\"\n", ip->lineno, ip->fname);
        !          3634: #else
        !          3635:   sprintf (line_cmd_buf, "# %d \"%s\"\n", ip->lineno, ip->fname);
        !          3636: #endif
        !          3637:   len = strlen (line_cmd_buf);
        !          3638:   check_expand (op, len + 1);
        !          3639:   if (op->bufp > op->buf && op->bufp[-1] != '\n')
        !          3640:     *op->bufp++ = '\n';
        !          3641:   bcopy (line_cmd_buf, op->bufp, len);
        !          3642:   op->bufp += len;
        !          3643:   op->lineno = ip->lineno;
        !          3644: }
        !          3645: 
        !          3646: /* This structure represents one parsed argument in a macro call.
        !          3647:    `raw' points to the argument text as written (`raw_length' is its length).
        !          3648:    `expanded' points to the argument's macro-expansion
        !          3649:    (its length is `expand_length').
        !          3650:    `stringified_length' is the length the argument would have
        !          3651:    if stringified.
        !          3652:    `free1' and `free2', if nonzero, point to blocks to be freed
        !          3653:    when the macro argument data is no longer needed.  */
        !          3654: 
        !          3655: struct argdata {
        !          3656:   U_CHAR *raw, *expanded;
        !          3657:   int raw_length, expand_length;
        !          3658:   int stringified_length;
        !          3659:   U_CHAR *free1, *free2;
        !          3660:   char newlines;
        !          3661:   char comments;
        !          3662: };
        !          3663: 
        !          3664: /* Expand a macro call.
        !          3665:    HP points to the symbol that is the macro being called.
        !          3666:    Put the result of expansion onto the input stack
        !          3667:    so that subsequent input by our caller will use it.
        !          3668: 
        !          3669:    If macro wants arguments, caller has already verified that
        !          3670:    an argument list follows; arguments come from the input stack.  */
        !          3671: 
        !          3672: macroexpand (hp, op)
        !          3673:      HASHNODE *hp;
        !          3674:      FILE_BUF *op;
        !          3675: {
        !          3676:   int nargs;
        !          3677:   DEFINITION *defn = hp->value.defn;
        !          3678:   register U_CHAR *xbuf;
        !          3679:   int xbuf_len;
        !          3680:   int start_line = instack[indepth].lineno;
        !          3681: 
        !          3682:   /* it might not actually be a macro.  */
        !          3683:   if (hp->type != T_MACRO)
        !          3684:     {
        !          3685:       special_symbol (hp, op);
        !          3686:       return;
        !          3687:     }
        !          3688: 
        !          3689:   nargs = defn->nargs;
        !          3690: 
        !          3691:   if (nargs >= 0)
        !          3692:     {
        !          3693:       register int i;
        !          3694:       struct argdata *args;
        !          3695:       char *parse_error = 0;
        !          3696: 
        !          3697:       args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
        !          3698: 
        !          3699:       for (i = 0; i < nargs; i++) {
        !          3700:        args[i].raw = args[i].expanded = (U_CHAR *) "";
        !          3701:        args[i].raw_length = args[i].expand_length
        !          3702:          = args[i].stringified_length = 0;
        !          3703:        args[i].free1 = args[i].free2 = 0;
        !          3704:       }
        !          3705: 
        !          3706:       /* Parse all the macro args that are supplied.  I counts them.
        !          3707:         The first NARGS args are stored in ARGS.
        !          3708:         The rest are discarded.  */
        !          3709:       i = 0;
        !          3710:       do {
        !          3711:        /* Discard the open-parenthesis or comma before the next arg.  */
        !          3712:        ++instack[indepth].bufp;
        !          3713:        if (parse_error = macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0))
        !          3714:          {
        !          3715:            error_with_line (line_for_error (start_line), parse_error);
        !          3716:            break;
        !          3717:          }
        !          3718:        i++;
        !          3719:       } while (*instack[indepth].bufp != ')');
        !          3720: 
        !          3721:       if (nargs == 0 && i == 1) {
        !          3722:        register U_CHAR *bp = args[0].raw;
        !          3723:        register U_CHAR *lim = bp + args[0].raw_length;
        !          3724:        while (bp != lim && is_space[*bp]) bp++;
        !          3725:        if (bp != lim)
        !          3726:          error ("arguments given to macro `%s'", hp->name);
        !          3727:       } else if (i < nargs)
        !          3728:        error ("only %d args to macro `%s'", i, hp->name);
        !          3729:       else if (i > nargs)
        !          3730:        error ("too many (%d) args to macro `%s'", i, hp->name);
        !          3731: 
        !          3732:       /* Swallow the closeparen.  */
        !          3733:       ++instack[indepth].bufp;
        !          3734: 
        !          3735:       /* If macro wants zero args, we parsed the arglist for checking only.
        !          3736:         Read directly from the macro definition.  */
        !          3737:       if (nargs == 0) {
        !          3738:        xbuf = defn->expansion;
        !          3739:        xbuf_len = defn->length;
        !          3740:       } else {
        !          3741:        register U_CHAR *exp = defn->expansion;
        !          3742:        register int offset;    /* offset in expansion,
        !          3743:                                   copied a piece at a time */
        !          3744:        register int totlen;    /* total amount of exp buffer filled so far */
        !          3745: 
        !          3746:        register struct reflist *ap;
        !          3747: 
        !          3748:        /* Macro really takes args.  Compute the expansion of this call.  */
        !          3749: 
        !          3750:        /* Compute length in characters of the macro's expansion.  */
        !          3751:        xbuf_len = defn->length;
        !          3752:        for (ap = defn->pattern; ap != NULL; ap = ap->next) {
        !          3753:          if (ap->stringify)
        !          3754:            xbuf_len += args[ap->argno].stringified_length;
        !          3755:          else if (ap->raw_before || ap->raw_after)
        !          3756:            xbuf_len += args[ap->argno].raw_length;
        !          3757:          else
        !          3758:            xbuf_len += args[ap->argno].expand_length;
        !          3759:        }
        !          3760: 
        !          3761:        xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
        !          3762: 
        !          3763:        /* Generate in XBUF the complete expansion
        !          3764:           with arguments substituted in.
        !          3765:           TOTLEN is the total size generated so far.
        !          3766:           OFFSET is the index in the definition
        !          3767:           of where we are copying from.  */
        !          3768:        offset = totlen = 0;
        !          3769:        for (ap = defn->pattern; ap != NULL; ap = ap->next) {
        !          3770:          register struct argdata *arg = &args[ap->argno];
        !          3771: 
        !          3772:          for (i = 0; i < ap->nchars; i++)
        !          3773:            xbuf[totlen++] = exp[offset++];
        !          3774: 
        !          3775:          if (ap->stringify != 0) {
        !          3776:            int arglen = arg->raw_length;
        !          3777:            int escaped = 0;
        !          3778:            int in_string = 0;
        !          3779:            int c;
        !          3780:            i = 0;
        !          3781:            while (i < arglen
        !          3782:                   && (c = arg->raw[i], is_space[c]))
        !          3783:              i++;
        !          3784:            while (i < arglen
        !          3785:                   && (c = arg->raw[arglen - 1], is_space[c]))
        !          3786:              arglen--;
        !          3787:            xbuf[totlen++] = '\"'; /* insert beginning quote */
        !          3788:            for (; i < arglen; i++) {
        !          3789:              c = arg->raw[i];
        !          3790: 
        !          3791:              /* Special markers Newline Space and Newline Newline
        !          3792:                 generate nothing for a stringified argument.  */
        !          3793:              if (c == '\n') {
        !          3794:                i++;
        !          3795:                continue;
        !          3796:              }
        !          3797: 
        !          3798:              /* Internal sequences of whitespace are replaced by one space.  */
        !          3799:              if (is_space[c]) {
        !          3800:                while (c = arg->raw[i+1], is_space[c]) i++;
        !          3801:                c = ' ';
        !          3802:              }
        !          3803: 
        !          3804:              if (escaped)
        !          3805:                escaped = 0;
        !          3806:              else {
        !          3807:                if (c == '\\')
        !          3808:                  escaped = 1;
        !          3809:                if (in_string && c == in_string)
        !          3810:                  in_string = 0;
        !          3811:                else if (c == '\"' || c == '\'')
        !          3812:                  in_string = c;
        !          3813:              }
        !          3814: 
        !          3815:              /* Escape these chars */
        !          3816:              if (c == '\"' || (in_string && c == '\\'))
        !          3817:                xbuf[totlen++] = '\\';
        !          3818:              if (isprint (c))
        !          3819:                xbuf[totlen++] = c;
        !          3820:              else {
        !          3821:                sprintf (&xbuf[totlen], "\\%03o", (unsigned int) c);
        !          3822:                totlen += 4;
        !          3823:              }
        !          3824:            }
        !          3825:            xbuf[totlen++] = '\"'; /* insert ending quote */
        !          3826:          } else if (ap->raw_before || ap->raw_after) {
        !          3827:            U_CHAR *p1 = arg->raw;
        !          3828:            U_CHAR *l1 = p1 + arg->raw_length;
        !          3829:            if (ap->raw_before) {
        !          3830:              while (p1 != l1 && is_space[*p1]) p1++;
        !          3831:              while (p1 != l1 && is_idchar[*p1])
        !          3832:                xbuf[totlen++] = *p1++;
        !          3833:              /* Delete any no-reexpansion marker that follows
        !          3834:                 an identifier at the beginning of the argument
        !          3835:                 if the argument is concatenated with what precedes it.  */
        !          3836:              if (p1[0] == '\n' && p1[1] == '-')
        !          3837:                p1 += 2;
        !          3838:            }
        !          3839:            if (ap->raw_after) {
        !          3840:              /* Arg is concatenated after: delete trailing whitespace,
        !          3841:                 whitespace markers, and no-reexpansion markers.  */
        !          3842:              while (p1 != l1) {
        !          3843:                if (is_space[l1[-1]]) l1--;
        !          3844:                else if (l1[-1] == '-') {
        !          3845:                  U_CHAR *p2 = l1 - 1;
        !          3846:                  /* If a `-' is preceded by an odd number of newlines then it
        !          3847:                     and the last newline are a no-reexpansion marker.  */
        !          3848:                  while (p2 != p1 && p2[-1] == '\n') p2--;
        !          3849:                  if ((l1 - 1 - p2) & 1) {
        !          3850:                    l1 -= 2;
        !          3851:                  }
        !          3852:                  else break;
        !          3853:                }
        !          3854:                else break;
        !          3855:              }
        !          3856:            }
        !          3857:            bcopy (p1, xbuf + totlen, l1 - p1);
        !          3858:            totlen += l1 - p1;
        !          3859:          } else {
        !          3860:            bcopy (arg->expanded, xbuf + totlen, arg->expand_length);
        !          3861:            totlen += arg->expand_length;
        !          3862:          }
        !          3863: 
        !          3864:          if (totlen > xbuf_len)
        !          3865:            abort ();
        !          3866:        }
        !          3867: 
        !          3868:        /* if there is anything left of the definition
        !          3869:           after handling the arg list, copy that in too. */
        !          3870: 
        !          3871:        for (i = offset; i < defn->length; i++)
        !          3872:          xbuf[totlen++] = exp[i];
        !          3873: 
        !          3874:        xbuf[totlen] = 0;
        !          3875:        xbuf_len = totlen;
        !          3876: 
        !          3877:        for (i = 0; i < nargs; i++) {
        !          3878:          if (args[i].free1 != 0)
        !          3879:            free (args[i].free1);
        !          3880:          if (args[i].free2 != 0)
        !          3881:            free (args[i].free2);
        !          3882:        }
        !          3883:       }
        !          3884:     }
        !          3885:   else
        !          3886:     {
        !          3887:       xbuf = defn->expansion;
        !          3888:       xbuf_len = defn->length;
        !          3889:     }
        !          3890: 
        !          3891:   /* Now put the expansion on the input stack
        !          3892:      so our caller will commence reading from it.  */
        !          3893:   {
        !          3894:     register FILE_BUF *ip2;
        !          3895: 
        !          3896:     ip2 = &instack[++indepth];
        !          3897: 
        !          3898:     ip2->fname = 0;
        !          3899:     ip2->lineno = 0;
        !          3900:     ip2->buf = xbuf;
        !          3901:     ip2->length = xbuf_len;
        !          3902:     ip2->bufp = xbuf;
        !          3903:     ip2->free = (nargs > 0) ? xbuf : 0;
        !          3904:     ip2->macro = hp;
        !          3905:     ip2->if_stack = if_stack;
        !          3906: 
        !          3907:     if (!traditional)
        !          3908:       hp->type = T_DISABLED;
        !          3909:   }
        !          3910: }
        !          3911: 
        !          3912: /*
        !          3913:  * Parse a macro argument and store the info on it into *ARGPTR.
        !          3914:  * Return nonzero to indicate a syntax error.
        !          3915:  */
        !          3916: 
        !          3917: char *
        !          3918: macarg (argptr)
        !          3919:      register struct argdata *argptr;
        !          3920: {
        !          3921:   FILE_BUF *ip = &instack[indepth];
        !          3922:   int paren = 0;
        !          3923:   int newlines = 0;
        !          3924:   int comments = 0;
        !          3925: 
        !          3926:   /* Try to parse as much of the argument as exists at this
        !          3927:      input stack level.  */
        !          3928:   U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
        !          3929:                        &paren, &newlines, &comments);
        !          3930: 
        !          3931:   /* If we find the end of the argument at this level,
        !          3932:      set up *ARGPTR to point at it in the input stack.  */
        !          3933:   if (!(ip->fname != 0 && (newlines != 0 || comments != 0))
        !          3934:       && bp != ip->buf + ip->length) {
        !          3935:     if (argptr != 0) {
        !          3936:       argptr->raw = ip->bufp;
        !          3937:       argptr->raw_length = bp - ip->bufp;
        !          3938:     }
        !          3939:     ip->bufp = bp;
        !          3940:   } else {
        !          3941:     /* This input stack level ends before the macro argument does.
        !          3942:        We must pop levels and keep parsing.
        !          3943:        Therefore, we must allocate a temporary buffer and copy
        !          3944:        the macro argument into it.  */
        !          3945:     int bufsize = bp - ip->bufp;
        !          3946:     int extra = newlines;
        !          3947:     U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1);
        !          3948:     int final_start = 0;
        !          3949: 
        !          3950:     bcopy (ip->bufp, buffer, bufsize);
        !          3951:     ip->bufp = bp;
        !          3952:     ip->lineno += newlines;
        !          3953: 
        !          3954:     while (bp == ip->buf + ip->length) {
        !          3955:       if (instack[indepth].macro == 0) {
        !          3956:        free (buffer);
        !          3957:        return "Unterminated macro call";
        !          3958:       }
        !          3959:       ip->macro->type = T_MACRO;
        !          3960:       free (ip->buf);
        !          3961:       ip = &instack[--indepth];
        !          3962:       newlines = 0;
        !          3963:       comments = 0;
        !          3964:       bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
        !          3965:                    &newlines, &comments);
        !          3966:       final_start = bufsize;
        !          3967:       bufsize += bp - ip->bufp;
        !          3968:       extra += newlines;
        !          3969:       buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1);
        !          3970:       bcopy (ip->bufp, buffer + bufsize - (bp - ip->bufp), bp - ip->bufp);
        !          3971:       ip->bufp = bp;
        !          3972:       ip->lineno += newlines;
        !          3973:     }
        !          3974: 
        !          3975:     /* Now, if arg is actually wanted, record its raw form,
        !          3976:        discarding comments and duplicating newlines in whatever
        !          3977:        part of it did not come from a macro expansion.
        !          3978:        EXTRA space has been preallocated for duplicating the newlines.
        !          3979:        FINAL_START is the index of the start of that part.  */
        !          3980:     if (argptr != 0) {
        !          3981:       argptr->raw = buffer;
        !          3982:       argptr->raw_length = bufsize;
        !          3983:       argptr->free1 = buffer;
        !          3984:       argptr->newlines = newlines;
        !          3985:       argptr->comments = comments;
        !          3986:       if ((newlines || comments) && ip->fname != 0)
        !          3987:        argptr->raw_length
        !          3988:          = final_start +
        !          3989:            discard_comments (argptr->raw + final_start,
        !          3990:                              argptr->raw_length - final_start,
        !          3991:                              newlines);
        !          3992:       argptr->raw[argptr->raw_length] = 0;
        !          3993:       if (argptr->raw_length > bufsize + extra)
        !          3994:        abort ();
        !          3995:     }
        !          3996:   }
        !          3997: 
        !          3998:   /* If we are not discarding this argument,
        !          3999:      macroexpand it and compute its length as stringified.
        !          4000:      All this info goes into *ARGPTR.  */
        !          4001: 
        !          4002:   if (argptr != 0) {
        !          4003:     FILE_BUF obuf;
        !          4004:     register U_CHAR *buf, *lim;
        !          4005:     register int totlen;
        !          4006: 
        !          4007:     obuf = expand_to_temp_buffer (argptr->raw,
        !          4008:                                  argptr->raw + argptr->raw_length,
        !          4009:                                  1);
        !          4010: 
        !          4011:     argptr->expanded = obuf.buf;
        !          4012:     argptr->expand_length = obuf.length;
        !          4013:     argptr->free2 = obuf.buf;
        !          4014: 
        !          4015:     buf = argptr->raw;
        !          4016:     lim = buf + argptr->raw_length;
        !          4017: 
        !          4018:     while (buf != lim && is_space[*buf])
        !          4019:       buf++;
        !          4020:     while (buf != lim && is_space[lim[-1]])
        !          4021:       lim--;
        !          4022:     totlen = 2;                /* Count opening and closing quote.  */
        !          4023:     while (buf != lim) {
        !          4024:       register U_CHAR c = *buf++;
        !          4025:       totlen++;
        !          4026:       /* Internal sequences of whitespace are replaced by one space.  */
        !          4027:       if (is_space[c])
        !          4028:        SKIP_ALL_WHITE_SPACE (buf);
        !          4029:       else if (c == '\"' || c == '\\') /* escape these chars */
        !          4030:        totlen++;
        !          4031:       else if (!isprint (c))
        !          4032:        totlen += 3;
        !          4033:     }
        !          4034:     argptr->stringified_length = totlen;
        !          4035:   }
        !          4036:   return 0;
        !          4037: }
        !          4038: 
        !          4039: /* Scan text from START (inclusive) up to LIMIT (exclusive),
        !          4040:    counting parens in *DEPTHPTR,
        !          4041:    and return if reach LIMIT
        !          4042:    or before a `)' that would make *DEPTHPTR negative
        !          4043:    or before a comma when *DEPTHPTR is zero.
        !          4044:    Single and double quotes are matched and termination
        !          4045:    is inhibited within them.  Comments also inhibit it.
        !          4046:    Value returned is pointer to stopping place.
        !          4047: 
        !          4048:    Increment *NEWLINES each time a newline is passed.
        !          4049:    Set *COMMENTS to 1 if a comment is seen.  */
        !          4050: 
        !          4051: U_CHAR *
        !          4052: macarg1 (start, limit, depthptr, newlines, comments)
        !          4053:      U_CHAR *start;
        !          4054:      register U_CHAR *limit;
        !          4055:      int *depthptr, *newlines, *comments;
        !          4056: {
        !          4057:   register U_CHAR *bp = start;
        !          4058: 
        !          4059:   while (bp < limit) {
        !          4060:     switch (*bp) {
        !          4061:     case '(':
        !          4062:       (*depthptr)++;
        !          4063:       break;
        !          4064:     case ')':
        !          4065:       if (--(*depthptr) < 0)
        !          4066:        return bp;
        !          4067:       break;
        !          4068:     case '\n':
        !          4069:       ++*newlines;
        !          4070:       break;
        !          4071:     case '/':
        !          4072:       if (bp[1] == '\\' && bp[2] == '\n')
        !          4073:        newline_fix (bp + 1);
        !          4074: #ifdef CPLUSPLUS
        !          4075:       if (bp[1] == '/') {
        !          4076:        *comments = 1;
        !          4077:        bp += 2;
        !          4078:        while (bp < limit && *bp++ != '\n') ;
        !          4079:        ++*newlines;
        !          4080:        break;
        !          4081:       }
        !          4082: #endif
        !          4083:       if (bp[1] != '*' || bp + 1 >= limit)
        !          4084:        break;
        !          4085:       *comments = 1;
        !          4086:       bp += 2;
        !          4087:       while (bp + 1 < limit) {
        !          4088:        if (bp[0] == '*'
        !          4089:            && bp[1] == '\\' && bp[2] == '\n')
        !          4090:          newline_fix (bp + 1);
        !          4091:        if (bp[0] == '*' && bp[1] == '/')
        !          4092:          break;
        !          4093:        if (*bp == '\n') ++*newlines;
        !          4094:        bp++;
        !          4095:       }
        !          4096:       break;
        !          4097:     case '\'':
        !          4098:     case '\"':
        !          4099:       {
        !          4100:        int quotec;
        !          4101:        for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) {
        !          4102:          if (*bp == '\\') {
        !          4103:            bp++;
        !          4104:            if (*bp == '\n')
        !          4105:              ++*newlines;
        !          4106:            while (*bp == '\\' && bp[1] == '\n') {
        !          4107:              bp += 2;
        !          4108:            }
        !          4109:          } else if (*bp == '\n')
        !          4110:            ++*newlines;
        !          4111:        }
        !          4112:       }
        !          4113:       break;
        !          4114:     case ',':
        !          4115:       if ((*depthptr) == 0)
        !          4116:        return bp;
        !          4117:       break;
        !          4118:     }
        !          4119:     bp++;
        !          4120:   }
        !          4121: 
        !          4122:   return bp;
        !          4123: }
        !          4124: 
        !          4125: /* Discard comments and duplicate newlines
        !          4126:    in the string of length LENGTH at START,
        !          4127:    except inside of string constants.
        !          4128:    The string is copied into itself with its beginning staying fixed.  
        !          4129: 
        !          4130:    NEWLINES is the number of newlines that must be duplicated.
        !          4131:    We assume that that much extra space is available past the end
        !          4132:    of the string.  */
        !          4133: 
        !          4134: int
        !          4135: discard_comments (start, length, newlines)
        !          4136:      U_CHAR *start;
        !          4137:      int length;
        !          4138:      int newlines;
        !          4139: {
        !          4140:   register U_CHAR *ibp;
        !          4141:   register U_CHAR *obp;
        !          4142:   register U_CHAR *limit;
        !          4143:   register int c;
        !          4144: 
        !          4145:   /* If we have newlines to duplicate, copy everything
        !          4146:      that many characters up.  Then, in the second part,
        !          4147:      we will have room to insert the newlines
        !          4148:      while copying down.
        !          4149:      NEWLINES may actually be too large, because it counts
        !          4150:      newlines in string constants, and we don't duplicate those.
        !          4151:      But that does no harm.  */
        !          4152:   if (newlines > 0) {
        !          4153:     ibp = start + length;
        !          4154:     obp = ibp + newlines;
        !          4155:     limit = start;
        !          4156:     while (limit != ibp)
        !          4157:       *--obp = *--ibp;
        !          4158:   }
        !          4159: 
        !          4160:   ibp = start + newlines;
        !          4161:   limit = start + length + newlines;
        !          4162:   obp = start;
        !          4163: 
        !          4164:   while (ibp < limit) {
        !          4165:     *obp++ = c = *ibp++;
        !          4166:     switch (c) {
        !          4167:     case '\n':
        !          4168:       /* Duplicate the newline.  */
        !          4169:       *obp++ = '\n';
        !          4170:       break;
        !          4171: 
        !          4172:     case '/':
        !          4173:       if (*ibp == '\\' && ibp[1] == '\n')
        !          4174:        newline_fix (ibp);
        !          4175:       /* Delete any comment.  */
        !          4176: #ifdef CPLUSPLUS
        !          4177:       if (ibp[0] == '/') {
        !          4178:        obp--;
        !          4179:        ibp++;
        !          4180:        while (ibp < limit && *ibp++ != '\n') ;
        !          4181:        break;
        !          4182:       }
        !          4183: #endif
        !          4184:       if (ibp[0] != '*' || ibp + 1 >= limit)
        !          4185:        break;
        !          4186:       obp--;
        !          4187:       ibp++;
        !          4188:       while (ibp + 1 < limit) {
        !          4189:        if (ibp[0] == '*'
        !          4190:            && ibp[1] == '\\' && ibp[2] == '\n')
        !          4191:          newline_fix (ibp + 1);
        !          4192:        if (ibp[0] == '*' && ibp[1] == '/')
        !          4193:          break;
        !          4194:        ibp++;
        !          4195:       }
        !          4196:       ibp += 2;
        !          4197:       break;
        !          4198: 
        !          4199:     case '\'':
        !          4200:     case '\"':
        !          4201:       /* Notice and skip strings, so that we don't
        !          4202:         think that comments start inside them,
        !          4203:         and so we don't duplicate newlines in them.  */
        !          4204:       {
        !          4205:        int quotec = c;
        !          4206:        while (ibp < limit)
        !          4207:          {
        !          4208:            *obp++ = c = *ibp++;
        !          4209:            if (c == quotec)
        !          4210:              break;
        !          4211:            if (c == '\\' && ibp < limit) {
        !          4212:              while (*ibp == '\\' && ibp[1] == '\n')
        !          4213:                ibp += 2;
        !          4214:              *obp++ = *ibp++;
        !          4215:            }
        !          4216:          }
        !          4217:       }
        !          4218:       break;
        !          4219:     }
        !          4220:   }
        !          4221: 
        !          4222:   return obp - start;
        !          4223: }
        !          4224: 
        !          4225: /*
        !          4226:  * error - print error message and increment count of errors.
        !          4227:  */
        !          4228: error (msg, arg1, arg2, arg3)
        !          4229:      U_CHAR *msg;
        !          4230: {
        !          4231:   int i;
        !          4232:   FILE_BUF *ip = NULL;
        !          4233: 
        !          4234:   for (i = indepth; i >= 0; i--)
        !          4235:     if (instack[i].fname != NULL) {
        !          4236:       ip = &instack[i];
        !          4237:       break;
        !          4238:     }
        !          4239: 
        !          4240:   if (ip != NULL)
        !          4241:     fprintf (stderr, "%s:%d: ", ip->fname, ip->lineno);
        !          4242:   fprintf (stderr, msg, arg1, arg2, arg3);
        !          4243:   fprintf (stderr, "\n", msg);
        !          4244:   errors++;
        !          4245:   return 0;
        !          4246: }
        !          4247: 
        !          4248: /* Print error message but don't count it.  */
        !          4249: 
        !          4250: warning (msg, arg1, arg2, arg3)
        !          4251:      U_CHAR *msg;
        !          4252: {
        !          4253:   int i;
        !          4254:   FILE_BUF *ip = NULL;
        !          4255: 
        !          4256:   for (i = indepth; i >= 0; i--)
        !          4257:     if (instack[i].fname != NULL) {
        !          4258:       ip = &instack[i];
        !          4259:       break;
        !          4260:     }
        !          4261: 
        !          4262:   if (ip != NULL)
        !          4263:     fprintf (stderr, "%s:%d: ", ip->fname, ip->lineno);
        !          4264:   fprintf (stderr, "warning: ");
        !          4265:   fprintf (stderr, msg, arg1, arg2, arg3);
        !          4266:   fprintf (stderr, "\n", msg);
        !          4267:   return 0;
        !          4268: }
        !          4269: 
        !          4270: error_with_line (line, msg, arg1, arg2, arg3)
        !          4271:      int line;
        !          4272:      U_CHAR *msg;
        !          4273: {
        !          4274:   int i;
        !          4275:   FILE_BUF *ip = NULL;
        !          4276: 
        !          4277:   for (i = indepth; i >= 0; i--)
        !          4278:     if (instack[i].fname != NULL) {
        !          4279:       ip = &instack[i];
        !          4280:       break;
        !          4281:     }
        !          4282: 
        !          4283:   if (ip != NULL)
        !          4284:     fprintf (stderr, "%s:%d: ", ip->fname, line);
        !          4285:   fprintf (stderr, msg, arg1, arg2, arg3);
        !          4286:   fprintf (stderr, "\n", msg);
        !          4287:   errors++;
        !          4288:   return 0;
        !          4289: }
        !          4290: 
        !          4291: /* Return the line at which an error occurred.
        !          4292:    The error is not necessarily associated with the current spot
        !          4293:    in the input stack, so LINE says where.  LINE will have been
        !          4294:    copied from ip->lineno for the current input level.
        !          4295:    If the current level is for a file, we return LINE.
        !          4296:    But if the current level is not for a file, LINE is meaningless.
        !          4297:    In that case, we return the lineno of the innermost file.  */
        !          4298: int
        !          4299: line_for_error (line)
        !          4300:      int line;
        !          4301: {
        !          4302:   int i;
        !          4303:   int line1 = line;
        !          4304: 
        !          4305:   for (i = indepth; i >= 0; ) {
        !          4306:     if (instack[i].fname != 0)
        !          4307:       return line1;
        !          4308:     i--;
        !          4309:     if (i < 0)
        !          4310:       return 0;
        !          4311:     line1 = instack[i].lineno;
        !          4312:   }
        !          4313: }
        !          4314: 
        !          4315: /*
        !          4316:  * If OBUF doesn't have NEEDED bytes after OPTR, make it bigger.
        !          4317:  *
        !          4318:  * As things stand, nothing is ever placed in the output buffer to be
        !          4319:  * removed again except when it's KNOWN to be part of an identifier,
        !          4320:  * so flushing and moving down everything left, instead of expanding,
        !          4321:  * should work ok.
        !          4322:  */
        !          4323: 
        !          4324: int
        !          4325: grow_outbuf (obuf, needed)
        !          4326:      register FILE_BUF *obuf;
        !          4327:      register int needed;
        !          4328: {
        !          4329:   register U_CHAR *p;
        !          4330:   int minsize;
        !          4331: 
        !          4332:   if (obuf->length - (obuf->bufp - obuf->buf) > needed)
        !          4333:     return;
        !          4334: 
        !          4335:   /* Make it at least twice as big as it is now.  */
        !          4336:   obuf->length *= 2;
        !          4337:   /* Make it have at least 150% of the free space we will need.  */
        !          4338:   minsize = (3 * needed) / 2 + (obuf->bufp - obuf->buf);
        !          4339:   if (minsize > obuf->length)
        !          4340:     obuf->length = minsize;
        !          4341: 
        !          4342:   if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL)
        !          4343:     memory_full ();
        !          4344: 
        !          4345:   obuf->bufp = p + (obuf->bufp - obuf->buf);
        !          4346:   obuf->buf = p;
        !          4347: }
        !          4348: 
        !          4349: /* Symbol table for macro names and special symbols */
        !          4350: 
        !          4351: /*
        !          4352:  * install a name in the main hash table, even if it is already there.
        !          4353:  *   name stops with first non alphanumeric, except leading '#'.
        !          4354:  * caller must check against redefinition if that is desired.
        !          4355:  * delete_macro () removes things installed by install () in fifo order.
        !          4356:  * this is important because of the `defined' special symbol used
        !          4357:  * in #if, and also if pushdef/popdef directives are ever implemented.
        !          4358:  *
        !          4359:  * If LEN is >= 0, it is the length of the name.
        !          4360:  * Otherwise, compute the length by scanning the entire name.
        !          4361:  *
        !          4362:  * If HASH is >= 0, it is the precomputed hash code.
        !          4363:  * Otherwise, compute the hash code.
        !          4364:  */
        !          4365: HASHNODE *
        !          4366: install (name, len, type, value, hash)
        !          4367:      U_CHAR *name;
        !          4368:      int len;
        !          4369:      enum node_type type;
        !          4370:      int value;
        !          4371:      int hash;
        !          4372:         /* watch out here if sizeof (U_CHAR *) != sizeof (int) */
        !          4373: {
        !          4374:   register HASHNODE *hp;
        !          4375:   register int i, bucket;
        !          4376:   register U_CHAR *p, *q;
        !          4377: 
        !          4378:   if (len < 0) {
        !          4379:     p = name;
        !          4380:     while (is_idchar[*p])
        !          4381:       p++;
        !          4382:     len = p - name;
        !          4383:   }
        !          4384: 
        !          4385:   if (hash < 0)
        !          4386:     hash = hashf (name, len, HASHSIZE);
        !          4387: 
        !          4388:   i = sizeof (HASHNODE) + len + 1;
        !          4389:   hp = (HASHNODE *) xmalloc (i);
        !          4390:   bucket = hash;
        !          4391:   hp->bucket_hdr = &hashtab[bucket];
        !          4392:   hp->next = hashtab[bucket];
        !          4393:   hashtab[bucket] = hp;
        !          4394:   hp->prev = NULL;
        !          4395:   if (hp->next != NULL)
        !          4396:     hp->next->prev = hp;
        !          4397:   hp->type = type;
        !          4398:   hp->length = len;
        !          4399:   hp->value.ival = value;
        !          4400:   hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
        !          4401:   p = hp->name;
        !          4402:   q = name;
        !          4403:   for (i = 0; i < len; i++)
        !          4404:     *p++ = *q++;
        !          4405:   hp->name[len] = 0;
        !          4406:   return hp;
        !          4407: }
        !          4408: 
        !          4409: /*
        !          4410:  * find the most recent hash node for name name (ending with first
        !          4411:  * non-identifier char) installed by install
        !          4412:  *
        !          4413:  * If LEN is >= 0, it is the length of the name.
        !          4414:  * Otherwise, compute the length by scanning the entire name.
        !          4415:  *
        !          4416:  * If HASH is >= 0, it is the precomputed hash code.
        !          4417:  * Otherwise, compute the hash code.
        !          4418:  */
        !          4419: HASHNODE *
        !          4420: lookup (name, len, hash)
        !          4421:      U_CHAR *name;
        !          4422:      int len;
        !          4423:      int hash;
        !          4424: {
        !          4425:   register U_CHAR *bp;
        !          4426:   register HASHNODE *bucket;
        !          4427: 
        !          4428:   if (len < 0) {
        !          4429:     for (bp = name; is_idchar[*bp]; bp++) ;
        !          4430:     len = bp - name;
        !          4431:   }
        !          4432: 
        !          4433:   if (hash < 0)
        !          4434:     hash = hashf (name, len, HASHSIZE);
        !          4435: 
        !          4436:   bucket = hashtab[hash];
        !          4437:   while (bucket) {
        !          4438:     if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
        !          4439:       return bucket;
        !          4440:     bucket = bucket->next;
        !          4441:   }
        !          4442:   return NULL;
        !          4443: }
        !          4444: 
        !          4445: /*
        !          4446:  * Delete a hash node.  Some weirdness to free junk from macros.
        !          4447:  * More such weirdness will have to be added if you define more hash
        !          4448:  * types that need it.
        !          4449:  */
        !          4450: 
        !          4451: /* Note that the DEFINITION of a macro is removed from the hash table
        !          4452:    but its storage is not freed.  This would be a storage leak
        !          4453:    except that it is not reasonable to keep undefining and redefining
        !          4454:    large numbers of macros many times.
        !          4455:    In any case, this is necessary, because a macro can be #undef'd
        !          4456:    in the middle of reading the arguments to a call to it.
        !          4457:    If #undef freed the DEFINITION, that would crash.  */
        !          4458: 
        !          4459: delete_macro (hp)
        !          4460:      HASHNODE *hp;
        !          4461: {
        !          4462: 
        !          4463:   if (hp->prev != NULL)
        !          4464:     hp->prev->next = hp->next;
        !          4465:   if (hp->next != NULL)
        !          4466:     hp->next->prev = hp->prev;
        !          4467: 
        !          4468:   /* make sure that the bucket chain header that
        !          4469:      the deleted guy was on points to the right thing afterwards. */
        !          4470:   if (hp == *hp->bucket_hdr)
        !          4471:     *hp->bucket_hdr = hp->next;
        !          4472: 
        !          4473: #if 0
        !          4474:   if (hp->type == T_MACRO) {
        !          4475:     DEFINITION *d = hp->value.defn;
        !          4476:     struct reflist *ap, *nextap;
        !          4477: 
        !          4478:     for (ap = d->pattern; ap != NULL; ap = nextap) {
        !          4479:       nextap = ap->next;
        !          4480:       free (ap);
        !          4481:     }
        !          4482:     free (d);
        !          4483:   }
        !          4484: #endif
        !          4485:   free (hp);
        !          4486: }
        !          4487: 
        !          4488: /*
        !          4489:  * return hash function on name.  must be compatible with the one
        !          4490:  * computed a step at a time, elsewhere
        !          4491:  */
        !          4492: int
        !          4493: hashf (name, len, hashsize)
        !          4494:      register U_CHAR *name;
        !          4495:      register int len;
        !          4496:      int hashsize;
        !          4497: {
        !          4498:   register int r = 0;
        !          4499: 
        !          4500:   while (len--)
        !          4501:     r = HASHSTEP (r, *name++);
        !          4502: 
        !          4503:   return MAKE_POS (r) % hashsize;
        !          4504: }
        !          4505: 
        !          4506: /* Dump all macro definitions as #defines to stdout.  */
        !          4507: 
        !          4508: dump_all_macros ()
        !          4509: {
        !          4510:   int bucket;
        !          4511: 
        !          4512:   for (bucket = 0; bucket < HASHSIZE; bucket++) {
        !          4513:     register HASHNODE *hp;
        !          4514: 
        !          4515:     for (hp = hashtab[bucket]; hp; hp= hp->next) {
        !          4516:       if (hp->type == T_MACRO) {
        !          4517:        register DEFINITION *defn = hp->value.defn;
        !          4518:        struct reflist *ap;
        !          4519:        int offset;
        !          4520:        int concat;
        !          4521: 
        !          4522: 
        !          4523:        /* Print the definition of the macro HP.  */
        !          4524: 
        !          4525:        printf ("#define %s", hp->name);
        !          4526:        if (defn->nargs >= 0) {
        !          4527:          int i;
        !          4528: 
        !          4529:          printf ("(");
        !          4530:          for (i = 0; i < defn->nargs; i++) {
        !          4531:            dump_arg_n (defn, i);
        !          4532:            if (i + 1 < defn->nargs)
        !          4533:              printf (", ");
        !          4534:          }
        !          4535:          printf (")");
        !          4536:        }
        !          4537: 
        !          4538:        printf (" ");
        !          4539: 
        !          4540:        offset = 0;
        !          4541:        concat = 0;
        !          4542:        for (ap = defn->pattern; ap != NULL; ap = ap->next) {
        !          4543:          dump_defn_1 (defn->expansion, offset, ap->nchars);
        !          4544:          if (ap->nchars != 0)
        !          4545:            concat = 0;
        !          4546:          offset += ap->nchars;
        !          4547:          if (ap->stringify)
        !          4548:            printf (" #");
        !          4549:          if (ap->raw_before && !concat)
        !          4550:            printf (" ## ");
        !          4551:          concat = 0;
        !          4552:          dump_arg_n (defn, ap->argno);
        !          4553:          if (ap->raw_after) {
        !          4554:            printf (" ## ");
        !          4555:            concat = 1;
        !          4556:          }
        !          4557:        }
        !          4558:        dump_defn_1 (defn->expansion, offset, defn->length - offset);
        !          4559:        printf ("\n");
        !          4560:       }
        !          4561:     }
        !          4562:   }
        !          4563:   return NULL;
        !          4564: }
        !          4565: 
        !          4566: /* Output to stdout a substring of a macro definition.
        !          4567:    BASE is the beginning of the definition.
        !          4568:    Output characters START thru LENGTH.
        !          4569:    Discard newlines outside of strings, thus
        !          4570:    converting funny-space markers to ordinary spaces.  */
        !          4571: 
        !          4572: dump_defn_1 (base, start, length)
        !          4573:      U_CHAR *base;
        !          4574:      int start;
        !          4575:      int length;
        !          4576: {
        !          4577:   U_CHAR *p = base + start;
        !          4578:   U_CHAR *limit = base + start + length;
        !          4579: 
        !          4580:   while (p < limit) {
        !          4581:     if (*p != '\n')
        !          4582:       putchar (*p);
        !          4583:     else if (*p == '\"' || *p =='\'') {
        !          4584:       U_CHAR *p1 = skip_quoted_string (p, limit, 0, 0, 0);
        !          4585:       fwrite (p, p1 - p, 1, stdout);
        !          4586:       p = p1 - 1;
        !          4587:     }
        !          4588:     p++;
        !          4589:   }
        !          4590: }
        !          4591: 
        !          4592: /* Print the name of argument number ARGNUM of macro definition DEFN.
        !          4593:    Recall that DEFN->argnames contains all the arg names
        !          4594:    concatenated in reverse order with comma-space in between.  */
        !          4595: 
        !          4596: dump_arg_n (defn, argnum)
        !          4597:      DEFINITION *defn;
        !          4598:      int argnum;
        !          4599: {
        !          4600:   register U_CHAR *p = defn->argnames;
        !          4601:   while (argnum + 1 < defn->nargs) {
        !          4602:     p = (U_CHAR *) index (p, ' ') + 1;
        !          4603:     argnum++;
        !          4604:   }
        !          4605: 
        !          4606:   while (*p && *p != ',') {
        !          4607:     putchar (*p);
        !          4608:     p++;
        !          4609:   }
        !          4610: }
        !          4611: 
        !          4612: /*
        !          4613:  * initialize random junk in the hash table and maybe other places
        !          4614:  */
        !          4615: initialize_random_junk ()
        !          4616: {
        !          4617:   register int i;
        !          4618: 
        !          4619:   /*
        !          4620:    * Set up is_idchar and is_idstart tables.  These should be
        !          4621:    * faster than saying (is_alpha (c) || c == '_'), etc.
        !          4622:    * Must do set up these things before calling any routines tthat
        !          4623:    * refer to them.
        !          4624:    */
        !          4625:   for (i = 'a'; i <= 'z'; i++) {
        !          4626:     ++is_idchar[i - 'a' + 'A'];
        !          4627:     ++is_idchar[i];
        !          4628:     ++is_idstart[i - 'a' + 'A'];
        !          4629:     ++is_idstart[i];
        !          4630:   }
        !          4631:   for (i = '0'; i <= '9'; i++)
        !          4632:     ++is_idchar[i];
        !          4633:   ++is_idchar['_'];
        !          4634:   ++is_idstart['_'];
        !          4635:   ++is_idchar['$'];
        !          4636:   ++is_idstart['$'];
        !          4637: 
        !          4638:   /* horizontal space table */
        !          4639:   ++is_hor_space[' '];
        !          4640:   ++is_hor_space['\t'];
        !          4641:   ++is_hor_space['\v'];
        !          4642:   ++is_hor_space['\f'];
        !          4643: 
        !          4644:   ++is_space[' '];
        !          4645:   ++is_space['\t'];
        !          4646:   ++is_space['\v'];
        !          4647:   ++is_space['\f'];
        !          4648:   ++is_space['\n'];
        !          4649: 
        !          4650:   install ("__LINE__", -1, T_SPECLINE, 0, -1);
        !          4651:   install ("__DATE__", -1, T_DATE, 0, -1);
        !          4652:   install ("__FILE__", -1, T_FILE, 0, -1);
        !          4653:   install ("__VERSION__", -1, T_VERSION, 0, -1);
        !          4654:   install ("__TIME__", -1, T_TIME, 0, -1);
        !          4655:   install ("__STDC__", -1, T_CONST, 1, -1);
        !          4656: /*  install ("__GNU__", -1, T_CONST, 1, -1);  */
        !          4657: /*  This is supplied using a -D by the compiler driver
        !          4658:     so that it is present only when truly compiling with GNU C.  */
        !          4659: }
        !          4660: 
        !          4661: /*
        !          4662:  * process a given definition string, for initialization
        !          4663:  * If STR is just an identifier, define it with value 1.
        !          4664:  * If STR has anything after the identifier, then it should
        !          4665:  * be identifier-space-definition.
        !          4666:  */
        !          4667: make_definition (str)
        !          4668:      U_CHAR *str;
        !          4669: {
        !          4670:   FILE_BUF *ip;
        !          4671:   struct directive *kt;
        !          4672:   U_CHAR *buf, *p;
        !          4673: 
        !          4674:   buf = str;
        !          4675:   p = str;
        !          4676:   while (is_idchar[*p]) p++;
        !          4677:   if (*p == 0) {
        !          4678:     buf = (U_CHAR *) alloca (p - buf + 4);
        !          4679:     strcpy (buf, str);
        !          4680:     strcat (buf, " 1");
        !          4681:   }
        !          4682:   
        !          4683:   ip = &instack[++indepth];
        !          4684:   ip->fname = "*Initialization*";
        !          4685: 
        !          4686:   ip->buf = ip->bufp = buf;
        !          4687:   ip->length = strlen (buf);
        !          4688:   ip->lineno = 1;
        !          4689:   ip->macro = 0;
        !          4690:   ip->free = 0;
        !          4691:   ip->if_stack = if_stack;
        !          4692: 
        !          4693:   for (kt = directive_table; kt->type != T_DEFINE; kt++)
        !          4694:     ;
        !          4695: 
        !          4696:   /* pass NULL as output ptr to do_define since we KNOW it never
        !          4697:      does any output.... */
        !          4698:   do_define (buf, buf + strlen (buf) , NULL, kt);
        !          4699:   --indepth;
        !          4700: }
        !          4701: 
        !          4702: /* JF, this does the work for the -U option */
        !          4703: make_undef (str)
        !          4704:      U_CHAR *str;
        !          4705: {
        !          4706:   FILE_BUF *ip;
        !          4707:   struct directive *kt;
        !          4708: 
        !          4709:   ip = &instack[++indepth];
        !          4710:   ip->fname = "*undef*";
        !          4711: 
        !          4712:   ip->buf = ip->bufp = str;
        !          4713:   ip->length = strlen (str);
        !          4714:   ip->lineno = 1;
        !          4715:   ip->macro = 0;
        !          4716:   ip->free = 0;
        !          4717:   ip->if_stack = if_stack;
        !          4718: 
        !          4719:   for (kt = directive_table; kt->type != T_UNDEF; kt++)
        !          4720:     ;
        !          4721: 
        !          4722:   do_undef (str,str + strlen (str) - 1, NULL, kt);
        !          4723:   --indepth;
        !          4724: }
        !          4725: 
        !          4726: /* Add output to `deps_buffer' for the -M switch.
        !          4727:    STRING points to the text to be output.
        !          4728:    SIZE is the number of bytes, or 0 meaning output until a null.
        !          4729:    If SIZE is nonzero, we break the line first, if it is long enough.  */
        !          4730: 
        !          4731: deps_output (string, size)
        !          4732:      char *string;
        !          4733:      int size;
        !          4734: {
        !          4735:   if (size != 0 && deps_column > 50)
        !          4736:     {
        !          4737:       deps_output ("\\\n  ", 0);
        !          4738:       deps_column = 0;
        !          4739:     }
        !          4740: 
        !          4741:   if (size == 0)
        !          4742:     size = strlen (string);
        !          4743: 
        !          4744:   if (deps_size + size + 1 > deps_allocated_size)
        !          4745:     {
        !          4746:       deps_allocated_size = deps_size + size + 50;
        !          4747:       deps_allocated_size *= 2;
        !          4748:       deps_buffer = (char *) xrealloc (deps_buffer, deps_allocated_size);
        !          4749:     }
        !          4750:   bcopy (string, &deps_buffer[deps_size], size);
        !          4751:   deps_size += size;
        !          4752:   deps_column += size;
        !          4753:   deps_buffer[deps_size] = 0;
        !          4754: }
        !          4755: 
        !          4756: #ifndef BSD
        !          4757: #ifndef BSTRING
        !          4758: 
        !          4759: void
        !          4760: bzero (b, length)
        !          4761:      register char *b;
        !          4762:      register int length;
        !          4763: {
        !          4764: #ifdef VMS
        !          4765:   short zero = 0;
        !          4766:   long max_str = 65535;
        !          4767: 
        !          4768:   while (length > max_str)
        !          4769:     {
        !          4770:       (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
        !          4771:       length -= max_str;
        !          4772:       b += max_str;
        !          4773:     }
        !          4774:   (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b);
        !          4775: #else
        !          4776:   while (length-- > 0)
        !          4777:     *b++ = 0;
        !          4778: #endif /* not VMS */
        !          4779: }
        !          4780: 
        !          4781: void
        !          4782: bcopy (b1, b2, length)
        !          4783:      register char *b1;
        !          4784:      register char *b2;
        !          4785:      register int length;
        !          4786: {
        !          4787: #ifdef VMS
        !          4788:   long max_str = 65535;
        !          4789: 
        !          4790:   while (length > max_str)
        !          4791:     {
        !          4792:       (void) LIB$MOVC3 (&max_str, b1, b2);
        !          4793:       length -= max_str;
        !          4794:       b1 += max_str;
        !          4795:       b2 += max_str;
        !          4796:     }
        !          4797:   (void) LIB$MOVC3 (&length, b1, b2);
        !          4798: #else
        !          4799:   while (length-- > 0)
        !          4800:     *b2++ = *b1++;
        !          4801: #endif /* not VMS */
        !          4802: }
        !          4803: 
        !          4804: int
        !          4805: bcmp (b1, b2, length)  /* This could be a macro! */
        !          4806:      register char *b1;
        !          4807:      register char *b2;
        !          4808:       register int length;
        !          4809:  {
        !          4810: #ifdef VMS
        !          4811:    struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
        !          4812:    struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
        !          4813: 
        !          4814:    return STR$COMPARE (&src1, &src2);
        !          4815: #else
        !          4816:    while (length-- > 0)
        !          4817:      if (*b1++ != *b2++)
        !          4818:        return 1;
        !          4819: 
        !          4820:    return 0;
        !          4821: #endif /* not VMS */
        !          4822: }
        !          4823: #endif /* not BSTRING */
        !          4824: #endif /* not BSD */
        !          4825: 
        !          4826: 
        !          4827: void
        !          4828: fatal (str, arg)
        !          4829:      char *str, *arg;
        !          4830: {
        !          4831:   fprintf (stderr, "%s: ", progname);
        !          4832:   fprintf (stderr, str, arg);
        !          4833:   fprintf (stderr, "\n");
        !          4834:   exit (FATAL_EXIT_CODE);
        !          4835: }
        !          4836: 
        !          4837: void
        !          4838: perror_with_name (name)
        !          4839:      char *name;
        !          4840: {
        !          4841:   extern int errno, sys_nerr;
        !          4842:   extern char *sys_errlist[];
        !          4843: 
        !          4844:   fprintf (stderr, "%s: ", progname);
        !          4845:   if (errno < sys_nerr)
        !          4846:     fprintf (stderr, "%s for `%s'\n", sys_errlist[errno], name);
        !          4847:   else
        !          4848:     fprintf (stderr, "cannot open `%s'\n", sys_errlist[errno], name);
        !          4849: }
        !          4850: 
        !          4851: void
        !          4852: pfatal_with_name (name)
        !          4853:      char *name;
        !          4854: {
        !          4855:   perror_with_name (name);
        !          4856:   exit (FATAL_EXIT_CODE);
        !          4857: }
        !          4858: 
        !          4859: 
        !          4860: void
        !          4861: memory_full ()
        !          4862: {
        !          4863:   fatal ("Memory exhausted.");
        !          4864: }
        !          4865: 
        !          4866: 
        !          4867: char *
        !          4868: xmalloc (size)
        !          4869:      int size;
        !          4870: {
        !          4871:   extern char *malloc ();
        !          4872:   register char *ptr = malloc (size);
        !          4873:   if (ptr != 0) return (ptr);
        !          4874:   memory_full ();
        !          4875:   /*NOTREACHED*/
        !          4876: }
        !          4877: 
        !          4878: char *
        !          4879: xrealloc (old, size)
        !          4880:      char *old;
        !          4881:      int size;
        !          4882: {
        !          4883:   extern char *realloc ();
        !          4884:   register char *ptr = realloc (old, size);
        !          4885:   if (ptr != 0) return (ptr);
        !          4886:   memory_full ();
        !          4887:   /*NOTREACHED*/
        !          4888: }
        !          4889: 
        !          4890: char *
        !          4891: xcalloc (number, size)
        !          4892:      int number, size;
        !          4893: {
        !          4894:   extern char *malloc ();
        !          4895:   register int total = number * size;
        !          4896:   register char *ptr = malloc (total);
        !          4897:   if (ptr != 0)
        !          4898:     {
        !          4899:       if (total > 100)
        !          4900:        bzero (ptr, total);
        !          4901:       else {
        !          4902:        /* It's not too long, so loop, zeroing by longs.
        !          4903:           It must be safe because malloc values are always well aligned.  */
        !          4904:        register long *zp = (long *) ptr;
        !          4905:        register long *zl = (long *) (ptr + total - 4);
        !          4906:        register int i = total - 4;
        !          4907:        while (zp < zl)
        !          4908:          *zp++ = 0;
        !          4909:        if (i < 0)
        !          4910:          i = 0;
        !          4911:        while (i < total)
        !          4912:          ptr[i++] = 0;
        !          4913:       }
        !          4914:       return ptr;
        !          4915:     }
        !          4916:   memory_full ();
        !          4917:   /*NOTREACHED*/
        !          4918: }
        !          4919: 
        !          4920: 
        !          4921: /* Get the file-mode and data size of the file open on FD
        !          4922:    and store them in *MODE_POINTER and *SIZE_POINTER.  */
        !          4923: 
        !          4924: int
        !          4925: file_size_and_mode (fd, mode_pointer, size_pointer)
        !          4926:      int fd;
        !          4927:      int *mode_pointer;
        !          4928:      long int *size_pointer;
        !          4929: {
        !          4930:   struct stat sbuf;
        !          4931: 
        !          4932:   if (fstat (fd, &sbuf) < 0) return (-1);
        !          4933: #ifdef VMS
        !          4934: #ifdef __GNUC__
        !          4935: #ifdef stat_alignment_fix
        !          4936:   /* Fix the size data in the stat buffer (this is temporary!) */
        !          4937:   sbuf.st_size = (stat_alignment_fix(&(sbuf))->st_size);
        !          4938: #endif stat_alignment_fix
        !          4939: #endif __GNUC__
        !          4940: #endif VMS
        !          4941:   if (mode_pointer) *mode_pointer = sbuf.st_mode;
        !          4942:   if (size_pointer) *size_pointer = sbuf.st_size;
        !          4943:   return 0;
        !          4944: }
        !          4945: 
        !          4946: #ifdef VMS
        !          4947: 
        !          4948: /* Under VMS we need to fix up the "include" specification
        !          4949:    filename so that everything following the 1st slash is
        !          4950:    changed into its correct VMS file specification. */
        !          4951: 
        !          4952: hack_vms_include_specification (fname)
        !          4953:      char *fname;
        !          4954: {
        !          4955:   register char *cp, *cp1, *cp2;
        !          4956:   char Local[512];
        !          4957:   extern char *index (), *rindex ();
        !          4958: 
        !          4959:   /* Ignore leading "./"s */
        !          4960:   while (fname[0] == '.' && fname[1] == '/')
        !          4961:     strcpy (fname, fname+2);
        !          4962:   /* Look for the boundary between the VMS and UNIX filespecs */
        !          4963:   cp = rindex (fname, ']');    /* Look for end of dirspec. */
        !          4964:   if (cp == 0) cp == rindex (fname, '>'); /* ... Ditto             */
        !          4965:   if (cp == 0) cp == rindex (fname, ':'); /* Look for end of devspec. */
        !          4966:   if (cp) {
        !          4967:     cp++;
        !          4968:   } else {
        !          4969:     cp = index (fname, '/');   /* Look for the "/" */
        !          4970:   }
        !          4971:   /* See if we found that 1st slash */
        !          4972:   if (cp == 0) return;         /* Nothing to do!!! */
        !          4973:   if (*cp != '/') return;      /* Nothing to do!!! */
        !          4974:   /* Point to the UNIX filename part (which needs to be fixed!) */
        !          4975:   cp1 = cp+1;
        !          4976:   /* If the directory spec is not rooted, we can just copy
        !          4977:      the UNIX filename part and we are done */
        !          4978:   if (((cp - fname) > 2)
        !          4979:       && ((cp[-1] == ']') || (cp[-1] == '>'))
        !          4980:       && (cp[-2] != '.')) {
        !          4981:     strcpy (cp, cp1);
        !          4982:     return;
        !          4983:   }
        !          4984:   /* If there are no other slashes then the filename will be
        !          4985:      in the "root" directory.  Otherwise, we need to add
        !          4986:      directory specifications. */
        !          4987:   if (index (cp1, '/') == 0) {
        !          4988:     /* Just add "[000000]" as the directory string */
        !          4989:     strcpy (Local, "[000000]");
        !          4990:     cp2 = Local + strlen (Local);
        !          4991:   } else {
        !          4992:     /* Open the directory specification */
        !          4993:     cp2 = Local;
        !          4994:     *cp2++ = '[';
        !          4995:     /* As long as there are still subdirectories to add, do them. */
        !          4996:     while (index (cp1, '/') != 0) {
        !          4997:       /* If this token is "." we can ignore it */
        !          4998:       if ((cp1[0] == '.') && (cp1[1] == '/')) {
        !          4999:        cp1 += 2;
        !          5000:        continue;
        !          5001:       }
        !          5002:       /* Add a subdirectory spec. */
        !          5003:       if (cp2 != Local+1) *cp2++ = '.';
        !          5004:       /* If this is ".." then the spec becomes "-" */
        !          5005:       if ((cp1[0] == '.') && (cp1[1] == '.') && (cp[2] == '/')) {
        !          5006:        /* Add "-" and skip the ".." */
        !          5007:        *cp2++ = '-';
        !          5008:        cp1 += 3;
        !          5009:        continue;
        !          5010:       }
        !          5011:       /* Copy the subdirectory */
        !          5012:       while (*cp1 != '/') *cp2++= *cp1++;
        !          5013:       cp1++;                   /* Skip the "/" */
        !          5014:     }
        !          5015:     /* Close the directory specification */
        !          5016:     *cp2++ = ']';
        !          5017:   }
        !          5018:   /* Now add the filename */
        !          5019:   while (*cp1) *cp2++ = *cp1++;
        !          5020:   *cp2 = 0;
        !          5021:   /* Now append it to the original VMS spec. */
        !          5022:   strcpy (cp, Local);
        !          5023:   return;
        !          5024: }
        !          5025: #endif /* VMS */
        !          5026: 
        !          5027: #ifdef VMS
        !          5028: 
        !          5029: /* These are the read/write replacement routines for
        !          5030:    VAX-11 "C".  They make read/write behave enough
        !          5031:    like their UNIX counterparts that CCCP will work */
        !          5032: 
        !          5033: int
        !          5034: read (fd, buf, size)
        !          5035:      int fd;
        !          5036:      char *buf;
        !          5037:      int size;
        !          5038: {
        !          5039: #undef read    /* Get back the REAL read routine */
        !          5040:   register int i;
        !          5041:   register int total = 0;
        !          5042: 
        !          5043:   /* Read until the buffer is exhausted */
        !          5044:   while (size > 0) {
        !          5045:     /* Limit each read to 32KB */
        !          5046:     i = (size > (32*1024)) ? (32*1024) : size;
        !          5047:     i = read (fd, buf, i);
        !          5048:     if (i <= 0) {
        !          5049:       if (i == 0) return (total);
        !          5050:       return(i);
        !          5051:     }
        !          5052:     /* Account for this read */
        !          5053:     total += i;
        !          5054:     buf += i;
        !          5055:     size -= i;
        !          5056:   }
        !          5057:   return (total);
        !          5058: }
        !          5059: 
        !          5060: int
        !          5061: write (fd, buf, size)
        !          5062:      int fd;
        !          5063:      char *buf;
        !          5064:      int size;
        !          5065: {
        !          5066: #undef write   /* Get back the REAL write routine */
        !          5067:   int i;
        !          5068:   int j;
        !          5069: 
        !          5070:   /* Limit individual writes to 32Kb */
        !          5071:   i = size;
        !          5072:   while (i > 0) {
        !          5073:     j = (i > (32*1024)) ? (32*1024) : i;
        !          5074:     if (write (fd, buf, j) < 0) return (-1);
        !          5075:     /* Account for the data written */
        !          5076:     buf += j;
        !          5077:     i -= j;
        !          5078:   }
        !          5079:   return (size);
        !          5080: }
        !          5081: 
        !          5082: #endif /* VMS */

unix.superglobalmegacorp.com

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