xref: /csrg-svn/contrib/gcc-2.3.3/cccp.c (revision 60376)
159995Selan /* C Compatible Compiler Preprocessor (CCCP)
259995Selan Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
359995Selan                     Written by Paul Rubin, June 1986
459995Selan 		    Adapted to ANSI C, Richard Stallman, Jan 1987
559995Selan 
659995Selan This program is free software; you can redistribute it and/or modify it
759995Selan under the terms of the GNU General Public License as published by the
859995Selan Free Software Foundation; either version 2, or (at your option) any
959995Selan later version.
1059995Selan 
1159995Selan This program is distributed in the hope that it will be useful,
1259995Selan but WITHOUT ANY WARRANTY; without even the implied warranty of
1359995Selan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1459995Selan GNU General Public License for more details.
1559995Selan 
1659995Selan You should have received a copy of the GNU General Public License
1759995Selan along with this program; if not, write to the Free Software
1859995Selan Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
1959995Selan 
2059995Selan  In other words, you are welcome to use, share and improve this program.
2159995Selan  You are forbidden to forbid anyone else to use, share and improve
2259995Selan  what you give them.   Help stamp out software-hoarding!  */
2359995Selan 
2459995Selan typedef unsigned char U_CHAR;
2559995Selan 
2659995Selan #ifdef EMACS
2759995Selan #define NO_SHORTNAMES
2859995Selan #include "../src/config.h"
2959995Selan #ifdef open
3059995Selan #undef open
3159995Selan #undef read
3259995Selan #undef write
3359995Selan #endif /* open */
3459995Selan #endif /* EMACS */
3559995Selan 
3659995Selan /* The macro EMACS is defined when cpp is distributed as part of Emacs,
3759995Selan    for the sake of machines with limited C compilers.  */
3859995Selan #ifndef EMACS
3959995Selan #include "config.h"
4059995Selan #endif /* not EMACS */
4159995Selan 
4259995Selan #ifndef STANDARD_INCLUDE_DIR
4359995Selan #define STANDARD_INCLUDE_DIR "/usr/include"
4459995Selan #endif
4559995Selan 
4659995Selan #ifndef LOCAL_INCLUDE_DIR
4759995Selan #define LOCAL_INCLUDE_DIR "/usr/local/include"
4859995Selan #endif
4959995Selan 
5059995Selan #if 0 /* We can't get ptrdiff_t, so I arranged not to need PTR_INT_TYPE.  */
5159995Selan #ifdef __STDC__
5259995Selan #define PTR_INT_TYPE ptrdiff_t
5359995Selan #else
5459995Selan #define PTR_INT_TYPE long
5559995Selan #endif
5659995Selan #endif /* 0 */
5759995Selan 
5859995Selan #include "pcp.h"
5959995Selan 
6059995Selan #ifndef STDC_VALUE
6159995Selan #define STDC_VALUE 1
6259995Selan #endif
6359995Selan 
6459995Selan /* By default, colon separates directories in a path.  */
6559995Selan #ifndef PATH_SEPARATOR
6659995Selan #define PATH_SEPARATOR ':'
6759995Selan #endif
6859995Selan 
6959995Selan /* In case config.h defines these.  */
7059995Selan #undef bcopy
7159995Selan #undef bzero
7259995Selan #undef bcmp
7359995Selan 
7459995Selan #include <sys/types.h>
7559995Selan #include <sys/stat.h>
7659995Selan #include <ctype.h>
7759995Selan #include <stdio.h>
7859995Selan 
7959995Selan #ifndef VMS
8059995Selan #ifndef USG
8159995Selan #include <sys/time.h>		/* for __DATE__ and __TIME__ */
8259995Selan #include <sys/resource.h>
8359995Selan #else
8459995Selan #include <time.h>
8559995Selan #include <fcntl.h>
8659995Selan #endif /* USG */
8759995Selan #endif /* not VMS */
8859995Selan 
8959995Selan /* VMS-specific definitions */
9059995Selan #ifdef VMS
9159995Selan #include <time.h>
9259995Selan #include <errno.h>		/* This defines "errno" properly */
9359995Selan #include <perror.h>		/* This defines sys_errlist/sys_nerr properly */
9459995Selan #include <descrip.h>
9559995Selan #define O_RDONLY	0	/* Open arg for Read/Only  */
9659995Selan #define O_WRONLY	1	/* Open arg for Write/Only */
9759995Selan #define read(fd,buf,size)	VMS_read(fd,buf,size)
9859995Selan #define write(fd,buf,size)	VMS_write(fd,buf,size)
9959995Selan #define open(fname,mode,prot)	VMS_open(fname,mode,prot)
10059995Selan #define fopen(fname,mode)	VMS_fopen(fname,mode)
10159995Selan #define freopen(fname,mode,ofile) VMS_freopen(fname,mode,ofile)
10259995Selan #define strncat(dst,src,cnt) VMS_strncat(dst,src,cnt)
10359995Selan static char * VMS_strncat ();
10459995Selan static int VMS_read ();
10559995Selan static int VMS_write ();
10659995Selan static int VMS_open ();
10759995Selan static FILE * VMS_fopen ();
10859995Selan static FILE * VMS_freopen ();
10959995Selan static void hack_vms_include_specification ();
11059995Selan typedef struct { unsigned :16, :16, :16; } vms_ino_t;
11159995Selan #define ino_t vms_ino_t
11259995Selan #define INCLUDE_LEN_FUDGE 10	/* leave room for VMS syntax conversion */
11359995Selan #ifdef __GNUC__
11459995Selan #define BSTRING			/* VMS/GCC supplies the bstring routines */
11559995Selan #endif /* __GNUC__ */
11659995Selan #endif /* VMS */
11759995Selan 
11859995Selan extern char *index ();
11959995Selan extern char *rindex ();
12059995Selan 
12159995Selan #ifndef O_RDONLY
12259995Selan #define O_RDONLY 0
12359995Selan #endif
12459995Selan 
12559995Selan #undef MIN
12659995Selan #undef MAX
12759995Selan #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
12859995Selan #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
12959995Selan 
13059995Selan /* Find the largest host integer type and set its size and type.  */
13159995Selan 
13259995Selan #ifndef HOST_BITS_PER_WIDE_INT
13359995Selan 
13459995Selan #if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
13559995Selan #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
13659995Selan #define HOST_WIDE_INT long
13759995Selan #else
13859995Selan #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
13959995Selan #define HOST_WIDE_INT int
14059995Selan #endif
14159995Selan 
14259995Selan #endif
14359995Selan 
14459995Selan #ifndef S_ISREG
14559995Selan #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
14659995Selan #endif
14759995Selan 
14859995Selan /* Define a generic NULL if one hasn't already been defined.  */
14959995Selan 
15059995Selan #ifndef NULL
15159995Selan #define NULL 0
15259995Selan #endif
15359995Selan 
15459995Selan #ifndef GENERIC_PTR
15559995Selan #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
15659995Selan #define GENERIC_PTR void *
15759995Selan #else
15859995Selan #define GENERIC_PTR char *
15959995Selan #endif
16059995Selan #endif
16159995Selan 
16259995Selan #ifndef NULL_PTR
16359995Selan #define NULL_PTR ((GENERIC_PTR)0)
16459995Selan #endif
16559995Selan 
16659995Selan #ifndef INCLUDE_LEN_FUDGE
16759995Selan #define INCLUDE_LEN_FUDGE 0
16859995Selan #endif
16959995Selan 
17059995Selan /* Forward declarations.  */
17159995Selan 
17259995Selan char *xmalloc ();
17359995Selan void error ();
17459995Selan void warning ();
17559995Selan 
17659995Selan /* External declarations.  */
17759995Selan 
17859995Selan extern char *getenv ();
17959995Selan extern FILE *fdopen ();
18059995Selan extern char *version_string;
18159995Selan extern struct tm *localtime ();
18259995Selan extern int sys_nerr;
183*60376Selan extern const char *const sys_errlist[];
18459995Selan 
18559995Selan #ifndef errno
18659995Selan extern int errno;
18759995Selan #endif
18859995Selan 
18959995Selan /* Forward declarations.  */
19059995Selan 
19159995Selan struct directive;
19259995Selan struct file_buf;
19359995Selan struct arglist;
19459995Selan struct argdata;
19559995Selan 
19659995Selan #if defined(USG) || defined(VMS)
19759995Selan #ifndef BSTRING
19859995Selan void bcopy ();
19959995Selan void bzero ();
20059995Selan int bcmp ();
20159995Selan #endif
20259995Selan #endif
20359995Selan 
20459995Selan /* These functions are declared to return int instead of void since they
20559995Selan    are going to be placed in a table and some old compilers have trouble with
20659995Selan    pointers to functions returning void.  */
20759995Selan 
20859995Selan static int do_define ();
20959995Selan static int do_line ();
21059995Selan static int do_include ();
21159995Selan static int do_undef ();
21259995Selan static int do_error ();
21359995Selan static int do_pragma ();
21459995Selan static int do_ident ();
21559995Selan static int do_if ();
21659995Selan static int do_xifdef ();
21759995Selan static int do_else ();
21859995Selan static int do_elif ();
21959995Selan static int do_endif ();
22059995Selan static int do_sccs ();
22159995Selan static int do_once ();
22259995Selan static int do_assert ();
22359995Selan static int do_unassert ();
22459995Selan static int do_warning ();
22559995Selan 
22659995Selan static void add_import ();
22759995Selan static void append_include_chain ();
22859995Selan static void deps_output ();
22959995Selan static void make_undef ();
23059995Selan static void make_definition ();
23159995Selan static void make_assertion ();
23259995Selan static void path_include ();
23359995Selan static void initialize_builtins ();
23459995Selan static void initialize_char_syntax ();
23559995Selan static void dump_arg_n ();
23659995Selan static void dump_defn_1 ();
23759995Selan static void delete_macro ();
23859995Selan static void trigraph_pcp ();
23959995Selan static void rescan ();
24059995Selan static void finclude ();
24159995Selan static void validate_else ();
24259995Selan static int comp_def_part ();
24359995Selan static void error_from_errno ();
24459995Selan static void error_with_line ();
24559995Selan void pedwarn ();
24659995Selan static void pedwarn_with_file_and_line ();
24759995Selan static void fatal ();
24859995Selan void fancy_abort ();
24959995Selan static void pfatal_with_name ();
25059995Selan static void perror_with_name ();
25159995Selan static void print_containing_files ();
25259995Selan static int lookup_import ();
25359995Selan static int redundant_include_p ();
25459995Selan static is_system_include ();
25559995Selan static int check_preconditions ();
25659995Selan static void pcfinclude ();
25759995Selan static void pcstring_used ();
25859995Selan static void write_output ();
25959995Selan static int check_macro_name ();
26059995Selan static int compare_defs ();
26159995Selan static int compare_token_lists ();
26259995Selan static int eval_if_expression ();
26359995Selan static int discard_comments ();
26459995Selan static int delete_newlines ();
26559995Selan static int line_for_error ();
26659995Selan static int hashf ();
26759995Selan static int file_size_and_mode ();
26859995Selan 
26959995Selan static struct arglist *read_token_list ();
27059995Selan static void free_token_list ();
27159995Selan 
27259995Selan static struct hashnode *install ();
27359995Selan struct hashnode *lookup ();
27459995Selan 
27559995Selan static struct assertion_hashnode *assertion_install ();
27659995Selan static struct assertion_hashnode *assertion_lookup ();
27759995Selan 
27859995Selan static char *xrealloc ();
27959995Selan static char *xcalloc ();
28059995Selan static char *savestring ();
28159995Selan 
28259995Selan static void delete_assertion ();
28359995Selan static void macroexpand ();
28459995Selan static void dump_all_macros ();
28559995Selan static void conditional_skip ();
28659995Selan static void skip_if_group ();
28759995Selan static void output_line_command ();
28859995Selan 
28959995Selan /* Last arg to output_line_command.  */
29059995Selan enum file_change_code {same_file, enter_file, leave_file};
29159995Selan 
29259995Selan static int grow_outbuf ();
29359995Selan static int handle_directive ();
29459995Selan static void memory_full ();
29559995Selan 
29659995Selan static U_CHAR *macarg1 ();
29759995Selan static char *macarg ();
29859995Selan 
29959995Selan static U_CHAR *skip_to_end_of_comment ();
30059995Selan static U_CHAR *skip_quoted_string ();
30159995Selan static U_CHAR *skip_paren_group ();
30259995Selan 
30359995Selan static char *check_precompiled ();
30459995Selan /* static struct macrodef create_definition ();	[moved below] */
30559995Selan static void dump_single_macro ();
30659995Selan 
30759995Selan #ifndef FAILURE_EXIT_CODE
30859995Selan #define FAILURE_EXIT_CODE 33	/* gnu cc command understands this */
30959995Selan #endif
31059995Selan 
31159995Selan #ifndef SUCCESS_EXIT_CODE
31259995Selan #define SUCCESS_EXIT_CODE 0	/* 0 means success on Unix.  */
31359995Selan #endif
31459995Selan 
31559995Selan /* Name under which this program was invoked.  */
31659995Selan 
31759995Selan static char *progname;
31859995Selan 
31959995Selan /* Nonzero means use extra default include directories for C++.  */
32059995Selan 
32159995Selan static int cplusplus;
32259995Selan 
32359995Selan /* Nonzero means handle cplusplus style comments */
32459995Selan 
32559995Selan static int cplusplus_comments;
32659995Selan 
32759995Selan /* Nonzero means handle #import, for objective C.  */
32859995Selan 
32959995Selan static int objc;
33059995Selan 
33159995Selan /* Nonzero means this is an assembly file, and allow
33259995Selan    unknown directives, which could be comments.  */
33359995Selan 
33459995Selan static int lang_asm;
33559995Selan 
33659995Selan /* Current maximum length of directory names in the search path
33759995Selan    for include files.  (Altered as we get more of them.)  */
33859995Selan 
33959995Selan static int max_include_len;
34059995Selan 
34159995Selan /* Nonzero means turn NOTREACHED into #pragma NOTREACHED etc */
34259995Selan 
34359995Selan static int lint = 0;
34459995Selan 
34559995Selan /* Nonzero means copy comments into the output file.  */
34659995Selan 
34759995Selan static int put_out_comments = 0;
34859995Selan 
34959995Selan /* Nonzero means don't process the ANSI trigraph sequences.  */
35059995Selan 
35159995Selan static int no_trigraphs = 0;
35259995Selan 
35359995Selan /* Nonzero means print the names of included files rather than
35459995Selan    the preprocessed output.  1 means just the #include "...",
35559995Selan    2 means #include <...> as well.  */
35659995Selan 
35759995Selan static int print_deps = 0;
35859995Selan 
35959995Selan /* Nonzero means print names of header files (-H).  */
36059995Selan 
36159995Selan static int print_include_names = 0;
36259995Selan 
36359995Selan /* Nonzero means don't output line number information.  */
36459995Selan 
36559995Selan static int no_line_commands;
36659995Selan 
36759995Selan /* dump_only means inhibit output of the preprocessed text
36859995Selan              and instead output the definitions of all user-defined
36959995Selan              macros in a form suitable for use as input to cccp.
37059995Selan    dump_names means pass #define and the macro name through to output.
37159995Selan    dump_definitions means pass the whole definition (plus #define) through
37259995Selan */
37359995Selan 
37459995Selan static enum {dump_none, dump_only, dump_names, dump_definitions}
37559995Selan      dump_macros = dump_none;
37659995Selan 
37759995Selan /* Nonzero means pass all #define and #undef directives which we actually
37859995Selan    process through to the output stream.  This feature is used primarily
37959995Selan    to allow cc1 to record the #defines and #undefs for the sake of
38059995Selan    debuggers which understand about preprocessor macros, but it may
38159995Selan    also be useful with -E to figure out how symbols are defined, and
38259995Selan    where they are defined.  */
38359995Selan static int debug_output = 0;
38459995Selan 
38559995Selan /* Nonzero indicates special processing used by the pcp program.  The
38659995Selan    special effects of this mode are:
38759995Selan 
38859995Selan      Inhibit all macro expansion, except those inside #if directives.
38959995Selan 
39059995Selan      Process #define directives normally, and output their contents
39159995Selan      to the output file.
39259995Selan 
39359995Selan      Output preconditions to pcp_outfile indicating all the relevant
39459995Selan      preconditions for use of this file in a later cpp run.
39559995Selan */
39659995Selan static FILE *pcp_outfile;
39759995Selan 
39859995Selan /* Nonzero means we are inside an IF during a -pcp run.  In this mode
39959995Selan    macro expansion is done, and preconditions are output for all macro
40059995Selan    uses requiring them. */
40159995Selan static int pcp_inside_if;
40259995Selan 
40359995Selan /* Nonzero means never to include precompiled files. */
40459995Selan static int no_precomp;
40559995Selan 
40659995Selan /* Nonzero means give all the error messages the ANSI standard requires.  */
40759995Selan 
40859995Selan int pedantic;
40959995Selan 
41059995Selan /* Nonzero means try to make failure to fit ANSI C an error.  */
41159995Selan 
41259995Selan static int pedantic_errors;
41359995Selan 
41459995Selan /* Nonzero means don't print warning messages.  -w.  */
41559995Selan 
41659995Selan static int inhibit_warnings = 0;
41759995Selan 
41859995Selan /* Nonzero means warn if slash-star appears in a comment.  */
41959995Selan 
42059995Selan static int warn_comments;
42159995Selan 
42259995Selan /* Nonzero means warn if a macro argument is (or would be)
42359995Selan    stringified with -traditional.  */
42459995Selan 
42559995Selan static int warn_stringify;
42659995Selan 
42759995Selan /* Nonzero means warn if there are any trigraphs.  */
42859995Selan 
42959995Selan static int warn_trigraphs;
43059995Selan 
43159995Selan /* Nonzero means warn if #import is used.  */
43259995Selan 
43359995Selan static int warn_import = 1;
43459995Selan 
43559995Selan /* Nonzero means turn warnings into errors.  */
43659995Selan 
43759995Selan static int warnings_are_errors;
43859995Selan 
43959995Selan /* Nonzero means try to imitate old fashioned non-ANSI preprocessor.  */
44059995Selan 
44159995Selan int traditional;
44259995Selan 
44359995Selan /* Nonzero causes output not to be done,
44459995Selan    but directives such as #define that have side effects
44559995Selan    are still obeyed.  */
44659995Selan 
44759995Selan static int no_output;
44859995Selan 
44959995Selan /* Nonzero means that we have finished processing the command line options.
45059995Selan    This flag is used to decide whether or not to issue certain errors
45159995Selan    and/or warnings.  */
45259995Selan 
45359995Selan static int done_initializing = 0;
45459995Selan 
45559995Selan /* I/O buffer structure.
45659995Selan    The `fname' field is nonzero for source files and #include files
45759995Selan    and for the dummy text used for -D and -U.
45859995Selan    It is zero for rescanning results of macro expansion
45959995Selan    and for expanding macro arguments.  */
46059995Selan #define INPUT_STACK_MAX 200
46159995Selan static struct file_buf {
46259995Selan   char *fname;
46359995Selan   /* Filename specified with #line command.  */
46459995Selan   char *nominal_fname;
46559995Selan   /* Record where in the search path this file was found.
46659995Selan      For #include_next.  */
46759995Selan   struct file_name_list *dir;
46859995Selan   int lineno;
46959995Selan   int length;
47059995Selan   U_CHAR *buf;
47159995Selan   U_CHAR *bufp;
47259995Selan   /* Macro that this level is the expansion of.
47359995Selan      Included so that we can reenable the macro
47459995Selan      at the end of this level.  */
47559995Selan   struct hashnode *macro;
47659995Selan   /* Value of if_stack at start of this file.
47759995Selan      Used to prohibit unmatched #endif (etc) in an include file.  */
47859995Selan   struct if_stack *if_stack;
47959995Selan   /* Object to be freed at end of input at this level.  */
48059995Selan   U_CHAR *free_ptr;
48159995Selan   /* True if this is a header file included using <FILENAME>.  */
48259995Selan   char system_header_p;
48359995Selan } instack[INPUT_STACK_MAX];
48459995Selan 
48559995Selan static int last_error_tick;	   /* Incremented each time we print it.  */
48659995Selan static int input_file_stack_tick;  /* Incremented when the status changes.  */
48759995Selan 
48859995Selan /* Current nesting level of input sources.
48959995Selan    `instack[indepth]' is the level currently being read.  */
49059995Selan static int indepth = -1;
49159995Selan #define CHECK_DEPTH(code) \
49259995Selan   if (indepth >= (INPUT_STACK_MAX - 1))					\
49359995Selan     {									\
49459995Selan       error_with_line (line_for_error (instack[indepth].lineno),	\
49559995Selan 		       "macro or `#include' recursion too deep");	\
49659995Selan       code;								\
49759995Selan     }
49859995Selan 
49959995Selan /* Current depth in #include directives that use <...>.  */
50059995Selan static int system_include_depth = 0;
50159995Selan 
50259995Selan typedef struct file_buf FILE_BUF;
50359995Selan 
50459995Selan /* The output buffer.  Its LENGTH field is the amount of room allocated
50559995Selan    for the buffer, not the number of chars actually present.  To get
50659995Selan    that, subtract outbuf.buf from outbuf.bufp. */
50759995Selan 
50859995Selan #define OUTBUF_SIZE 10	/* initial size of output buffer */
50959995Selan static FILE_BUF outbuf;
51059995Selan 
51159995Selan /* Grow output buffer OBUF points at
51259995Selan    so it can hold at least NEEDED more chars.  */
51359995Selan 
51459995Selan #define check_expand(OBUF, NEEDED)  \
51559995Selan   (((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED))   \
51659995Selan    ? grow_outbuf ((OBUF), (NEEDED)) : 0)
51759995Selan 
51859995Selan struct file_name_list
51959995Selan   {
52059995Selan     struct file_name_list *next;
52159995Selan     char *fname;
52259995Selan     /* If the following is nonzero, it is a macro name.
52359995Selan        Don't include the file again if that macro is defined.  */
52459995Selan     U_CHAR *control_macro;
52559995Selan   };
52659995Selan 
52759995Selan /* #include "file" looks in source file dir, then stack. */
52859995Selan /* #include <file> just looks in the stack. */
52959995Selan /* -I directories are added to the end, then the defaults are added. */
53059995Selan static struct default_include { char *fname; int cplusplus; } include_defaults_array[]
53159995Selan #ifdef INCLUDE_DEFAULTS
53259995Selan   = INCLUDE_DEFAULTS;
53359995Selan #else
53459995Selan   = {
53559995Selan     /* Pick up GNU C++ specific include files.  */
53659995Selan     { GPLUSPLUS_INCLUDE_DIR, 1},
53759995Selan     { GCC_INCLUDE_DIR, 0},
53859995Selan #ifdef CROSS_COMPILE
53959995Selan     /* For cross-compilation, this dir name is generated
54059995Selan        automatically in Makefile.in.  */
54159995Selan     { CROSS_INCLUDE_DIR, 0 },
54259995Selan #else /* not CROSS_COMPILE */
54359995Selan     { LOCAL_INCLUDE_DIR, 0},
54459995Selan     /* Some systems have an extra dir of include files.  */
54559995Selan #ifdef SYSTEM_INCLUDE_DIR
54659995Selan     { SYSTEM_INCLUDE_DIR, 0},
54759995Selan #endif
54859995Selan     { STANDARD_INCLUDE_DIR, 0},
54959995Selan #endif /* not CROSS_COMPILE */
55059995Selan     { 0, 0}
55159995Selan     };
55259995Selan #endif /* no INCLUDE_DEFAULTS */
55359995Selan 
55459995Selan /* The code looks at the defaults through this pointer, rather than through
55559995Selan    the constant structure above.  This pointer gets changed if an environment
55659995Selan    variable specifies other defaults.  */
55759995Selan static struct default_include *include_defaults = include_defaults_array;
55859995Selan 
55959995Selan static struct file_name_list *include = 0;	/* First dir to search */
56059995Selan 	/* First dir to search for <file> */
56159995Selan /* This is the first element to use for #include <...>.
56259995Selan    If it is 0, use the entire chain for such includes.  */
56359995Selan static struct file_name_list *first_bracket_include = 0;
56459995Selan /* This is the first element in the chain that corresponds to
56559995Selan    a directory of system header files.  */
56659995Selan static struct file_name_list *first_system_include = 0;
56759995Selan static struct file_name_list *last_include = 0;	/* Last in chain */
56859995Selan 
56959995Selan /* Chain of include directories to put at the end of the other chain.  */
57059995Selan static struct file_name_list *after_include = 0;
57159995Selan static struct file_name_list *last_after_include = 0;	/* Last in chain */
57259995Selan 
57359995Selan /* List of included files that contained #pragma once.  */
57459995Selan static struct file_name_list *dont_repeat_files = 0;
57559995Selan 
57659995Selan /* List of other included files.
57759995Selan    If ->control_macro if nonzero, the file had a #ifndef
57859995Selan    around the entire contents, and ->control_macro gives the macro name.  */
57959995Selan static struct file_name_list *all_include_files = 0;
58059995Selan 
58159995Selan /* Directory prefix that should replace `/usr' in the standard
58259995Selan    include file directories.  */
58359995Selan static char *include_prefix;
58459995Selan 
58559995Selan /* Global list of strings read in from precompiled files.  This list
58659995Selan    is kept in the order the strings are read in, with new strings being
58759995Selan    added at the end through stringlist_tailp.  We use this list to output
58859995Selan    the strings at the end of the run.
58959995Selan */
59059995Selan static STRINGDEF *stringlist;
59159995Selan static STRINGDEF **stringlist_tailp = &stringlist;
59259995Selan 
59359995Selan 
59459995Selan /* Structure returned by create_definition */
59559995Selan typedef struct macrodef MACRODEF;
59659995Selan struct macrodef
59759995Selan {
59859995Selan   struct definition *defn;
59959995Selan   U_CHAR *symnam;
60059995Selan   int symlen;
60159995Selan };
60259995Selan 
60359995Selan static struct macrodef create_definition ();
60459995Selan 
60559995Selan 
60659995Selan /* Structure allocated for every #define.  For a simple replacement
60759995Selan    such as
60859995Selan    	#define foo bar ,
60959995Selan    nargs = -1, the `pattern' list is null, and the expansion is just
61059995Selan    the replacement text.  Nargs = 0 means a functionlike macro with no args,
61159995Selan    e.g.,
61259995Selan        #define getchar() getc (stdin) .
61359995Selan    When there are args, the expansion is the replacement text with the
61459995Selan    args squashed out, and the reflist is a list describing how to
61559995Selan    build the output from the input: e.g., "3 chars, then the 1st arg,
61659995Selan    then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
61759995Selan    The chars here come from the expansion.  Whatever is left of the
61859995Selan    expansion after the last arg-occurrence is copied after that arg.
61959995Selan    Note that the reflist can be arbitrarily long---
62059995Selan    its length depends on the number of times the arguments appear in
62159995Selan    the replacement text, not how many args there are.  Example:
62259995Selan    #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
62359995Selan    pattern list
62459995Selan      { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
62559995Selan    where (x, y) means (nchars, argno). */
62659995Selan 
62759995Selan typedef struct definition DEFINITION;
62859995Selan struct definition {
62959995Selan   int nargs;
63059995Selan   int length;			/* length of expansion string */
63159995Selan   int predefined;		/* True if the macro was builtin or */
63259995Selan 				/* came from the command line */
63359995Selan   U_CHAR *expansion;
63459995Selan   int line;			/* Line number of definition */
63559995Selan   char *file;			/* File of definition */
63659995Selan   char rest_args;		/* Nonzero if last arg. absorbs the rest */
63759995Selan   struct reflist {
63859995Selan     struct reflist *next;
63959995Selan     char stringify;		/* nonzero if this arg was preceded by a
64059995Selan 				   # operator. */
64159995Selan     char raw_before;		/* Nonzero if a ## operator before arg. */
64259995Selan     char raw_after;		/* Nonzero if a ## operator after arg. */
64359995Selan     char rest_args;		/* Nonzero if this arg. absorbs the rest */
64459995Selan     int nchars;			/* Number of literal chars to copy before
64559995Selan 				   this arg occurrence.  */
64659995Selan     int argno;			/* Number of arg to substitute (origin-0) */
64759995Selan   } *pattern;
64859995Selan   union {
64959995Selan     /* Names of macro args, concatenated in reverse order
65059995Selan        with comma-space between them.
65159995Selan        The only use of this is that we warn on redefinition
65259995Selan        if this differs between the old and new definitions.  */
65359995Selan     U_CHAR *argnames;
65459995Selan   } args;
65559995Selan };
65659995Selan 
65759995Selan /* different kinds of things that can appear in the value field
65859995Selan    of a hash node.  Actually, this may be useless now. */
65959995Selan union hashval {
66059995Selan   int ival;
66159995Selan   char *cpval;
66259995Selan   DEFINITION *defn;
66359995Selan   KEYDEF *keydef;
66459995Selan };
66559995Selan 
66659995Selan /*
66759995Selan  * special extension string that can be added to the last macro argument to
66859995Selan  * allow it to absorb the "rest" of the arguments when expanded.  Ex:
66959995Selan  * 		#define wow(a, b...)		process(b, a, b)
67059995Selan  *		{ wow(1, 2, 3); }	->	{ process( 2, 3, 1,  2, 3); }
67159995Selan  *		{ wow(one, two); }	->	{ process( two, one,  two); }
67259995Selan  * if this "rest_arg" is used with the concat token '##' and if it is not
67359995Selan  * supplied then the token attached to with ## will not be outputted.  Ex:
67459995Selan  * 		#define wow(a, b...)		process(b ## , a, ## b)
67559995Selan  *		{ wow(1, 2); }		->	{ process( 2, 1,2); }
67659995Selan  *		{ wow(one); }		->	{ process( one); {
67759995Selan  */
67859995Selan static char rest_extension[] = "...";
67959995Selan #define REST_EXTENSION_LENGTH	(sizeof (rest_extension) - 1)
68059995Selan 
68159995Selan /* The structure of a node in the hash table.  The hash table
68259995Selan    has entries for all tokens defined by #define commands (type T_MACRO),
68359995Selan    plus some special tokens like __LINE__ (these each have their own
68459995Selan    type, and the appropriate code is run when that type of node is seen.
68559995Selan    It does not contain control words like "#define", which are recognized
68659995Selan    by a separate piece of code. */
68759995Selan 
68859995Selan /* different flavors of hash nodes --- also used in keyword table */
68959995Selan enum node_type {
69059995Selan  T_DEFINE = 1,	/* the `#define' keyword */
69159995Selan  T_INCLUDE,	/* the `#include' keyword */
69259995Selan  T_INCLUDE_NEXT, /* the `#include_next' keyword */
69359995Selan  T_IMPORT,      /* the `#import' keyword */
69459995Selan  T_IFDEF,	/* the `#ifdef' keyword */
69559995Selan  T_IFNDEF,	/* the `#ifndef' keyword */
69659995Selan  T_IF,		/* the `#if' keyword */
69759995Selan  T_ELSE,	/* `#else' */
69859995Selan  T_PRAGMA,	/* `#pragma' */
69959995Selan  T_ELIF,	/* `#elif' */
70059995Selan  T_UNDEF,	/* `#undef' */
70159995Selan  T_LINE,	/* `#line' */
70259995Selan  T_ERROR,	/* `#error' */
70359995Selan  T_WARNING,	/* `#warning' */
70459995Selan  T_ENDIF,	/* `#endif' */
70559995Selan  T_SCCS,	/* `#sccs', used on system V.  */
70659995Selan  T_IDENT,	/* `#ident', used on system V.  */
70759995Selan  T_ASSERT,	/* `#assert', taken from system V.  */
70859995Selan  T_UNASSERT,	/* `#unassert', taken from system V.  */
70959995Selan  T_SPECLINE,	/* special symbol `__LINE__' */
71059995Selan  T_DATE,	/* `__DATE__' */
71159995Selan  T_FILE,	/* `__FILE__' */
71259995Selan  T_BASE_FILE,	/* `__BASE_FILE__' */
71359995Selan  T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
71459995Selan  T_VERSION,	/* `__VERSION__' */
71559995Selan  T_SIZE_TYPE,   /* `__SIZE_TYPE__' */
71659995Selan  T_PTRDIFF_TYPE,   /* `__PTRDIFF_TYPE__' */
71759995Selan  T_WCHAR_TYPE,   /* `__WCHAR_TYPE__' */
71859995Selan  T_TIME,	/* `__TIME__' */
71959995Selan  T_CONST,	/* Constant value, used by `__STDC__' */
72059995Selan  T_MACRO,	/* macro defined by `#define' */
72159995Selan  T_DISABLED,	/* macro temporarily turned off for rescan */
72259995Selan  T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
72359995Selan  T_PCSTRING,	/* precompiled string (hashval is KEYDEF *) */
72459995Selan  T_UNUSED	/* Used for something not defined.  */
72559995Selan  };
72659995Selan 
72759995Selan struct hashnode {
72859995Selan   struct hashnode *next;	/* double links for easy deletion */
72959995Selan   struct hashnode *prev;
73059995Selan   struct hashnode **bucket_hdr;	/* also, a back pointer to this node's hash
73159995Selan 				   chain is kept, in case the node is the head
73259995Selan 				   of the chain and gets deleted. */
73359995Selan   enum node_type type;		/* type of special token */
73459995Selan   int length;			/* length of token, for quick comparison */
73559995Selan   U_CHAR *name;			/* the actual name */
73659995Selan   union hashval value;		/* pointer to expansion, or whatever */
73759995Selan };
73859995Selan 
73959995Selan typedef struct hashnode HASHNODE;
74059995Selan 
74159995Selan /* Some definitions for the hash table.  The hash function MUST be
74259995Selan    computed as shown in hashf () below.  That is because the rescan
74359995Selan    loop computes the hash value `on the fly' for most tokens,
74459995Selan    in order to avoid the overhead of a lot of procedure calls to
74559995Selan    the hashf () function.  Hashf () only exists for the sake of
74659995Selan    politeness, for use when speed isn't so important. */
74759995Selan 
74859995Selan #define HASHSIZE 1403
74959995Selan static HASHNODE *hashtab[HASHSIZE];
75059995Selan #define HASHSTEP(old, c) ((old << 2) + c)
75159995Selan #define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
75259995Selan 
75359995Selan /* Symbols to predefine.  */
75459995Selan 
75559995Selan #ifdef CPP_PREDEFINES
75659995Selan static char *predefs = CPP_PREDEFINES;
75759995Selan #else
75859995Selan static char *predefs = "";
75959995Selan #endif
76059995Selan 
76159995Selan /* We let tm.h override the types used here, to handle trivial differences
76259995Selan    such as the choice of unsigned int or long unsigned int for size_t.
76359995Selan    When machines start needing nontrivial differences in the size type,
76459995Selan    it would be best to do something here to figure out automatically
76559995Selan    from other information what type to use.  */
76659995Selan 
76759995Selan /* The string value for __size_type__.  */
76859995Selan 
76959995Selan #ifndef SIZE_TYPE
77059995Selan #define SIZE_TYPE "long unsigned int"
77159995Selan #endif
77259995Selan 
77359995Selan /* The string value for __ptrdiff_type__.  */
77459995Selan 
77559995Selan #ifndef PTRDIFF_TYPE
77659995Selan #define PTRDIFF_TYPE "long int"
77759995Selan #endif
77859995Selan 
77959995Selan /* The string value for __wchar_type__.  */
78059995Selan 
78159995Selan #ifndef WCHAR_TYPE
78259995Selan #define WCHAR_TYPE "int"
78359995Selan #endif
78459995Selan 
78559995Selan /* In the definition of a #assert name, this structure forms
78659995Selan    a list of the individual values asserted.
78759995Selan    Each value is itself a list of "tokens".
78859995Selan    These are strings that are compared by name.  */
78959995Selan 
79059995Selan struct tokenlist_list {
79159995Selan   struct tokenlist_list *next;
79259995Selan   struct arglist *tokens;
79359995Selan };
79459995Selan 
79559995Selan struct assertion_hashnode {
79659995Selan   struct assertion_hashnode *next;	/* double links for easy deletion */
79759995Selan   struct assertion_hashnode *prev;
79859995Selan   /* also, a back pointer to this node's hash
79959995Selan      chain is kept, in case the node is the head
80059995Selan      of the chain and gets deleted. */
80159995Selan   struct assertion_hashnode **bucket_hdr;
80259995Selan   int length;			/* length of token, for quick comparison */
80359995Selan   U_CHAR *name;			/* the actual name */
80459995Selan   /* List of token-sequences.  */
80559995Selan   struct tokenlist_list *value;
80659995Selan };
80759995Selan 
80859995Selan typedef struct assertion_hashnode ASSERTION_HASHNODE;
80959995Selan 
81059995Selan /* Some definitions for the hash table.  The hash function MUST be
81159995Selan    computed as shown in hashf below.  That is because the rescan
81259995Selan    loop computes the hash value `on the fly' for most tokens,
81359995Selan    in order to avoid the overhead of a lot of procedure calls to
81459995Selan    the hashf function.  hashf only exists for the sake of
81559995Selan    politeness, for use when speed isn't so important. */
81659995Selan 
81759995Selan #define ASSERTION_HASHSIZE 37
81859995Selan static ASSERTION_HASHNODE *assertion_hashtab[ASSERTION_HASHSIZE];
81959995Selan 
82059995Selan /* Nonzero means inhibit macroexpansion of what seem to be
82159995Selan    assertion tests, in rescan.  For #if.  */
82259995Selan static int assertions_flag;
82359995Selan 
82459995Selan /* `struct directive' defines one #-directive, including how to handle it.  */
82559995Selan 
82659995Selan struct directive {
82759995Selan   int length;			/* Length of name */
82859995Selan   int (*func)();		/* Function to handle directive */
82959995Selan   char *name;			/* Name of directive */
83059995Selan   enum node_type type;		/* Code which describes which directive. */
83159995Selan   char angle_brackets;		/* Nonzero => <...> is special.  */
83259995Selan   char traditional_comments;	/* Nonzero: keep comments if -traditional.  */
83359995Selan   char pass_thru;		/* Copy preprocessed directive to output file.  */
83459995Selan };
83559995Selan 
83659995Selan /* Here is the actual list of #-directives, most-often-used first.  */
83759995Selan 
83859995Selan static struct directive directive_table[] = {
83959995Selan   {  6, do_define, "define", T_DEFINE, 0, 1},
84059995Selan   {  2, do_if, "if", T_IF},
84159995Selan   {  5, do_xifdef, "ifdef", T_IFDEF},
84259995Selan   {  6, do_xifdef, "ifndef", T_IFNDEF},
84359995Selan   {  5, do_endif, "endif", T_ENDIF},
84459995Selan   {  4, do_else, "else", T_ELSE},
84559995Selan   {  4, do_elif, "elif", T_ELIF},
84659995Selan   {  4, do_line, "line", T_LINE},
84759995Selan   {  7, do_include, "include", T_INCLUDE, 1},
84859995Selan   { 12, do_include, "include_next", T_INCLUDE_NEXT, 1},
84959995Selan   {  6, do_include, "import", T_IMPORT, 1},
85059995Selan   {  5, do_undef, "undef", T_UNDEF},
85159995Selan   {  5, do_error, "error", T_ERROR},
85259995Selan   {  7, do_warning, "warning", T_WARNING},
85359995Selan #ifdef SCCS_DIRECTIVE
85459995Selan   {  4, do_sccs, "sccs", T_SCCS},
85559995Selan #endif
85659995Selan   {  6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1},
85759995Selan   {  5, do_ident, "ident", T_IDENT, 0, 0, 1},
85859995Selan   {  6, do_assert, "assert", T_ASSERT},
85959995Selan   {  8, do_unassert, "unassert", T_UNASSERT},
86059995Selan   {  -1, 0, "", T_UNUSED},
86159995Selan };
86259995Selan 
86359995Selan /* When a directive handler is called,
86459995Selan    this points to the # that started the directive.  */
86559995Selan U_CHAR *directive_start;
86659995Selan 
86759995Selan /* table to tell if char can be part of a C identifier. */
86859995Selan U_CHAR is_idchar[256];
86959995Selan /* table to tell if char can be first char of a c identifier. */
87059995Selan U_CHAR is_idstart[256];
87159995Selan /* table to tell if c is horizontal space.  */
87259995Selan U_CHAR is_hor_space[256];
87359995Selan /* table to tell if c is horizontal or vertical space.  */
87459995Selan static U_CHAR is_space[256];
87559995Selan 
87659995Selan #define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
87759995Selan #define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
87859995Selan 
87959995Selan static int errors = 0;			/* Error counter for exit code */
88059995Selan 
88159995Selan /* Zero means dollar signs are punctuation.
88259995Selan    -$ stores 0; -traditional may store 1.  Default is 1 for VMS, 0 otherwise.
88359995Selan    This must be 0 for correct processing of this ANSI C program:
88459995Selan 	#define foo(a) #a
88559995Selan 	#define lose(b) foo(b)
88659995Selan 	#define test$
88759995Selan 	lose(test)	*/
88859995Selan static int dollars_in_ident;
88959995Selan #ifndef DOLLARS_IN_IDENTIFIERS
89059995Selan #define DOLLARS_IN_IDENTIFIERS 1
89159995Selan #endif
89259995Selan 
89359995Selan static FILE_BUF expand_to_temp_buffer ();
89459995Selan 
89559995Selan static DEFINITION *collect_expansion ();
89659995Selan 
89759995Selan /* Stack of conditionals currently in progress
89859995Selan    (including both successful and failing conditionals).  */
89959995Selan 
90059995Selan struct if_stack {
90159995Selan   struct if_stack *next;	/* for chaining to the next stack frame */
90259995Selan   char *fname;		/* copied from input when frame is made */
90359995Selan   int lineno;			/* similarly */
90459995Selan   int if_succeeded;		/* true if a leg of this if-group
90559995Selan 				    has been passed through rescan */
90659995Selan   U_CHAR *control_macro;	/* For #ifndef at start of file,
90759995Selan 				   this is the macro name tested.  */
90859995Selan   enum node_type type;		/* type of last directive seen in this group */
90959995Selan };
91059995Selan typedef struct if_stack IF_STACK_FRAME;
91159995Selan static IF_STACK_FRAME *if_stack = NULL;
91259995Selan 
91359995Selan /* Buffer of -M output.  */
91459995Selan static char *deps_buffer;
91559995Selan 
91659995Selan /* Number of bytes allocated in above.  */
91759995Selan static int deps_allocated_size;
91859995Selan 
91959995Selan /* Number of bytes used.  */
92059995Selan static int deps_size;
92159995Selan 
92259995Selan /* Number of bytes since the last newline.  */
92359995Selan static int deps_column;
92459995Selan 
92559995Selan /* Nonzero means -I- has been seen,
92659995Selan    so don't look for #include "foo" the source-file directory.  */
92759995Selan static int ignore_srcdir;
92859995Selan 
92959995Selan int
main(argc,argv)93059995Selan main (argc, argv)
93159995Selan      int argc;
93259995Selan      char **argv;
93359995Selan {
93459995Selan   int st_mode;
93559995Selan   long st_size;
93659995Selan   char *in_fname, *out_fname;
93759995Selan   char *p;
93859995Selan   int f, i;
93959995Selan   FILE_BUF *fp;
94059995Selan   char **pend_files = (char **) xmalloc (argc * sizeof (char *));
94159995Selan   char **pend_defs = (char **) xmalloc (argc * sizeof (char *));
94259995Selan   char **pend_undefs = (char **) xmalloc (argc * sizeof (char *));
94359995Selan   char **pend_assertions = (char **) xmalloc (argc * sizeof (char *));
94459995Selan   char **pend_includes = (char **) xmalloc (argc * sizeof (char *));
94559995Selan 
94659995Selan   /* Record the option used with each element of pend_assertions.
94759995Selan      This is preparation for supporting more than one option for making
94859995Selan      an assertion.  */
94959995Selan   char **pend_assertion_options = (char **) xmalloc (argc * sizeof (char *));
95059995Selan   int inhibit_predefs = 0;
95159995Selan   int no_standard_includes = 0;
95259995Selan   int no_standard_cplusplus_includes = 0;
95359995Selan   int missing_newline = 0;
95459995Selan 
95559995Selan   /* Non-0 means don't output the preprocessed program.  */
95659995Selan   int inhibit_output = 0;
95759995Selan 
95859995Selan   /* File name which deps are being written to.
95959995Selan      This is 0 if deps are being written to stdout.  */
96059995Selan   char *deps_file = 0;
96159995Selan   /* Stream on which to print the dependency information.  */
96259995Selan   FILE *deps_stream = 0;
96359995Selan   /* Target-name to write with the dependency information.  */
96459995Selan   char *deps_target = 0;
96559995Selan 
96659995Selan #ifdef RLIMIT_STACK
96759995Selan   /* Get rid of any avoidable limit on stack size.  */
96859995Selan   {
96959995Selan     struct rlimit rlim;
97059995Selan 
97159995Selan     /* Set the stack limit huge so that alloca (particularly stringtab
97259995Selan      * in dbxread.c) does not fail. */
97359995Selan     getrlimit (RLIMIT_STACK, &rlim);
97459995Selan     rlim.rlim_cur = rlim.rlim_max;
97559995Selan     setrlimit (RLIMIT_STACK, &rlim);
97659995Selan   }
97759995Selan #endif /* RLIMIT_STACK defined */
97859995Selan 
97959995Selan   progname = argv[0];
98059995Selan #ifdef VMS
98159995Selan   {
98259995Selan     /* Remove directories from PROGNAME.  */
98359995Selan     char *s;
98459995Selan 
98559995Selan     progname = savestring (argv[0]);
98659995Selan 
98759995Selan     if (!(s = rindex (progname, ']')))
98859995Selan       s = rindex (progname, ':');
98959995Selan     if (s)
99059995Selan       strcpy (progname, s+1);
99159995Selan     if (s = rindex (progname, '.'))
99259995Selan       *s = '\0';
99359995Selan   }
99459995Selan #endif
99559995Selan 
99659995Selan   in_fname = NULL;
99759995Selan   out_fname = NULL;
99859995Selan 
99959995Selan   /* Initialize is_idchar to allow $.  */
100059995Selan   dollars_in_ident = 1;
100159995Selan   initialize_char_syntax ();
100259995Selan   dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 0;
100359995Selan 
100459995Selan   no_line_commands = 0;
100559995Selan   no_trigraphs = 1;
100659995Selan   dump_macros = dump_none;
100759995Selan   no_output = 0;
100859995Selan   cplusplus = 0;
100959995Selan   cplusplus_comments = 0;
101059995Selan 
101159995Selan   bzero (pend_files, argc * sizeof (char *));
101259995Selan   bzero (pend_defs, argc * sizeof (char *));
101359995Selan   bzero (pend_undefs, argc * sizeof (char *));
101459995Selan   bzero (pend_assertions, argc * sizeof (char *));
101559995Selan   bzero (pend_includes, argc * sizeof (char *));
101659995Selan 
101759995Selan   /* Process switches and find input file name.  */
101859995Selan 
101959995Selan   for (i = 1; i < argc; i++) {
102059995Selan     if (argv[i][0] != '-') {
102159995Selan       if (out_fname != NULL)
102259995Selan 	fatal ("Usage: %s [switches] input output", argv[0]);
102359995Selan       else if (in_fname != NULL)
102459995Selan 	out_fname = argv[i];
102559995Selan       else
102659995Selan 	in_fname = argv[i];
102759995Selan     } else {
102859995Selan       switch (argv[i][1]) {
102959995Selan 
103059995Selan       case 'i':
103159995Selan 	if (!strcmp (argv[i], "-include")) {
103259995Selan 	  if (i + 1 == argc)
103359995Selan 	    fatal ("Filename missing after -include option");
103459995Selan 	  else
103559995Selan 	    pend_includes[i] = argv[i+1], i++;
103659995Selan 	}
103759995Selan 	if (!strcmp (argv[i], "-imacros")) {
103859995Selan 	  if (i + 1 == argc)
103959995Selan 	    fatal ("Filename missing after -imacros option");
104059995Selan 	  else
104159995Selan 	    pend_files[i] = argv[i+1], i++;
104259995Selan 	}
104359995Selan 	if (!strcmp (argv[i], "-iprefix")) {
104459995Selan 	  if (i + 1 == argc)
104559995Selan 	    fatal ("Filename missing after -iprefix option");
104659995Selan 	  else
104759995Selan 	    include_prefix = argv[++i];
104859995Selan 	}
104959995Selan 	/* Add directory to end of path for includes.  */
105059995Selan 	if (!strcmp (argv[i], "-idirafter")) {
105159995Selan 	  struct file_name_list *dirtmp;
105259995Selan 
105359995Selan 	  dirtmp = (struct file_name_list *)
105459995Selan 	    xmalloc (sizeof (struct file_name_list));
105559995Selan 	  dirtmp->next = 0;	/* New one goes on the end */
105659995Selan 	  dirtmp->control_macro = 0;
105759995Selan 	  if (i + 1 == argc)
105859995Selan 	    fatal ("Directory name missing after -idirafter option");
105959995Selan 	  else
106059995Selan 	    dirtmp->fname = argv[++i];
106159995Selan 
106259995Selan 	  if (after_include == 0)
106359995Selan 	    after_include = dirtmp;
106459995Selan 	  else
106559995Selan 	    last_after_include->next = dirtmp;
106659995Selan 	  last_after_include = dirtmp; /* Tail follows the last one */
106759995Selan 	}
106859995Selan 	break;
106959995Selan 
107059995Selan       case 'o':
107159995Selan 	if (out_fname != NULL)
107259995Selan 	  fatal ("Output filename specified twice");
107359995Selan 	if (i + 1 == argc)
107459995Selan 	  fatal ("Filename missing after -o option");
107559995Selan 	out_fname = argv[++i];
107659995Selan 	if (!strcmp (out_fname, "-"))
107759995Selan 	  out_fname = "";
107859995Selan 	break;
107959995Selan 
108059995Selan       case 'p':
108159995Selan 	if (!strcmp (argv[i], "-pedantic"))
108259995Selan 	  pedantic = 1;
108359995Selan 	else if (!strcmp (argv[i], "-pedantic-errors")) {
108459995Selan 	  pedantic = 1;
108559995Selan 	  pedantic_errors = 1;
108659995Selan 	} else if (!strcmp (argv[i], "-pcp")) {
108759995Selan 	  char *pcp_fname = argv[++i];
108859995Selan 	  pcp_outfile =
108959995Selan 	    ((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
109059995Selan 	     ? fopen (pcp_fname, "w")
109159995Selan 	     : fdopen (dup (fileno (stdout)), "w"));
109259995Selan 	  if (pcp_outfile == 0)
109359995Selan 	    pfatal_with_name (pcp_fname);
109459995Selan 	  no_precomp = 1;
109559995Selan 	}
109659995Selan 	break;
109759995Selan 
109859995Selan       case 't':
109959995Selan 	if (!strcmp (argv[i], "-traditional")) {
110059995Selan 	  traditional = 1;
110159995Selan 	  if (dollars_in_ident > 0)
110259995Selan 	    dollars_in_ident = 1;
110359995Selan 	} else if (!strcmp (argv[i], "-trigraphs")) {
110459995Selan 	  no_trigraphs = 0;
110559995Selan 	}
110659995Selan 	break;
110759995Selan 
110859995Selan       case 'l':
110959995Selan 	if (! strcmp (argv[i], "-lang-c"))
111059995Selan 	  cplusplus = 0, cplusplus_comments = 0, objc = 0;
111159995Selan 	if (! strcmp (argv[i], "-lang-c++"))
111259995Selan 	  cplusplus = 1, cplusplus_comments = 1, objc = 0;
111359995Selan 	if (! strcmp (argv[i], "-lang-objc"))
111459995Selan 	  objc = 1, cplusplus = 0, cplusplus_comments = 1;
111559995Selan 	if (! strcmp (argv[i], "-lang-objc++"))
111659995Selan 	  objc = 1, cplusplus = 1, cplusplus_comments = 1;
111759995Selan  	if (! strcmp (argv[i], "-lang-asm"))
111859995Selan  	  lang_asm = 1;
111959995Selan  	if (! strcmp (argv[i], "-lint"))
112059995Selan  	  lint = 1;
112159995Selan 	break;
112259995Selan 
112359995Selan       case '+':
112459995Selan 	cplusplus = 1, cplusplus_comments = 1;
112559995Selan 	break;
112659995Selan 
112759995Selan       case 'w':
112859995Selan 	inhibit_warnings = 1;
112959995Selan 	break;
113059995Selan 
113159995Selan       case 'W':
113259995Selan 	if (!strcmp (argv[i], "-Wtrigraphs"))
113359995Selan 	  warn_trigraphs = 1;
113459995Selan 	else if (!strcmp (argv[i], "-Wno-trigraphs"))
113559995Selan 	  warn_trigraphs = 0;
113659995Selan 	else if (!strcmp (argv[i], "-Wcomment"))
113759995Selan 	  warn_comments = 1;
113859995Selan 	else if (!strcmp (argv[i], "-Wno-comment"))
113959995Selan 	  warn_comments = 0;
114059995Selan 	else if (!strcmp (argv[i], "-Wcomments"))
114159995Selan 	  warn_comments = 1;
114259995Selan 	else if (!strcmp (argv[i], "-Wno-comments"))
114359995Selan 	  warn_comments = 0;
114459995Selan 	else if (!strcmp (argv[i], "-Wtraditional"))
114559995Selan 	  warn_stringify = 1;
114659995Selan 	else if (!strcmp (argv[i], "-Wno-traditional"))
114759995Selan 	  warn_stringify = 0;
114859995Selan 	else if (!strcmp (argv[i], "-Wimport"))
114959995Selan 	  warn_import = 1;
115059995Selan 	else if (!strcmp (argv[i], "-Wno-import"))
115159995Selan 	  warn_import = 0;
115259995Selan 	else if (!strcmp (argv[i], "-Werror"))
115359995Selan 	  warnings_are_errors = 1;
115459995Selan 	else if (!strcmp (argv[i], "-Wno-error"))
115559995Selan 	  warnings_are_errors = 0;
115659995Selan 	else if (!strcmp (argv[i], "-Wall"))
115759995Selan 	  {
115859995Selan 	    warn_trigraphs = 1;
115959995Selan 	    warn_comments = 1;
116059995Selan 	  }
116159995Selan 	break;
116259995Selan 
116359995Selan       case 'M':
116459995Selan 	if (!strcmp (argv[i], "-M"))
116559995Selan 	  print_deps = 2;
116659995Selan 	else if (!strcmp (argv[i], "-MM"))
116759995Selan 	  print_deps = 1;
116859995Selan 	else if (!strcmp (argv[i], "-MD"))
116959995Selan 	  print_deps = 2;
117059995Selan 	else if (!strcmp (argv[i], "-MMD"))
117159995Selan 	  print_deps = 1;
117259995Selan 	/* For -MD and -MMD options, write deps on file named by next arg.  */
117359995Selan 	if (!strcmp (argv[i], "-MD")
117459995Selan 	    || !strcmp (argv[i], "-MMD")) {
117559995Selan 	  i++;
117659995Selan 	  deps_file = argv[i];
117759995Selan 	} else {
117859995Selan 	  /* For -M and -MM, write deps on standard output
117959995Selan 	     and suppress the usual output.  */
118059995Selan 	  deps_stream = stdout;
118159995Selan 	  inhibit_output = 1;
118259995Selan 	}
118359995Selan 	break;
118459995Selan 
118559995Selan       case 'd':
118659995Selan 	{
118759995Selan 	  char *p = argv[i] + 2;
118859995Selan 	  char c;
118959995Selan 	  while (c = *p++) {
119059995Selan 	    /* Arg to -d specifies what parts of macros to dump */
119159995Selan 	    switch (c) {
119259995Selan 	    case 'M':
119359995Selan 	      dump_macros = dump_only;
119459995Selan 	      no_output = 1;
119559995Selan 	      break;
119659995Selan 	    case 'N':
119759995Selan 	      dump_macros = dump_names;
119859995Selan 	      break;
119959995Selan 	    case 'D':
120059995Selan 	      dump_macros = dump_definitions;
120159995Selan 	      break;
120259995Selan 	    }
120359995Selan 	  }
120459995Selan 	}
120559995Selan 	break;
120659995Selan 
120759995Selan       case 'g':
120859995Selan 	if (argv[i][2] == '3')
120959995Selan 	  debug_output = 1;
121059995Selan 	break;
121159995Selan 
121259995Selan       case 'v':
121359995Selan 	fprintf (stderr, "GNU CPP version %s", version_string);
121459995Selan #ifdef TARGET_VERSION
121559995Selan 	TARGET_VERSION;
121659995Selan #endif
121759995Selan 	fprintf (stderr, "\n");
121859995Selan 	break;
121959995Selan 
122059995Selan       case 'H':
122159995Selan 	print_include_names = 1;
122259995Selan 	break;
122359995Selan 
122459995Selan       case 'D':
122559995Selan 	{
122659995Selan 	  char *p, *p1;
122759995Selan 
122859995Selan 	  if (argv[i][2] != 0)
122959995Selan 	    p = argv[i] + 2;
123059995Selan 	  else if (i + 1 == argc)
123159995Selan 	    fatal ("Macro name missing after -D option");
123259995Selan 	  else
123359995Selan 	    p = argv[++i];
123459995Selan 
123559995Selan 	  pend_defs[i] = p;
123659995Selan 	}
123759995Selan 	break;
123859995Selan 
123959995Selan       case 'A':
124059995Selan 	{
124159995Selan 	  char *p, *p1;
124259995Selan 
124359995Selan 	  if (argv[i][2] != 0)
124459995Selan 	    p = argv[i] + 2;
124559995Selan 	  else if (i + 1 == argc)
124659995Selan 	    fatal ("Assertion missing after -A option");
124759995Selan 	  else
124859995Selan 	    p = argv[++i];
124959995Selan 
125059995Selan 	  if (!strcmp (p, "-")) {
125159995Selan 	    /* -A- eliminates all predefined macros and assertions.
125259995Selan 	       Let's include also any that were specified earlier
125359995Selan 	       on the command line.  That way we can get rid of any
125459995Selan 	       that were passed automatically in from GCC.  */
125559995Selan 	    int j;
125659995Selan 	    inhibit_predefs = 1;
125759995Selan 	    for (j = 0; j < i; j++)
125859995Selan 	      pend_defs[j] = pend_assertions[j] = 0;
125959995Selan 	  } else {
126059995Selan 	    pend_assertions[i] = p;
126159995Selan 	    pend_assertion_options[i] = "-A";
126259995Selan 	  }
126359995Selan 	}
126459995Selan 	break;
126559995Selan 
126659995Selan       case 'U':		/* JF #undef something */
126759995Selan 	if (argv[i][2] != 0)
126859995Selan 	  pend_undefs[i] = argv[i] + 2;
126959995Selan 	else if (i + 1 == argc)
127059995Selan 	  fatal ("Macro name missing after -U option");
127159995Selan 	else
127259995Selan 	  pend_undefs[i] = argv[i+1], i++;
127359995Selan 	break;
127459995Selan 
127559995Selan       case 'C':
127659995Selan 	put_out_comments = 1;
127759995Selan 	break;
127859995Selan 
127959995Selan       case 'E':			/* -E comes from cc -E; ignore it.  */
128059995Selan 	break;
128159995Selan 
128259995Selan       case 'P':
128359995Selan 	no_line_commands = 1;
128459995Selan 	break;
128559995Selan 
128659995Selan       case '$':			/* Don't include $ in identifiers.  */
128759995Selan 	dollars_in_ident = 0;
128859995Selan 	break;
128959995Selan 
129059995Selan       case 'I':			/* Add directory to path for includes.  */
129159995Selan 	{
129259995Selan 	  struct file_name_list *dirtmp;
129359995Selan 
129459995Selan 	  if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) {
129559995Selan 	    ignore_srcdir = 1;
129659995Selan 	    /* Don't use any preceding -I directories for #include <...>.  */
129759995Selan 	    first_bracket_include = 0;
129859995Selan 	  }
129959995Selan 	  else {
130059995Selan 	    dirtmp = (struct file_name_list *)
130159995Selan 	      xmalloc (sizeof (struct file_name_list));
130259995Selan 	    dirtmp->next = 0;		/* New one goes on the end */
130359995Selan 	    dirtmp->control_macro = 0;
130459995Selan 	    if (argv[i][2] != 0)
130559995Selan 	      dirtmp->fname = argv[i] + 2;
130659995Selan 	    else if (i + 1 == argc)
130759995Selan 	      fatal ("Directory name missing after -I option");
130859995Selan 	    else
130959995Selan 	      dirtmp->fname = argv[++i];
131059995Selan 	    append_include_chain (dirtmp, dirtmp);
131159995Selan 	  }
131259995Selan 	}
131359995Selan 	break;
131459995Selan 
131559995Selan       case 'n':
131659995Selan 	if (!strcmp (argv[i], "-nostdinc"))
131759995Selan 	  /* -nostdinc causes no default include directories.
131859995Selan 	     You must specify all include-file directories with -I.  */
131959995Selan 	  no_standard_includes = 1;
132059995Selan 	else if (!strcmp (argv[i], "-nostdinc++"))
132159995Selan 	  /* -nostdinc++ causes no default C++-specific include directories. */
132259995Selan 	  no_standard_cplusplus_includes = 1;
132359995Selan 	else if (!strcmp (argv[i], "-noprecomp"))
132459995Selan 	  no_precomp = 1;
132559995Selan 	break;
132659995Selan 
132759995Selan       case 'u':
132859995Selan 	/* Sun compiler passes undocumented switch "-undef".
132959995Selan 	   Let's assume it means to inhibit the predefined symbols.  */
133059995Selan 	inhibit_predefs = 1;
133159995Selan 	break;
133259995Selan 
133359995Selan       case '\0': /* JF handle '-' as file name meaning stdin or stdout */
133459995Selan 	if (in_fname == NULL) {
133559995Selan 	  in_fname = "";
133659995Selan 	  break;
133759995Selan 	} else if (out_fname == NULL) {
133859995Selan 	  out_fname = "";
133959995Selan 	  break;
134059995Selan 	}	/* else fall through into error */
134159995Selan 
134259995Selan       default:
134359995Selan 	fatal ("Invalid option `%s'", argv[i]);
134459995Selan       }
134559995Selan     }
134659995Selan   }
134759995Selan 
134859995Selan   /* Add dirs from CPATH after dirs from -I.  */
134959995Selan   /* There seems to be confusion about what CPATH should do,
135059995Selan      so for the moment it is not documented.  */
135159995Selan   /* Some people say that CPATH should replace the standard include dirs,
135259995Selan      but that seems pointless: it comes before them, so it overrides them
135359995Selan      anyway.  */
135459995Selan   p = (char *) getenv ("CPATH");
135559995Selan   if (p != 0 && ! no_standard_includes)
135659995Selan     path_include (p);
135759995Selan 
135859995Selan   /* Now that dollars_in_ident is known, initialize is_idchar.  */
135959995Selan   initialize_char_syntax ();
136059995Selan 
136159995Selan   /* Initialize output buffer */
136259995Selan 
136359995Selan   outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
136459995Selan   outbuf.bufp = outbuf.buf;
136559995Selan   outbuf.length = OUTBUF_SIZE;
136659995Selan 
136759995Selan   /* Do partial setup of input buffer for the sake of generating
136859995Selan      early #line directives (when -g is in effect).  */
136959995Selan 
137059995Selan   fp = &instack[++indepth];
137159995Selan   if (in_fname == NULL)
137259995Selan     in_fname = "";
137359995Selan   fp->nominal_fname = fp->fname = in_fname;
137459995Selan   fp->lineno = 0;
137559995Selan 
137659995Selan   /* Install __LINE__, etc.  Must follow initialize_char_syntax
137759995Selan      and option processing.  */
137859995Selan   initialize_builtins (fp, &outbuf);
137959995Selan 
138059995Selan   /* Do standard #defines and assertions
138159995Selan      that identify system and machine type.  */
138259995Selan 
138359995Selan   if (!inhibit_predefs) {
138459995Selan     char *p = (char *) alloca (strlen (predefs) + 1);
138559995Selan     strcpy (p, predefs);
138659995Selan     while (*p) {
138759995Selan       char *q;
138859995Selan       while (*p == ' ' || *p == '\t')
138959995Selan 	p++;
139059995Selan       /* Handle -D options.  */
139159995Selan       if (p[0] == '-' && p[1] == 'D') {
139259995Selan 	q = &p[2];
139359995Selan 	while (*p && *p != ' ' && *p != '\t')
139459995Selan 	  p++;
139559995Selan 	if (*p != 0)
139659995Selan 	  *p++= 0;
139759995Selan 	if (debug_output)
139859995Selan 	  output_line_command (fp, &outbuf, 0, same_file);
139959995Selan 	make_definition (q, &outbuf);
140059995Selan 	while (*p == ' ' || *p == '\t')
140159995Selan 	  p++;
140259995Selan       } else if (p[0] == '-' && p[1] == 'A') {
140359995Selan 	/* Handle -A options (assertions).  */
140459995Selan 	char *assertion;
140559995Selan 	char *past_name;
140659995Selan 	char *value;
140759995Selan 	char *past_value;
140859995Selan 	char *termination;
140959995Selan 	int save_char;
141059995Selan 
141159995Selan 	assertion = &p[2];
141259995Selan 	past_name = assertion;
141359995Selan 	/* Locate end of name.  */
141459995Selan 	while (*past_name && *past_name != ' '
141559995Selan 	       && *past_name != '\t' && *past_name != '(')
141659995Selan 	  past_name++;
141759995Selan 	/* Locate `(' at start of value.  */
141859995Selan 	value = past_name;
141959995Selan 	while (*value && (*value == ' ' || *value == '\t'))
142059995Selan 	  value++;
142159995Selan 	if (*value++ != '(')
142259995Selan 	  abort ();
142359995Selan 	while (*value && (*value == ' ' || *value == '\t'))
142459995Selan 	  value++;
142559995Selan 	past_value = value;
142659995Selan 	/* Locate end of value.  */
142759995Selan 	while (*past_value && *past_value != ' '
142859995Selan 	       && *past_value != '\t' && *past_value != ')')
142959995Selan 	  past_value++;
143059995Selan 	termination = past_value;
143159995Selan 	while (*termination && (*termination == ' ' || *termination == '\t'))
143259995Selan 	  termination++;
143359995Selan 	if (*termination++ != ')')
143459995Selan 	  abort ();
143559995Selan 	if (*termination && *termination != ' ' && *termination != '\t')
143659995Selan 	  abort ();
143759995Selan 	/* Temporarily null-terminate the value.  */
143859995Selan 	save_char = *termination;
143959995Selan 	*termination = '\0';
144059995Selan 	/* Install the assertion.  */
144159995Selan 	make_assertion ("-A", assertion);
144259995Selan 	*termination = (char) save_char;
144359995Selan 	p = termination;
144459995Selan 	while (*p == ' ' || *p == '\t')
144559995Selan 	  p++;
144659995Selan       } else {
144759995Selan 	abort ();
144859995Selan       }
144959995Selan     }
145059995Selan   }
145159995Selan 
145259995Selan   /* Now handle the command line options.  */
145359995Selan 
145459995Selan   /* Do -U's, -D's and -A's in the order they were seen.  */
145559995Selan   for (i = 1; i < argc; i++) {
145659995Selan     if (pend_undefs[i]) {
145759995Selan       if (debug_output)
145859995Selan         output_line_command (fp, &outbuf, 0, same_file);
145959995Selan       make_undef (pend_undefs[i], &outbuf);
146059995Selan     }
146159995Selan     if (pend_defs[i]) {
146259995Selan       if (debug_output)
146359995Selan         output_line_command (fp, &outbuf, 0, same_file);
146459995Selan       make_definition (pend_defs[i], &outbuf);
146559995Selan     }
146659995Selan     if (pend_assertions[i])
146759995Selan       make_assertion (pend_assertion_options[i], pend_assertions[i]);
146859995Selan   }
146959995Selan 
147059995Selan   done_initializing = 1;
147159995Selan 
147259995Selan   { /* read the appropriate environment variable and if it exists
147359995Selan        replace include_defaults with the listed path. */
147459995Selan     char *epath = 0;
147559995Selan     switch ((objc << 1) + cplusplus)
147659995Selan       {
147759995Selan       case 0:
147859995Selan 	epath = getenv ("C_INCLUDE_PATH");
147959995Selan 	break;
148059995Selan       case 1:
148159995Selan 	epath = getenv ("CPLUS_INCLUDE_PATH");
148259995Selan 	break;
148359995Selan       case 2:
148459995Selan 	epath = getenv ("OBJC_INCLUDE_PATH");
148559995Selan 	break;
148659995Selan       case 3:
148759995Selan 	epath = getenv ("OBJCPLUS_INCLUDE_PATH");
148859995Selan 	break;
148959995Selan       }
149059995Selan     /* If the environment var for this language is set,
149159995Selan        add to the default list of include directories.  */
149259995Selan     if (epath) {
149359995Selan       char *nstore = (char *) alloca (strlen (epath) + 2);
149459995Selan       int num_dirs;
149559995Selan       char *startp, *endp;
149659995Selan 
149759995Selan       for (num_dirs = 1, startp = epath; *startp; startp++)
149859995Selan 	if (*startp == PATH_SEPARATOR)
149959995Selan 	  num_dirs++;
150059995Selan       include_defaults
150159995Selan 	= (struct default_include *) xmalloc ((num_dirs
150259995Selan 					       * sizeof (struct default_include))
150359995Selan 					      + sizeof (include_defaults_array));
150459995Selan       startp = endp = epath;
150559995Selan       num_dirs = 0;
150659995Selan       while (1) {
150759995Selan         /* Handle cases like c:/usr/lib:d:/gcc/lib */
150859995Selan         if ((*endp == PATH_SEPARATOR
150959995Selan #if 0 /* Obsolete, now that we use semicolons as the path separator.  */
151059995Selan #ifdef __MSDOS__
151159995Selan 	     && (endp-startp != 1 || !isalpha (*startp))
151259995Selan #endif
151359995Selan #endif
151459995Selan 	     )
151559995Selan             || *endp == 0) {
151659995Selan 	  strncpy (nstore, startp, endp-startp);
151759995Selan 	  if (endp == startp)
151859995Selan 	    strcpy (nstore, ".");
151959995Selan 	  else
152059995Selan 	    nstore[endp-startp] = '\0';
152159995Selan 
152259995Selan 	  include_defaults[num_dirs].fname = savestring (nstore);
152359995Selan 	  include_defaults[num_dirs].cplusplus = cplusplus;
152459995Selan 	  num_dirs++;
152559995Selan 	  if (*endp == '\0')
152659995Selan 	    break;
152759995Selan 	  endp = startp = endp + 1;
152859995Selan 	} else
152959995Selan 	  endp++;
153059995Selan       }
153159995Selan       /* Put the usual defaults back in at the end.  */
153259995Selan       bcopy (include_defaults_array, &include_defaults[num_dirs],
153359995Selan 	     sizeof (include_defaults_array));
153459995Selan     }
153559995Selan   }
153659995Selan 
153759995Selan   first_system_include = 0;
153859995Selan   /* Unless -fnostdinc,
153959995Selan      tack on the standard include file dirs to the specified list */
154059995Selan   if (!no_standard_includes) {
154159995Selan     struct default_include *p = include_defaults;
154259995Selan     char *specd_prefix = include_prefix;
154359995Selan     char *default_prefix = savestring (GCC_INCLUDE_DIR);
154459995Selan     int default_len = 0;
154559995Selan     /* Remove the `include' from /usr/local/lib/gcc.../include.  */
154659995Selan     if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) {
154759995Selan       default_len = strlen (default_prefix) - 7;
154859995Selan       default_prefix[default_len] = 0;
154959995Selan     }
155059995Selan     /* Search "translated" versions of GNU directories.
155159995Selan        These have /usr/local/lib/gcc... replaced by specd_prefix.  */
155259995Selan     if (specd_prefix != 0 && default_len != 0)
155359995Selan       for (p = include_defaults; p->fname; p++) {
155459995Selan 	/* Some standard dirs are only for C++.  */
155559995Selan 	if (!p->cplusplus || (cplusplus && !no_standard_cplusplus_includes)) {
155659995Selan 	  /* Does this dir start with the prefix?  */
155759995Selan 	  if (!strncmp (p->fname, default_prefix, default_len)) {
155859995Selan 	    /* Yes; change prefix and add to search list.  */
155959995Selan 	    struct file_name_list *new
156059995Selan 	      = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
156159995Selan 	    int this_len = strlen (specd_prefix) + strlen (p->fname) - default_len;
156259995Selan 	    char *str = (char *) xmalloc (this_len + 1);
156359995Selan 	    strcpy (str, specd_prefix);
156459995Selan 	    strcat (str, p->fname + default_len);
156559995Selan 	    new->fname = str;
156659995Selan 	    new->control_macro = 0;
156759995Selan 	    append_include_chain (new, new);
156859995Selan 	    if (first_system_include == 0)
156959995Selan 	      first_system_include = new;
157059995Selan 	  }
157159995Selan 	}
157259995Selan       }
157359995Selan     /* Search ordinary names for GNU include directories.  */
157459995Selan     for (p = include_defaults; p->fname; p++) {
157559995Selan       /* Some standard dirs are only for C++.  */
157659995Selan       if (!p->cplusplus || (cplusplus && !no_standard_cplusplus_includes)) {
157759995Selan 	struct file_name_list *new
157859995Selan 	  = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
157959995Selan 	new->control_macro = 0;
158059995Selan 	new->fname = p->fname;
158159995Selan 	append_include_chain (new, new);
158259995Selan 	if (first_system_include == 0)
158359995Selan 	  first_system_include = new;
158459995Selan       }
158559995Selan     }
158659995Selan   }
158759995Selan 
158859995Selan   /* Tack the after_include chain at the end of the include chain.  */
158959995Selan   append_include_chain (after_include, last_after_include);
159059995Selan   if (first_system_include == 0)
159159995Selan     first_system_include = after_include;
159259995Selan 
159359995Selan   /* Scan the -imacros files before the main input.
159459995Selan      Much like #including them, but with no_output set
159559995Selan      so that only their macro definitions matter.  */
159659995Selan 
159759995Selan   no_output++;
159859995Selan   for (i = 1; i < argc; i++)
159959995Selan     if (pend_files[i]) {
160059995Selan       int fd = open (pend_files[i], O_RDONLY, 0666);
160159995Selan       if (fd < 0) {
160259995Selan 	perror_with_name (pend_files[i]);
160359995Selan 	return FAILURE_EXIT_CODE;
160459995Selan       }
160559995Selan       finclude (fd, pend_files[i], &outbuf, 0, NULL_PTR);
160659995Selan     }
160759995Selan   no_output--;
160859995Selan 
160959995Selan   /* Copy the entire contents of the main input file into
161059995Selan      the stacked input buffer previously allocated for it.  */
161159995Selan 
161259995Selan   /* JF check for stdin */
161359995Selan   if (in_fname == NULL || *in_fname == 0) {
161459995Selan     in_fname = "";
161559995Selan     f = 0;
161659995Selan   } else if ((f = open (in_fname, O_RDONLY, 0666)) < 0)
161759995Selan     goto perror;
161859995Selan 
161959995Selan   /* Either of two environment variables can specify output of deps.
162059995Selan      Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET",
162159995Selan      where OUTPUT_FILE is the file to write deps info to
162259995Selan      and DEPS_TARGET is the target to mention in the deps.  */
162359995Selan 
162459995Selan   if (print_deps == 0
162559995Selan       && (getenv ("SUNPRO_DEPENDENCIES") != 0
162659995Selan 	  || getenv ("DEPENDENCIES_OUTPUT") != 0)) {
162759995Selan     char *spec = getenv ("DEPENDENCIES_OUTPUT");
162859995Selan     char *s;
162959995Selan     char *output_file;
163059995Selan 
163159995Selan     if (spec == 0) {
163259995Selan       spec = getenv ("SUNPRO_DEPENDENCIES");
163359995Selan       print_deps = 2;
163459995Selan     }
163559995Selan     else
163659995Selan       print_deps = 1;
163759995Selan 
163859995Selan     s = spec;
163959995Selan     /* Find the space before the DEPS_TARGET, if there is one.  */
164059995Selan     /* This should use index.  (mrs) */
164159995Selan     while (*s != 0 && *s != ' ') s++;
164259995Selan     if (*s != 0) {
164359995Selan       deps_target = s + 1;
164459995Selan       output_file = (char *) xmalloc (s - spec + 1);
164559995Selan       bcopy (spec, output_file, s - spec);
164659995Selan       output_file[s - spec] = 0;
164759995Selan     }
164859995Selan     else {
164959995Selan       deps_target = 0;
165059995Selan       output_file = spec;
165159995Selan     }
165259995Selan 
165359995Selan     deps_file = output_file;
165459995Selan   }
165559995Selan 
165659995Selan   /* For -M, print the expected object file name
165759995Selan      as the target of this Make-rule.  */
165859995Selan   if (print_deps) {
165959995Selan     deps_allocated_size = 200;
166059995Selan     deps_buffer = (char *) xmalloc (deps_allocated_size);
166159995Selan     deps_buffer[0] = 0;
166259995Selan     deps_size = 0;
166359995Selan     deps_column = 0;
166459995Selan 
166559995Selan     if (deps_target) {
166659995Selan       deps_output (deps_target, 0);
166759995Selan       deps_output (":", 0);
166859995Selan     } else if (*in_fname == 0)
166959995Selan       deps_output ("-: ", 0);
167059995Selan     else {
167159995Selan       int len;
167259995Selan       char *p = in_fname;
167359995Selan       char *p1 = p;
167459995Selan       /* Discard all directory prefixes from P.  */
167559995Selan       while (*p1) {
167659995Selan 	if (*p1 == '/')
167759995Selan 	  p = p1 + 1;
167859995Selan 	p1++;
167959995Selan       }
168059995Selan       /* Output P, but remove known suffixes.  */
168159995Selan       len = strlen (p);
168259995Selan       if (p[len - 2] == '.' && p[len - 1] == 'c')
168359995Selan 	deps_output (p, len - 2);
168459995Selan       else if (p[len - 2] == '.' && p[len - 1] == 'C')
168559995Selan 	deps_output (p, len - 2);
168659995Selan       else if (p[len - 3] == '.'
168759995Selan 	       && p[len - 2] == 'c'
168859995Selan 	       && p[len - 1] == 'c')
168959995Selan 	deps_output (p, len - 3);
169059995Selan       else if (p[len - 2] == '.' && p[len - 1] == 's')
169159995Selan 	deps_output (p, len - 2);
169259995Selan       else if (p[len - 2] == '.' && p[len - 1] == 'S')
169359995Selan 	deps_output (p, len - 2);
169459995Selan       else if (p[len - 2] == '.' && p[len - 1] == 'm')
169559995Selan 	deps_output (p, len - 2);
169659995Selan       else
169759995Selan 	deps_output (p, 0);
169859995Selan       /* Supply our own suffix.  */
169959995Selan #ifndef VMS
170059995Selan       deps_output (".o : ", 0);
170159995Selan #else
170259995Selan       deps_output (".obj : ", 0);
170359995Selan #endif
170459995Selan       deps_output (in_fname, 0);
170559995Selan       deps_output (" ", 0);
170659995Selan     }
170759995Selan   }
170859995Selan 
170959995Selan   file_size_and_mode (f, &st_mode, &st_size);
171059995Selan   fp->nominal_fname = fp->fname = in_fname;
171159995Selan   fp->lineno = 1;
171259995Selan   fp->system_header_p = 0;
171359995Selan   /* JF all this is mine about reading pipes and ttys */
171459995Selan   if (! S_ISREG (st_mode)) {
171559995Selan     /* Read input from a file that is not a normal disk file.
171659995Selan        We cannot preallocate a buffer with the correct size,
171759995Selan        so we must read in the file a piece at the time and make it bigger.  */
171859995Selan     int size;
171959995Selan     int bsize;
172059995Selan     int cnt;
172159995Selan     U_CHAR *bufp;
172259995Selan 
172359995Selan     bsize = 2000;
172459995Selan     size = 0;
172559995Selan     fp->buf = (U_CHAR *) xmalloc (bsize + 2);
172659995Selan     bufp = fp->buf;
172759995Selan     for (;;) {
172859995Selan       cnt = read (f, bufp, bsize - size);
172959995Selan       if (cnt < 0) goto perror;	/* error! */
173059995Selan       if (cnt == 0) break;	/* End of file */
173159995Selan       size += cnt;
173259995Selan       bufp += cnt;
173359995Selan       if (bsize == size) {	/* Buffer is full! */
173459995Selan         bsize *= 2;
173559995Selan         fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
173659995Selan 	bufp = fp->buf + size;	/* May have moved */
173759995Selan       }
173859995Selan     }
173959995Selan     fp->length = size;
174059995Selan   } else {
174159995Selan     /* Read a file whose size we can determine in advance.
174259995Selan        For the sake of VMS, st_size is just an upper bound.  */
174359995Selan     long i;
174459995Selan     fp->length = 0;
174559995Selan     fp->buf = (U_CHAR *) xmalloc (st_size + 2);
174659995Selan 
174759995Selan     while (st_size > 0) {
174859995Selan       i = read (f, fp->buf + fp->length, st_size);
174959995Selan       if (i <= 0) {
175059995Selan         if (i == 0) break;
175159995Selan 	goto perror;
175259995Selan       }
175359995Selan       fp->length += i;
175459995Selan       st_size -= i;
175559995Selan     }
175659995Selan   }
175759995Selan   fp->bufp = fp->buf;
175859995Selan   fp->if_stack = if_stack;
175959995Selan 
176059995Selan   /* Make sure data ends with a newline.  And put a null after it.  */
176159995Selan 
176259995Selan   if ((fp->length > 0 && fp->buf[fp->length - 1] != '\n')
176359995Selan       /* Backslash-newline at end is not good enough.  */
176459995Selan       || (fp->length > 1 && fp->buf[fp->length - 2] == '\\')) {
176559995Selan     fp->buf[fp->length++] = '\n';
176659995Selan     missing_newline = 1;
176759995Selan   }
176859995Selan   fp->buf[fp->length] = '\0';
176959995Selan 
177059995Selan   /* Unless inhibited, convert trigraphs in the input.  */
177159995Selan 
177259995Selan   if (!no_trigraphs)
177359995Selan     trigraph_pcp (fp);
177459995Selan 
177559995Selan   /* Now that we know the input file is valid, open the output.  */
177659995Selan 
177759995Selan   if (!out_fname || !strcmp (out_fname, ""))
177859995Selan     out_fname = "stdout";
177959995Selan   else if (! freopen (out_fname, "w", stdout))
178059995Selan     pfatal_with_name (out_fname);
178159995Selan 
178259995Selan   output_line_command (fp, &outbuf, 0, same_file);
178359995Selan 
178459995Selan   /* Scan the -include files before the main input.  */
178559995Selan 
178659995Selan   for (i = 1; i < argc; i++)
178759995Selan     if (pend_includes[i]) {
178859995Selan       int fd = open (pend_includes[i], O_RDONLY, 0666);
178959995Selan       if (fd < 0) {
179059995Selan 	perror_with_name (pend_includes[i]);
179159995Selan 	return FAILURE_EXIT_CODE;
179259995Selan       }
179359995Selan       finclude (fd, pend_includes[i], &outbuf, 0, NULL_PTR);
179459995Selan     }
179559995Selan 
179659995Selan   /* Scan the input, processing macros and directives.  */
179759995Selan 
179859995Selan   rescan (&outbuf, 0);
179959995Selan 
180059995Selan   if (pedantic && missing_newline)
180159995Selan     pedwarn ("file does not end in newline");
180259995Selan 
180359995Selan   /* Now we have processed the entire input
180459995Selan      Write whichever kind of output has been requested.  */
180559995Selan 
180659995Selan   if (dump_macros == dump_only)
180759995Selan     dump_all_macros ();
180859995Selan   else if (! inhibit_output) {
180959995Selan     write_output ();
181059995Selan   }
181159995Selan 
181259995Selan   if (print_deps) {
181359995Selan     /* Don't actually write the deps file if compilation has failed.  */
181459995Selan     if (errors == 0) {
181559995Selan       if (deps_file && ! (deps_stream = fopen (deps_file, "a")))
181659995Selan 	pfatal_with_name (deps_file);
181759995Selan       fputs (deps_buffer, deps_stream);
181859995Selan       putc ('\n', deps_stream);
181959995Selan       if (deps_file) {
182059995Selan 	if (ferror (deps_stream) || fclose (deps_stream) != 0)
182159995Selan 	  fatal ("I/O error on output");
182259995Selan       }
182359995Selan     }
182459995Selan   }
182559995Selan 
182659995Selan   if (ferror (stdout) || fclose (stdout) != 0)
182759995Selan     fatal ("I/O error on output");
182859995Selan 
182959995Selan   if (errors)
183059995Selan     exit (FAILURE_EXIT_CODE);
183159995Selan   exit (SUCCESS_EXIT_CODE);
183259995Selan 
183359995Selan  perror:
183459995Selan   pfatal_with_name (in_fname);
183559995Selan   return 0;
183659995Selan }
183759995Selan 
183859995Selan /* Given a colon-separated list of file names PATH,
183959995Selan    add all the names to the search path for include files.  */
184059995Selan 
184159995Selan static void
path_include(path)184259995Selan path_include (path)
184359995Selan      char *path;
184459995Selan {
184559995Selan   char *p;
184659995Selan 
184759995Selan   p = path;
184859995Selan 
184959995Selan   if (*p)
185059995Selan     while (1) {
185159995Selan       char *q = p;
185259995Selan       char *name;
185359995Selan       struct file_name_list *dirtmp;
185459995Selan 
185559995Selan       /* Find the end of this name.  */
185659995Selan       while (*q != 0 && *q != PATH_SEPARATOR) q++;
185759995Selan       if (p == q) {
185859995Selan 	/* An empty name in the path stands for the current directory.  */
185959995Selan 	name = (char *) xmalloc (2);
186059995Selan 	name[0] = '.';
186159995Selan 	name[1] = 0;
186259995Selan       } else {
186359995Selan 	/* Otherwise use the directory that is named.  */
186459995Selan 	name = (char *) xmalloc (q - p + 1);
186559995Selan 	bcopy (p, name, q - p);
186659995Selan 	name[q - p] = 0;
186759995Selan       }
186859995Selan 
186959995Selan       dirtmp = (struct file_name_list *)
187059995Selan 	xmalloc (sizeof (struct file_name_list));
187159995Selan       dirtmp->next = 0;		/* New one goes on the end */
187259995Selan       dirtmp->control_macro = 0;
187359995Selan       dirtmp->fname = name;
187459995Selan       append_include_chain (dirtmp, dirtmp);
187559995Selan 
187659995Selan       /* Advance past this name.  */
187759995Selan       p = q;
187859995Selan       if (*p == 0)
187959995Selan 	break;
188059995Selan       /* Skip the colon.  */
188159995Selan       p++;
188259995Selan     }
188359995Selan }
188459995Selan 
188559995Selan /* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF
188659995Selan    before main CCCP processing.  Name `pcp' is also in honor of the
188759995Selan    drugs the trigraph designers must have been on.
188859995Selan 
188959995Selan    Using an extra pass through the buffer takes a little extra time,
189059995Selan    but is infinitely less hairy than trying to handle trigraphs inside
189159995Selan    strings, etc. everywhere, and also makes sure that trigraphs are
189259995Selan    only translated in the top level of processing. */
189359995Selan 
189459995Selan static void
trigraph_pcp(buf)189559995Selan trigraph_pcp (buf)
189659995Selan      FILE_BUF *buf;
189759995Selan {
189859995Selan   register U_CHAR c, *fptr, *bptr, *sptr;
189959995Selan   int len;
190059995Selan 
190159995Selan   fptr = bptr = sptr = buf->buf;
190259995Selan   while ((sptr = (U_CHAR *) index (sptr, '?')) != NULL) {
190359995Selan     if (*++sptr != '?')
190459995Selan       continue;
190559995Selan     switch (*++sptr) {
190659995Selan       case '=':
190759995Selan       c = '#';
190859995Selan       break;
190959995Selan     case '(':
191059995Selan       c = '[';
191159995Selan       break;
191259995Selan     case '/':
191359995Selan       c = '\\';
191459995Selan       break;
191559995Selan     case ')':
191659995Selan       c = ']';
191759995Selan       break;
191859995Selan     case '\'':
191959995Selan       c = '^';
192059995Selan       break;
192159995Selan     case '<':
192259995Selan       c = '{';
192359995Selan       break;
192459995Selan     case '!':
192559995Selan       c = '|';
192659995Selan       break;
192759995Selan     case '>':
192859995Selan       c = '}';
192959995Selan       break;
193059995Selan     case '-':
193159995Selan       c  = '~';
193259995Selan       break;
193359995Selan     case '?':
193459995Selan       sptr--;
193559995Selan       continue;
193659995Selan     default:
193759995Selan       continue;
193859995Selan     }
193959995Selan     len = sptr - fptr - 2;
194059995Selan     if (bptr != fptr && len > 0)
194159995Selan       bcopy (fptr, bptr, len);	/* BSD doc says bcopy () works right
194259995Selan 				   for overlapping strings.  In ANSI
194359995Selan 				   C, this will be memmove (). */
194459995Selan     bptr += len;
194559995Selan     *bptr++ = c;
194659995Selan     fptr = ++sptr;
194759995Selan   }
194859995Selan   len = buf->length - (fptr - buf->buf);
194959995Selan   if (bptr != fptr && len > 0)
195059995Selan     bcopy (fptr, bptr, len);
195159995Selan   buf->length -= fptr - bptr;
195259995Selan   buf->buf[buf->length] = '\0';
195359995Selan   if (warn_trigraphs && fptr != bptr)
195459995Selan     warning ("%d trigraph(s) encountered", (fptr - bptr) / 2);
195559995Selan }
195659995Selan 
195759995Selan /* Move all backslash-newline pairs out of embarrassing places.
195859995Selan    Exchange all such pairs following BP
195959995Selan    with any potentially-embarrassing characters that follow them.
196059995Selan    Potentially-embarrassing characters are / and *
196159995Selan    (because a backslash-newline inside a comment delimiter
196259995Selan    would cause it not to be recognized).  */
196359995Selan 
196459995Selan static void
newline_fix(bp)196559995Selan newline_fix (bp)
196659995Selan      U_CHAR *bp;
196759995Selan {
196859995Selan   register U_CHAR *p = bp;
196959995Selan   register int count = 0;
197059995Selan 
197159995Selan   /* First count the backslash-newline pairs here.  */
197259995Selan 
197359995Selan   while (1) {
197459995Selan     if (p[0] == '\\') {
197559995Selan       if (p[1] == '\n')
197659995Selan 	p += 2, count++;
197759995Selan       else if (p[1] == '\r' && p[2] == '\n')
197859995Selan 	p += 3, count++;
197959995Selan       else
198059995Selan 	break;
198159995Selan     } else
198259995Selan       break;
198359995Selan   }
198459995Selan 
198559995Selan   /* What follows the backslash-newlines is not embarrassing.  */
198659995Selan 
198759995Selan   if (count == 0 || (*p != '/' && *p != '*'))
198859995Selan     return;
198959995Selan 
199059995Selan   /* Copy all potentially embarrassing characters
199159995Selan      that follow the backslash-newline pairs
199259995Selan      down to where the pairs originally started.  */
199359995Selan 
199459995Selan   while (*p == '*' || *p == '/')
199559995Selan     *bp++ = *p++;
199659995Selan 
199759995Selan   /* Now write the same number of pairs after the embarrassing chars.  */
199859995Selan   while (count-- > 0) {
199959995Selan     *bp++ = '\\';
200059995Selan     *bp++ = '\n';
200159995Selan   }
200259995Selan }
200359995Selan 
200459995Selan /* Like newline_fix but for use within a directive-name.
200559995Selan    Move any backslash-newlines up past any following symbol constituents.  */
200659995Selan 
200759995Selan static void
name_newline_fix(bp)200859995Selan name_newline_fix (bp)
200959995Selan      U_CHAR *bp;
201059995Selan {
201159995Selan   register U_CHAR *p = bp;
201259995Selan   register int count = 0;
201359995Selan 
201459995Selan   /* First count the backslash-newline pairs here.  */
201559995Selan   while (1) {
201659995Selan     if (p[0] == '\\') {
201759995Selan       if (p[1] == '\n')
201859995Selan 	p += 2, count++;
201959995Selan       else if (p[1] == '\r' && p[2] == '\n')
202059995Selan 	p += 3, count++;
202159995Selan       else
202259995Selan 	break;
202359995Selan     } else
202459995Selan       break;
202559995Selan   }
202659995Selan 
202759995Selan   /* What follows the backslash-newlines is not embarrassing.  */
202859995Selan 
202959995Selan   if (count == 0 || !is_idchar[*p])
203059995Selan     return;
203159995Selan 
203259995Selan   /* Copy all potentially embarrassing characters
203359995Selan      that follow the backslash-newline pairs
203459995Selan      down to where the pairs originally started.  */
203559995Selan 
203659995Selan   while (is_idchar[*p])
203759995Selan     *bp++ = *p++;
203859995Selan 
203959995Selan   /* Now write the same number of pairs after the embarrassing chars.  */
204059995Selan   while (count-- > 0) {
204159995Selan     *bp++ = '\\';
204259995Selan     *bp++ = '\n';
204359995Selan   }
204459995Selan }
204559995Selan 
204659995Selan /* Look for lint commands in comments.
204759995Selan 
204859995Selan    When we come in here, ibp points into a comment.  Limit is as one expects.
204959995Selan    scan within the comment -- it should start, after lwsp, with a lint command.
205059995Selan    If so that command is returned as a (constant) string.
205159995Selan 
205259995Selan    Upon return, any arg will be pointed to with argstart and will be
205359995Selan    arglen long.  Note that we don't parse that arg since it will just
205459995Selan    be printed out again.
205559995Selan */
205659995Selan 
205759995Selan static char *
get_lintcmd(ibp,limit,argstart,arglen,cmdlen)205859995Selan get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
205959995Selan      register U_CHAR *ibp;
206059995Selan      register U_CHAR *limit;
206159995Selan      U_CHAR **argstart;		/* point to command arg */
206259995Selan      int *arglen, *cmdlen;	/* how long they are */
206359995Selan {
206459995Selan   long linsize;
206559995Selan   register U_CHAR *numptr;	/* temp for arg parsing */
206659995Selan 
206759995Selan   *arglen = 0;
206859995Selan 
206959995Selan   SKIP_WHITE_SPACE (ibp);
207059995Selan 
207159995Selan   if (ibp >= limit) return NULL;
207259995Selan 
207359995Selan   linsize = limit - ibp;
207459995Selan 
207559995Selan   /* Oh, I wish C had lexical functions... hell, I'll just open-code the set */
207659995Selan   if ((linsize >= 10) && !strncmp (ibp, "NOTREACHED", 10)) {
207759995Selan     *cmdlen = 10;
207859995Selan     return "NOTREACHED";
207959995Selan   }
208059995Selan   if ((linsize >= 8) && !strncmp (ibp, "ARGSUSED", 8)) {
208159995Selan     *cmdlen = 8;
208259995Selan     return "ARGSUSED";
208359995Selan   }
208459995Selan   if ((linsize >= 11) && !strncmp (ibp, "LINTLIBRARY", 11)) {
208559995Selan     *cmdlen = 11;
208659995Selan     return "LINTLIBRARY";
208759995Selan   }
208859995Selan   if ((linsize >= 7) && !strncmp (ibp, "VARARGS", 7)) {
208959995Selan     *cmdlen = 7;
209059995Selan     ibp += 7; linsize -= 7;
209159995Selan     if ((linsize == 0) || ! isdigit (*ibp)) return "VARARGS";
209259995Selan 
209359995Selan     /* OK, read a number */
209459995Selan     for (numptr = *argstart = ibp; (numptr < limit) && isdigit (*numptr);
209559995Selan 	 numptr++);
209659995Selan     *arglen = numptr - *argstart;
209759995Selan     return "VARARGS";
209859995Selan   }
209959995Selan   return NULL;
210059995Selan }
210159995Selan 
210259995Selan /*
210359995Selan  * The main loop of the program.
210459995Selan  *
210559995Selan  * Read characters from the input stack, transferring them to the
210659995Selan  * output buffer OP.
210759995Selan  *
210859995Selan  * Macros are expanded and push levels on the input stack.
210959995Selan  * At the end of such a level it is popped off and we keep reading.
211059995Selan  * At the end of any other kind of level, we return.
211159995Selan  * #-directives are handled, except within macros.
211259995Selan  *
211359995Selan  * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input
211459995Selan  * and insert them when appropriate.  This is set while scanning macro
211559995Selan  * arguments before substitution.  It is zero when scanning for final output.
211659995Selan  *   There are three types of Newline markers:
211759995Selan  *   * Newline -  follows a macro name that was not expanded
211859995Selan  *     because it appeared inside an expansion of the same macro.
211959995Selan  *     This marker prevents future expansion of that identifier.
212059995Selan  *     When the input is rescanned into the final output, these are deleted.
212159995Selan  *     These are also deleted by ## concatenation.
212259995Selan  *   * Newline Space (or Newline and any other whitespace character)
212359995Selan  *     stands for a place that tokens must be separated or whitespace
212459995Selan  *     is otherwise desirable, but where the ANSI standard specifies there
212559995Selan  *     is no whitespace.  This marker turns into a Space (or whichever other
212659995Selan  *     whitespace char appears in the marker) in the final output,
212759995Selan  *     but it turns into nothing in an argument that is stringified with #.
212859995Selan  *     Such stringified arguments are the only place where the ANSI standard
212959995Selan  *     specifies with precision that whitespace may not appear.
213059995Selan  *
213159995Selan  * During this function, IP->bufp is kept cached in IBP for speed of access.
213259995Selan  * Likewise, OP->bufp is kept in OBP.  Before calling a subroutine
213359995Selan  * IBP, IP and OBP must be copied back to memory.  IP and IBP are
213459995Selan  * copied back with the RECACHE macro.  OBP must be copied back from OP->bufp
213559995Selan  * explicitly, and before RECACHE, since RECACHE uses OBP.
213659995Selan  */
213759995Selan 
213859995Selan static void
rescan(op,output_marks)213959995Selan rescan (op, output_marks)
214059995Selan      FILE_BUF *op;
214159995Selan      int output_marks;
214259995Selan {
214359995Selan   /* Character being scanned in main loop.  */
214459995Selan   register U_CHAR c;
214559995Selan 
214659995Selan   /* Length of pending accumulated identifier.  */
214759995Selan   register int ident_length = 0;
214859995Selan 
214959995Selan   /* Hash code of pending accumulated identifier.  */
215059995Selan   register int hash = 0;
215159995Selan 
215259995Selan   /* Current input level (&instack[indepth]).  */
215359995Selan   FILE_BUF *ip;
215459995Selan 
215559995Selan   /* Pointer for scanning input.  */
215659995Selan   register U_CHAR *ibp;
215759995Selan 
215859995Selan   /* Pointer to end of input.  End of scan is controlled by LIMIT.  */
215959995Selan   register U_CHAR *limit;
216059995Selan 
216159995Selan   /* Pointer for storing output.  */
216259995Selan   register U_CHAR *obp;
216359995Selan 
216459995Selan   /* REDO_CHAR is nonzero if we are processing an identifier
216559995Selan      after backing up over the terminating character.
216659995Selan      Sometimes we process an identifier without backing up over
216759995Selan      the terminating character, if the terminating character
216859995Selan      is not special.  Backing up is done so that the terminating character
216959995Selan      will be dispatched on again once the identifier is dealt with.  */
217059995Selan   int redo_char = 0;
217159995Selan 
217259995Selan   /* 1 if within an identifier inside of which a concatenation
217359995Selan      marker (Newline -) has been seen.  */
217459995Selan   int concatenated = 0;
217559995Selan 
217659995Selan   /* While scanning a comment or a string constant,
217759995Selan      this records the line it started on, for error messages.  */
217859995Selan   int start_line;
217959995Selan 
218059995Selan   /* Line where a newline was first seen in a string constant.  */
218159995Selan   int multiline_string_line = 0;
218259995Selan 
218359995Selan   /* Record position of last `real' newline.  */
218459995Selan   U_CHAR *beg_of_line;
218559995Selan 
218659995Selan /* Pop the innermost input stack level, assuming it is a macro expansion.  */
218759995Selan 
218859995Selan #define POPMACRO \
218959995Selan do { ip->macro->type = T_MACRO;		\
219059995Selan      if (ip->free_ptr) free (ip->free_ptr);	\
219159995Selan      --indepth; } while (0)
219259995Selan 
219359995Selan /* Reload `rescan's local variables that describe the current
219459995Selan    level of the input stack.  */
219559995Selan 
219659995Selan #define RECACHE  \
219759995Selan do { ip = &instack[indepth];		\
219859995Selan      ibp = ip->bufp;			\
219959995Selan      limit = ip->buf + ip->length;	\
220059995Selan      op->bufp = obp;			\
220159995Selan      check_expand (op, limit - ibp);	\
220259995Selan      beg_of_line = 0;			\
220359995Selan      obp = op->bufp; } while (0)
220459995Selan 
220559995Selan   if (no_output && instack[indepth].fname != 0)
220659995Selan     skip_if_group (&instack[indepth], 1);
220759995Selan 
220859995Selan   obp = op->bufp;
220959995Selan   RECACHE;
221059995Selan 
221159995Selan   beg_of_line = ibp;
221259995Selan 
221359995Selan   /* Our caller must always put a null after the end of
221459995Selan      the input at each input stack level.  */
221559995Selan   if (*limit != 0)
221659995Selan     abort ();
221759995Selan 
221859995Selan   while (1) {
221959995Selan     c = *ibp++;
222059995Selan     *obp++ = c;
222159995Selan 
222259995Selan     switch (c) {
222359995Selan     case '\\':
222459995Selan       if (ibp >= limit)
222559995Selan 	break;
222659995Selan       if (*ibp == '\n') {
222759995Selan 	/* Always merge lines ending with backslash-newline,
222859995Selan 	   even in middle of identifier.  */
222959995Selan 	++ibp;
223059995Selan 	++ip->lineno;
223159995Selan 	--obp;		/* remove backslash from obuf */
223259995Selan 	break;
223359995Selan       }
223459995Selan       /* Otherwise, backslash suppresses specialness of following char,
223559995Selan 	 so copy it here to prevent the switch from seeing it.
223659995Selan 	 But first get any pending identifier processed.  */
223759995Selan       if (ident_length > 0)
223859995Selan 	goto specialchar;
223959995Selan       *obp++ = *ibp++;
224059995Selan       break;
224159995Selan 
224259995Selan     case '#':
224359995Selan       if (assertions_flag) {
224459995Selan 	/* Copy #foo (bar lose) without macro expansion.  */
224559995Selan 	SKIP_WHITE_SPACE (ibp);
224659995Selan 	while (is_idchar[*ibp])
224759995Selan 	  *obp++ = *ibp++;
224859995Selan 	SKIP_WHITE_SPACE (ibp);
224959995Selan 	if (*ibp == '(') {
225059995Selan 	  ip->bufp = ibp;
225159995Selan 	  skip_paren_group (ip);
225259995Selan 	  bcopy (ibp, obp, ip->bufp - ibp);
225359995Selan 	  obp += ip->bufp - ibp;
225459995Selan 	  ibp = ip->bufp;
225559995Selan 	}
225659995Selan       }
225759995Selan 
225859995Selan       /* If this is expanding a macro definition, don't recognize
225959995Selan 	 preprocessor directives.  */
226059995Selan       if (ip->macro != 0)
226159995Selan 	goto randomchar;
226259995Selan       /* If this is expand_into_temp_buffer, recognize them
226359995Selan 	 only after an actual newline at this level,
226459995Selan 	 not at the beginning of the input level.  */
226559995Selan       if (ip->fname == 0 && beg_of_line == ip->buf)
226659995Selan 	goto randomchar;
226759995Selan       if (ident_length)
226859995Selan 	goto specialchar;
226959995Selan 
227059995Selan 
227159995Selan       /* # keyword: a # must be first nonblank char on the line */
227259995Selan       if (beg_of_line == 0)
227359995Selan 	goto randomchar;
227459995Selan       {
227559995Selan 	U_CHAR *bp;
227659995Selan 
227759995Selan 	/* Scan from start of line, skipping whitespace, comments
227859995Selan 	   and backslash-newlines, and see if we reach this #.
227959995Selan 	   If not, this # is not special.  */
228059995Selan 	bp = beg_of_line;
228159995Selan 	/* If -traditional, require # to be at beginning of line.  */
228259995Selan 	if (!traditional)
228359995Selan 	  while (1) {
228459995Selan 	    if (is_hor_space[*bp])
228559995Selan 	      bp++;
228659995Selan 	    else if (*bp == '\\' && bp[1] == '\n')
228759995Selan 	      bp += 2;
228859995Selan 	    else if (*bp == '/' && bp[1] == '*') {
228959995Selan 	      bp += 2;
229059995Selan 	      while (!(*bp == '*' && bp[1] == '/'))
229159995Selan 		bp++;
229259995Selan 	      bp += 2;
229359995Selan 	    }
229459995Selan 	    else if (cplusplus_comments && *bp == '/' && bp[1] == '/') {
229559995Selan 	      bp += 2;
229659995Selan 	      while (*bp++ != '\n') ;
229759995Selan 	    }
229859995Selan 	    else break;
229959995Selan 	  }
230059995Selan 	if (bp + 1 != ibp)
230159995Selan 	  goto randomchar;
230259995Selan       }
230359995Selan 
230459995Selan       /* This # can start a directive.  */
230559995Selan 
230659995Selan       --obp;		/* Don't copy the '#' */
230759995Selan 
230859995Selan       ip->bufp = ibp;
230959995Selan       op->bufp = obp;
231059995Selan       if (! handle_directive (ip, op)) {
231159995Selan #ifdef USE_C_ALLOCA
231259995Selan 	alloca (0);
231359995Selan #endif
231459995Selan 	/* Not a known directive: treat it as ordinary text.
231559995Selan 	   IP, OP, IBP, etc. have not been changed.  */
231659995Selan 	if (no_output && instack[indepth].fname) {
231759995Selan 	  /* If not generating expanded output,
231859995Selan 	     what we do with ordinary text is skip it.
231959995Selan 	     Discard everything until next # directive.  */
232059995Selan 	  skip_if_group (&instack[indepth], 1);
232159995Selan 	  RECACHE;
232259995Selan 	  beg_of_line = ibp;
232359995Selan 	  break;
232459995Selan 	}
232559995Selan 	++obp;		/* Copy the '#' after all */
232659995Selan 	goto randomchar;
232759995Selan       }
232859995Selan #ifdef USE_C_ALLOCA
232959995Selan       alloca (0);
233059995Selan #endif
233159995Selan       /* A # directive has been successfully processed.  */
233259995Selan       /* If not generating expanded output, ignore everything until
233359995Selan 	 next # directive.  */
233459995Selan       if (no_output && instack[indepth].fname)
233559995Selan 	skip_if_group (&instack[indepth], 1);
233659995Selan       obp = op->bufp;
233759995Selan       RECACHE;
233859995Selan       beg_of_line = ibp;
233959995Selan       break;
234059995Selan 
234159995Selan     case '\"':			/* skip quoted string */
234259995Selan     case '\'':
234359995Selan       /* A single quoted string is treated like a double -- some
234459995Selan 	 programs (e.g., troff) are perverse this way */
234559995Selan 
234659995Selan       if (ident_length)
234759995Selan 	goto specialchar;
234859995Selan 
234959995Selan       start_line = ip->lineno;
235059995Selan 
235159995Selan       /* Skip ahead to a matching quote.  */
235259995Selan 
235359995Selan       while (1) {
235459995Selan 	if (ibp >= limit) {
235559995Selan 	  if (ip->macro != 0) {
235659995Selan 	    /* try harder: this string crosses a macro expansion boundary.
235759995Selan 	       This can happen naturally if -traditional.
235859995Selan 	       Otherwise, only -D can make a macro with an unmatched quote.  */
235959995Selan 	    POPMACRO;
236059995Selan 	    RECACHE;
236159995Selan 	    continue;
236259995Selan 	  }
236359995Selan 	  if (!traditional) {
236459995Selan 	    error_with_line (line_for_error (start_line),
236559995Selan 			     "unterminated string or character constant");
236659995Selan 	    error_with_line (multiline_string_line,
236759995Selan 			     "possible real start of unterminated constant");
236859995Selan 	    multiline_string_line = 0;
236959995Selan 	  }
237059995Selan 	  break;
237159995Selan 	}
237259995Selan 	*obp++ = *ibp;
237359995Selan 	switch (*ibp++) {
237459995Selan 	case '\n':
237559995Selan 	  ++ip->lineno;
237659995Selan 	  ++op->lineno;
237759995Selan 	  /* Traditionally, end of line ends a string constant with no error.
237859995Selan 	     So exit the loop and record the new line.  */
237959995Selan 	  if (traditional) {
238059995Selan 	    beg_of_line = ibp;
238159995Selan 	    goto while2end;
238259995Selan 	  }
238359995Selan 	  if (pedantic || c == '\'') {
238459995Selan 	    error_with_line (line_for_error (start_line),
238559995Selan 			     "unterminated string or character constant");
238659995Selan 	    goto while2end;
238759995Selan 	  }
238859995Selan 	  if (multiline_string_line == 0)
238959995Selan 	    multiline_string_line = ip->lineno - 1;
239059995Selan 	  break;
239159995Selan 
239259995Selan 	case '\\':
239359995Selan 	  if (ibp >= limit)
239459995Selan 	    break;
239559995Selan 	  if (*ibp == '\n') {
239659995Selan 	    /* Backslash newline is replaced by nothing at all,
239759995Selan 	       but keep the line counts correct.  */
239859995Selan 	    --obp;
239959995Selan 	    ++ibp;
240059995Selan 	    ++ip->lineno;
240159995Selan 	  } else {
240259995Selan 	    /* ANSI stupidly requires that in \\ the second \
240359995Selan 	       is *not* prevented from combining with a newline.  */
240459995Selan 	    while (*ibp == '\\' && ibp[1] == '\n') {
240559995Selan 	      ibp += 2;
240659995Selan 	      ++ip->lineno;
240759995Selan 	    }
240859995Selan 	    *obp++ = *ibp++;
240959995Selan 	  }
241059995Selan 	  break;
241159995Selan 
241259995Selan 	case '\"':
241359995Selan 	case '\'':
241459995Selan 	  if (ibp[-1] == c)
241559995Selan 	    goto while2end;
241659995Selan 	  break;
241759995Selan 	}
241859995Selan       }
241959995Selan     while2end:
242059995Selan       break;
242159995Selan 
242259995Selan     case '/':
242359995Selan       if (*ibp == '\\' && ibp[1] == '\n')
242459995Selan 	newline_fix (ibp);
242559995Selan 
242659995Selan       if (*ibp != '*'
242759995Selan 	  && !(cplusplus_comments && *ibp == '/'))
242859995Selan 	goto randomchar;
242959995Selan       if (ip->macro != 0)
243059995Selan 	goto randomchar;
243159995Selan       if (ident_length)
243259995Selan 	goto specialchar;
243359995Selan 
243459995Selan       if (*ibp == '/') {
243559995Selan 	/* C++ style comment... */
243659995Selan 	start_line = ip->lineno;
243759995Selan 
243859995Selan 	--ibp;			/* Back over the slash */
243959995Selan 	--obp;
244059995Selan 
244159995Selan 	/* Comments are equivalent to spaces. */
244259995Selan 	if (! put_out_comments)
244359995Selan 	  *obp++ = ' ';
244459995Selan 	else {
244559995Selan 	  /* must fake up a comment here */
244659995Selan 	  *obp++ = '/';
244759995Selan 	  *obp++ = '/';
244859995Selan 	}
244959995Selan 	{
245059995Selan 	  U_CHAR *before_bp = ibp+2;
245159995Selan 
245259995Selan 	  while (ibp < limit) {
245359995Selan 	    if (*ibp++ == '\n') {
245459995Selan 	      ibp--;
245559995Selan 	      if (put_out_comments) {
245659995Selan 		bcopy (before_bp, obp, ibp - before_bp);
245759995Selan 		obp += ibp - before_bp;
245859995Selan 	      }
245959995Selan 	      break;
246059995Selan 	    }
246159995Selan 	  }
246259995Selan 	  break;
246359995Selan 	}
246459995Selan       }
246559995Selan 
246659995Selan       /* Ordinary C comment.  Skip it, optionally copying it to output.  */
246759995Selan 
246859995Selan       start_line = ip->lineno;
246959995Selan 
247059995Selan       ++ibp;			/* Skip the star. */
247159995Selan 
247259995Selan       /* If this cpp is for lint, we peek inside the comments: */
247359995Selan       if (lint) {
247459995Selan 	U_CHAR *argbp;
247559995Selan 	int cmdlen, arglen;
247659995Selan 	char *lintcmd = get_lintcmd (ibp, limit, &argbp, &arglen, &cmdlen);
247759995Selan 
247859995Selan 	if (lintcmd != NULL) {
247959995Selan 	  /* I believe it is always safe to emit this newline: */
248059995Selan 	  obp[-1] = '\n';
248159995Selan 	  bcopy ("#pragma lint ", obp, 13);
248259995Selan 	  obp += 13;
248359995Selan 	  bcopy (lintcmd, obp, cmdlen);
248459995Selan 	  obp += cmdlen;
248559995Selan 
248659995Selan 	  if (arglen != 0) {
248759995Selan 	    *(obp++) = ' ';
248859995Selan 	    bcopy (argbp, obp, arglen);
248959995Selan 	    obp += arglen;
249059995Selan 	  }
249159995Selan 
249259995Selan 	  /* OK, now bring us back to the state we were in before we entered
249359995Selan 	     this branch.  We need #line b/c the newline for the pragma
249459995Selan 	     could fuck things up. */
249559995Selan 	  output_line_command (ip, op, 0, same_file);
249659995Selan 	  *(obp++) = ' ';	/* just in case, if comments are copied thru */
249759995Selan 	  *(obp++) = '/';
249859995Selan 	}
249959995Selan       }
250059995Selan 
250159995Selan       /* Comments are equivalent to spaces.
250259995Selan 	 Note that we already output the slash; we might not want it.
250359995Selan 	 For -traditional, a comment is equivalent to nothing.  */
250459995Selan       if (! put_out_comments) {
250559995Selan 	if (traditional)
250659995Selan 	  obp--;
250759995Selan 	else
250859995Selan 	  obp[-1] = ' ';
250959995Selan       }
251059995Selan       else
251159995Selan 	*obp++ = '*';
251259995Selan 
251359995Selan       {
251459995Selan 	U_CHAR *before_bp = ibp;
251559995Selan 
251659995Selan 	while (ibp < limit) {
251759995Selan 	  switch (*ibp++) {
251859995Selan 	  case '/':
251959995Selan 	    if (warn_comments && ibp < limit && *ibp == '*')
252059995Selan 	      warning("`/*' within comment");
252159995Selan 	    break;
252259995Selan 	  case '*':
252359995Selan 	    if (*ibp == '\\' && ibp[1] == '\n')
252459995Selan 	      newline_fix (ibp);
252559995Selan 	    if (ibp >= limit || *ibp == '/')
252659995Selan 	      goto comment_end;
252759995Selan 	    break;
252859995Selan 	  case '\n':
252959995Selan 	    ++ip->lineno;
253059995Selan 	    /* Copy the newline into the output buffer, in order to
253159995Selan 	       avoid the pain of a #line every time a multiline comment
253259995Selan 	       is seen.  */
253359995Selan 	    if (!put_out_comments)
253459995Selan 	      *obp++ = '\n';
253559995Selan 	    ++op->lineno;
253659995Selan 	  }
253759995Selan 	}
253859995Selan       comment_end:
253959995Selan 
254059995Selan 	if (ibp >= limit)
254159995Selan 	  error_with_line (line_for_error (start_line),
254259995Selan 			   "unterminated comment");
254359995Selan 	else {
254459995Selan 	  ibp++;
254559995Selan 	  if (put_out_comments) {
254659995Selan 	    bcopy (before_bp, obp, ibp - before_bp);
254759995Selan 	    obp += ibp - before_bp;
254859995Selan 	  }
254959995Selan 	}
255059995Selan       }
255159995Selan       break;
255259995Selan 
255359995Selan     case '$':
255459995Selan       if (!dollars_in_ident)
255559995Selan 	goto randomchar;
255659995Selan       goto letter;
255759995Selan 
255859995Selan     case '0': case '1': case '2': case '3': case '4':
255959995Selan     case '5': case '6': case '7': case '8': case '9':
256059995Selan       /* If digit is not part of identifier, it starts a number,
256159995Selan 	 which means that following letters are not an identifier.
256259995Selan 	 "0x5" does not refer to an identifier "x5".
256359995Selan 	 So copy all alphanumerics that follow without accumulating
256459995Selan 	 as an identifier.  Periods also, for sake of "3.e7".  */
256559995Selan 
256659995Selan       if (ident_length == 0) {
256759995Selan 	while (ibp < limit) {
256859995Selan 	  while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') {
256959995Selan 	    ++ip->lineno;
257059995Selan 	    ibp += 2;
257159995Selan 	  }
257259995Selan 	  c = *ibp++;
257359995Selan 	  /* ".." terminates a preprocessing number.  This is useless for C
257459995Selan 	     code but useful for preprocessing other things.  */
257559995Selan 	  if (!isalnum (c) && (c != '.' || *ibp == '.') && c != '_') {
257659995Selan 	    --ibp;
257759995Selan 	    break;
257859995Selan 	  }
257959995Selan 	  *obp++ = c;
258059995Selan 	  /* A sign can be part of a preprocessing number
258159995Selan 	     if it follows an e.  */
258259995Selan 	  if (c == 'e' || c == 'E') {
258359995Selan 	    while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') {
258459995Selan 	      ++ip->lineno;
258559995Selan 	      ibp += 2;
258659995Selan 	    }
258759995Selan 	    if (ibp < limit && (*ibp == '+' || *ibp == '-')) {
258859995Selan 	      *obp++ = *ibp++;
258959995Selan 	      /* But traditional C does not let the token go past the sign.  */
259059995Selan 	      if (traditional)
259159995Selan 		break;
259259995Selan 	    }
259359995Selan 	  }
259459995Selan 	}
259559995Selan 	break;
259659995Selan       }
259759995Selan       /* fall through */
259859995Selan 
259959995Selan     case '_':
260059995Selan     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
260159995Selan     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
260259995Selan     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
260359995Selan     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
260459995Selan     case 'y': case 'z':
260559995Selan     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
260659995Selan     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
260759995Selan     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
260859995Selan     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
260959995Selan     case 'Y': case 'Z':
261059995Selan     letter:
261159995Selan       ident_length++;
261259995Selan       /* Compute step of hash function, to avoid a proc call on every token */
261359995Selan       hash = HASHSTEP (hash, c);
261459995Selan       break;
261559995Selan 
261659995Selan     case '\n':
261759995Selan       /* If reprocessing a macro expansion, newline is a special marker.  */
261859995Selan       if (ip->macro != 0) {
261959995Selan 	/* Newline White is a "funny space" to separate tokens that are
262059995Selan 	   supposed to be separate but without space between.
262159995Selan 	   Here White means any whitespace character.
262259995Selan 	   Newline - marks a recursive macro use that is not
262359995Selan 	   supposed to be expandable.  */
262459995Selan 
262559995Selan 	if (*ibp == '-') {
262659995Selan 	  /* Newline - inhibits expansion of preceding token.
262759995Selan 	     If expanding a macro arg, we keep the newline -.
262859995Selan 	     In final output, it is deleted.  */
262959995Selan 	  if (! concatenated) {
263059995Selan 	    ident_length = 0;
263159995Selan 	    hash = 0;
263259995Selan 	  }
263359995Selan 	  ibp++;
263459995Selan 	  if (!output_marks) {
263559995Selan 	    obp--;
263659995Selan 	  } else {
263759995Selan 	    /* If expanding a macro arg, keep the newline -.  */
263859995Selan 	    *obp++ = '-';
263959995Selan 	  }
264059995Selan 	} else if (is_space[*ibp]) {
264159995Selan 	  /* Newline Space does not prevent expansion of preceding token
264259995Selan 	     so expand the preceding token and then come back.  */
264359995Selan 	  if (ident_length > 0)
264459995Selan 	    goto specialchar;
264559995Selan 
264659995Selan 	  /* If generating final output, newline space makes a space.  */
264759995Selan 	  if (!output_marks) {
264859995Selan 	    obp[-1] = *ibp++;
264959995Selan 	    /* And Newline Newline makes a newline, so count it.  */
265059995Selan 	    if (obp[-1] == '\n')
265159995Selan 	      op->lineno++;
265259995Selan 	  } else {
265359995Selan 	    /* If expanding a macro arg, keep the newline space.
265459995Selan 	       If the arg gets stringified, newline space makes nothing.  */
265559995Selan 	    *obp++ = *ibp++;
265659995Selan 	  }
265759995Selan 	} else abort ();	/* Newline followed by something random?  */
265859995Selan 	break;
265959995Selan       }
266059995Selan 
266159995Selan       /* If there is a pending identifier, handle it and come back here.  */
266259995Selan       if (ident_length > 0)
266359995Selan 	goto specialchar;
266459995Selan 
266559995Selan       beg_of_line = ibp;
266659995Selan 
266759995Selan       /* Update the line counts and output a #line if necessary.  */
266859995Selan       ++ip->lineno;
266959995Selan       ++op->lineno;
267059995Selan       if (ip->lineno != op->lineno) {
267159995Selan 	op->bufp = obp;
267259995Selan 	output_line_command (ip, op, 1, same_file);
267359995Selan 	check_expand (op, ip->length - (ip->bufp - ip->buf));
267459995Selan 	obp = op->bufp;
267559995Selan       }
267659995Selan       break;
267759995Selan 
267859995Selan       /* Come here either after (1) a null character that is part of the input
267959995Selan 	 or (2) at the end of the input, because there is a null there.  */
268059995Selan     case 0:
268159995Selan       if (ibp <= limit)
268259995Selan 	/* Our input really contains a null character.  */
268359995Selan 	goto randomchar;
268459995Selan 
268559995Selan       /* At end of a macro-expansion level, pop it and read next level.  */
268659995Selan       if (ip->macro != 0) {
268759995Selan 	obp--;
268859995Selan 	ibp--;
268959995Selan 	/* If traditional, and we have an identifier that ends here,
269059995Selan 	   process it now, so we get the right error for recursion.  */
269159995Selan 	if (traditional && ident_length
269259995Selan 	    && ! is_idchar[*instack[indepth - 1].bufp]) {
269359995Selan 	  redo_char = 1;
269459995Selan 	  goto randomchar;
269559995Selan 	}
269659995Selan 	POPMACRO;
269759995Selan 	RECACHE;
269859995Selan 	break;
269959995Selan       }
270059995Selan 
270159995Selan       /* If we don't have a pending identifier,
270259995Selan 	 return at end of input.  */
270359995Selan       if (ident_length == 0) {
270459995Selan 	obp--;
270559995Selan 	ibp--;
270659995Selan 	op->bufp = obp;
270759995Selan 	ip->bufp = ibp;
270859995Selan 	goto ending;
270959995Selan       }
271059995Selan 
271159995Selan       /* If we do have a pending identifier, just consider this null
271259995Selan 	 a special character and arrange to dispatch on it again.
271359995Selan 	 The second time, IDENT_LENGTH will be zero so we will return.  */
271459995Selan 
271559995Selan       /* Fall through */
271659995Selan 
271759995Selan specialchar:
271859995Selan 
271959995Selan       /* Handle the case of a character such as /, ', " or null
272059995Selan 	 seen following an identifier.  Back over it so that
272159995Selan 	 after the identifier is processed the special char
272259995Selan 	 will be dispatched on again.  */
272359995Selan 
272459995Selan       ibp--;
272559995Selan       obp--;
272659995Selan       redo_char = 1;
272759995Selan 
272859995Selan     default:
272959995Selan 
273059995Selan randomchar:
273159995Selan 
273259995Selan       if (ident_length > 0) {
273359995Selan 	register HASHNODE *hp;
273459995Selan 
273559995Selan 	/* We have just seen an identifier end.  If it's a macro, expand it.
273659995Selan 
273759995Selan 	   IDENT_LENGTH is the length of the identifier
273859995Selan 	   and HASH is its hash code.
273959995Selan 
274059995Selan 	   The identifier has already been copied to the output,
274159995Selan 	   so if it is a macro we must remove it.
274259995Selan 
274359995Selan 	   If REDO_CHAR is 0, the char that terminated the identifier
274459995Selan 	   has been skipped in the output and the input.
274559995Selan 	   OBP-IDENT_LENGTH-1 points to the identifier.
274659995Selan 	   If the identifier is a macro, we must back over the terminator.
274759995Selan 
274859995Selan 	   If REDO_CHAR is 1, the terminating char has already been
274959995Selan 	   backed over.  OBP-IDENT_LENGTH points to the identifier.  */
275059995Selan 
275159995Selan 	if (!pcp_outfile || pcp_inside_if) {
275259995Selan startagain:
275359995Selan 	  for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL;
275459995Selan 	       hp = hp->next) {
275559995Selan 
275659995Selan 	    if (hp->length == ident_length) {
275759995Selan 	      int obufp_before_macroname;
275859995Selan 	      int op_lineno_before_macroname;
275959995Selan 	      register int i = ident_length;
276059995Selan 	      register U_CHAR *p = hp->name;
276159995Selan 	      register U_CHAR *q = obp - i;
276259995Selan 	      int disabled;
276359995Selan 
276459995Selan 	      if (! redo_char)
276559995Selan 		q--;
276659995Selan 
276759995Selan 	      do {		/* All this to avoid a strncmp () */
276859995Selan 		if (*p++ != *q++)
276959995Selan 		  goto hashcollision;
277059995Selan 	      } while (--i);
277159995Selan 
277259995Selan 	      /* We found a use of a macro name.
277359995Selan 		 see if the context shows it is a macro call.  */
277459995Selan 
277559995Selan 	      /* Back up over terminating character if not already done.  */
277659995Selan 	      if (! redo_char) {
277759995Selan 		ibp--;
277859995Selan 		obp--;
277959995Selan 	      }
278059995Selan 
278159995Selan 	      /* Save this as a displacement from the beginning of the output
278259995Selan 		 buffer.  We can not save this as a position in the output
278359995Selan 		 buffer, because it may get realloc'ed by RECACHE.  */
278459995Selan 	      obufp_before_macroname = (obp - op->buf) - ident_length;
278559995Selan 	      op_lineno_before_macroname = op->lineno;
278659995Selan 
278759995Selan 	      if (hp->type == T_PCSTRING) {
278859995Selan 		pcstring_used (hp); /* Mark the definition of this key
278959995Selan 				       as needed, ensuring that it
279059995Selan 				       will be output.  */
279159995Selan 		break;		/* Exit loop, since the key cannot have a
279259995Selan 				   definition any longer.  */
279359995Selan 	      }
279459995Selan 
279559995Selan 	      /* Record whether the macro is disabled.  */
279659995Selan 	      disabled = hp->type == T_DISABLED;
279759995Selan 
279859995Selan 	      /* This looks like a macro ref, but if the macro was disabled,
279959995Selan 		 just copy its name and put in a marker if requested.  */
280059995Selan 
280159995Selan 	      if (disabled) {
280259995Selan #if 0
280359995Selan 		/* This error check caught useful cases such as
280459995Selan 		   #define foo(x,y) bar(x(y,0), y)
280559995Selan 		   foo(foo, baz)  */
280659995Selan 		if (traditional)
280759995Selan 		  error ("recursive use of macro `%s'", hp->name);
280859995Selan #endif
280959995Selan 
281059995Selan 		if (output_marks) {
281159995Selan 		  check_expand (op, limit - ibp + 2);
281259995Selan 		  *obp++ = '\n';
281359995Selan 		  *obp++ = '-';
281459995Selan 		}
281559995Selan 		break;
281659995Selan 	      }
281759995Selan 
281859995Selan 	      /* If macro wants an arglist, verify that a '(' follows.
281959995Selan 		 first skip all whitespace, copying it to the output
282059995Selan 		 after the macro name.  Then, if there is no '(',
282159995Selan 		 decide this is not a macro call and leave things that way.  */
282259995Selan 	      if ((hp->type == T_MACRO || hp->type == T_DISABLED)
282359995Selan 		  && hp->value.defn->nargs >= 0)
282459995Selan 		{
282559995Selan 		  U_CHAR *old_ibp = ibp;
282659995Selan 		  U_CHAR *old_obp = obp;
282759995Selan 		  int old_iln = ip->lineno;
282859995Selan 		  int old_oln = op->lineno;
282959995Selan 
283059995Selan 		  while (1) {
283159995Selan 		    /* Scan forward over whitespace, copying it to the output.  */
283259995Selan 		    if (ibp == limit && ip->macro != 0) {
283359995Selan 		      POPMACRO;
283459995Selan 		      RECACHE;
283559995Selan 		      old_ibp = ibp;
283659995Selan 		      old_obp = obp;
283759995Selan 		      old_iln = ip->lineno;
283859995Selan 		      old_oln = op->lineno;
283959995Selan 		    }
284059995Selan 		    /* A comment: copy it unchanged or discard it.  */
284159995Selan 		    else if (*ibp == '/' && ibp+1 != limit && ibp[1] == '*') {
284259995Selan 		      if (put_out_comments) {
284359995Selan 			*obp++ = '/';
284459995Selan 			*obp++ = '*';
284559995Selan 		      } else if (! traditional) {
284659995Selan 			*obp++ = ' ';
284759995Selan 		      }
284859995Selan 		      ibp += 2;
284959995Selan 		      while (ibp + 1 != limit
285059995Selan 			     && !(ibp[0] == '*' && ibp[1] == '/')) {
285159995Selan 			/* We need not worry about newline-marks,
285259995Selan 			   since they are never found in comments.  */
285359995Selan 			if (*ibp == '\n') {
285459995Selan 			  /* Newline in a file.  Count it.  */
285559995Selan 			  ++ip->lineno;
285659995Selan 			  ++op->lineno;
285759995Selan 			}
285859995Selan 			if (put_out_comments)
285959995Selan 			  *obp++ = *ibp++;
286059995Selan 			else
286159995Selan 			  ibp++;
286259995Selan 		      }
286359995Selan 		      ibp += 2;
286459995Selan 		      if (put_out_comments) {
286559995Selan 			*obp++ = '*';
286659995Selan 			*obp++ = '/';
286759995Selan 		      }
286859995Selan 		    }
286959995Selan 		    else if (is_space[*ibp]) {
287059995Selan 		      *obp++ = *ibp++;
287159995Selan 		      if (ibp[-1] == '\n') {
287259995Selan 			if (ip->macro == 0) {
287359995Selan 			  /* Newline in a file.  Count it.  */
287459995Selan 			  ++ip->lineno;
287559995Selan 			  ++op->lineno;
287659995Selan 			} else if (!output_marks) {
287759995Selan 			  /* A newline mark, and we don't want marks
287859995Selan 			     in the output.  If it is newline-hyphen,
287959995Selan 			     discard it entirely.  Otherwise, it is
288059995Selan 			     newline-whitechar, so keep the whitechar.  */
288159995Selan 			  obp--;
288259995Selan 			  if (*ibp == '-')
288359995Selan 			    ibp++;
288459995Selan 			  else {
288559995Selan 			    if (*ibp == '\n')
288659995Selan 			      ++op->lineno;
288759995Selan 			    *obp++ = *ibp++;
288859995Selan 			  }
288959995Selan 			} else {
289059995Selan 			  /* A newline mark; copy both chars to the output.  */
289159995Selan 			  *obp++ = *ibp++;
289259995Selan 			}
289359995Selan 		      }
289459995Selan 		    }
289559995Selan 		    else break;
289659995Selan 		  }
289759995Selan 		  if (*ibp != '(') {
289859995Selan 		    /* It isn't a macro call.
289959995Selan 		       Put back the space that we just skipped.  */
290059995Selan 		    ibp = old_ibp;
290159995Selan 		    obp = old_obp;
290259995Selan 		    ip->lineno = old_iln;
290359995Selan 		    op->lineno = old_oln;
290459995Selan 		    /* Exit the for loop.  */
290559995Selan 		    break;
290659995Selan 		  }
290759995Selan 		}
290859995Selan 
290959995Selan 	      /* This is now known to be a macro call.
291059995Selan 		 Discard the macro name from the output,
291159995Selan 		 along with any following whitespace just copied.  */
291259995Selan 	      obp = op->buf + obufp_before_macroname;
291359995Selan 	      op->lineno = op_lineno_before_macroname;
291459995Selan 
291559995Selan 	      /* Expand the macro, reading arguments as needed,
291659995Selan 		 and push the expansion on the input stack.  */
291759995Selan 	      ip->bufp = ibp;
291859995Selan 	      op->bufp = obp;
291959995Selan 	      macroexpand (hp, op);
292059995Selan 
292159995Selan 	      /* Reexamine input stack, since macroexpand has pushed
292259995Selan 		 a new level on it.  */
292359995Selan 	      obp = op->bufp;
292459995Selan 	      RECACHE;
292559995Selan 	      break;
292659995Selan 	    }
292759995Selan hashcollision:
292859995Selan 	    ;
292959995Selan 	  }			/* End hash-table-search loop */
293059995Selan 	}
293159995Selan 	ident_length = hash = 0; /* Stop collecting identifier */
293259995Selan 	redo_char = 0;
293359995Selan 	concatenated = 0;
293459995Selan       }				/* End if (ident_length > 0) */
293559995Selan     }				/* End switch */
293659995Selan   }				/* End per-char loop */
293759995Selan 
293859995Selan   /* Come here to return -- but first give an error message
293959995Selan      if there was an unterminated successful conditional.  */
294059995Selan  ending:
294159995Selan   if (if_stack != ip->if_stack) {
294259995Selan     char *str;
294359995Selan     switch (if_stack->type) {
294459995Selan     case T_IF:
294559995Selan       str = "if";
294659995Selan       break;
294759995Selan     case T_IFDEF:
294859995Selan       str = "ifdef";
294959995Selan       break;
295059995Selan     case T_IFNDEF:
295159995Selan       str = "ifndef";
295259995Selan       break;
295359995Selan     case T_ELSE:
295459995Selan       str = "else";
295559995Selan       break;
295659995Selan     case T_ELIF:
295759995Selan       str = "elif";
295859995Selan       break;
295959995Selan     }
296059995Selan     error_with_line (line_for_error (if_stack->lineno),
296159995Selan 		     "unterminated `#%s' conditional", str);
296259995Selan   }
296359995Selan   if_stack = ip->if_stack;
296459995Selan }
296559995Selan 
296659995Selan /*
296759995Selan  * Rescan a string into a temporary buffer and return the result
296859995Selan  * as a FILE_BUF.  Note this function returns a struct, not a pointer.
296959995Selan  *
297059995Selan  * OUTPUT_MARKS nonzero means keep Newline markers found in the input
297159995Selan  * and insert such markers when appropriate.  See `rescan' for details.
297259995Selan  * OUTPUT_MARKS is 1 for macroexpanding a macro argument separately
297359995Selan  * before substitution; it is 0 for other uses.
297459995Selan  */
297559995Selan static FILE_BUF
expand_to_temp_buffer(buf,limit,output_marks,assertions)297659995Selan expand_to_temp_buffer (buf, limit, output_marks, assertions)
297759995Selan      U_CHAR *buf, *limit;
297859995Selan      int output_marks, assertions;
297959995Selan {
298059995Selan   register FILE_BUF *ip;
298159995Selan   FILE_BUF obuf;
298259995Selan   int length = limit - buf;
298359995Selan   U_CHAR *buf1;
298459995Selan   int odepth = indepth;
298559995Selan   int save_assertions_flag = assertions_flag;
298659995Selan 
298759995Selan   assertions_flag = assertions;
298859995Selan 
298959995Selan   if (length < 0)
299059995Selan     abort ();
299159995Selan 
299259995Selan   /* Set up the input on the input stack.  */
299359995Selan 
299459995Selan   buf1 = (U_CHAR *) alloca (length + 1);
299559995Selan   {
299659995Selan     register U_CHAR *p1 = buf;
299759995Selan     register U_CHAR *p2 = buf1;
299859995Selan 
299959995Selan     while (p1 != limit)
300059995Selan       *p2++ = *p1++;
300159995Selan   }
300259995Selan   buf1[length] = 0;
300359995Selan 
300459995Selan   /* Set up to receive the output.  */
300559995Selan 
300659995Selan   obuf.length = length * 2 + 100; /* Usually enough.  Why be stingy?  */
300759995Selan   obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
300859995Selan   obuf.fname = 0;
300959995Selan   obuf.macro = 0;
301059995Selan   obuf.free_ptr = 0;
301159995Selan 
301259995Selan   CHECK_DEPTH ({return obuf;});
301359995Selan 
301459995Selan   ++indepth;
301559995Selan 
301659995Selan   ip = &instack[indepth];
301759995Selan   ip->fname = 0;
301859995Selan   ip->nominal_fname = 0;
301959995Selan   ip->system_header_p = 0;
302059995Selan   ip->macro = 0;
302159995Selan   ip->free_ptr = 0;
302259995Selan   ip->length = length;
302359995Selan   ip->buf = ip->bufp = buf1;
302459995Selan   ip->if_stack = if_stack;
302559995Selan 
302659995Selan   ip->lineno = obuf.lineno = 1;
302759995Selan 
302859995Selan   /* Scan the input, create the output.  */
302959995Selan   rescan (&obuf, output_marks);
303059995Selan 
303159995Selan   /* Pop input stack to original state.  */
303259995Selan   --indepth;
303359995Selan 
303459995Selan   if (indepth != odepth)
303559995Selan     abort ();
303659995Selan 
303759995Selan   /* Record the output.  */
303859995Selan   obuf.length = obuf.bufp - obuf.buf;
303959995Selan 
304059995Selan   assertions_flag = save_assertions_flag;
304159995Selan   return obuf;
304259995Selan }
304359995Selan 
304459995Selan /*
304559995Selan  * Process a # directive.  Expects IP->bufp to point after the '#', as in
304659995Selan  * `#define foo bar'.  Passes to the command handler
304759995Selan  * (do_define, do_include, etc.): the addresses of the 1st and
304859995Selan  * last chars of the command (starting immediately after the #
304959995Selan  * keyword), plus op and the keyword table pointer.  If the command
305059995Selan  * contains comments it is copied into a temporary buffer sans comments
305159995Selan  * and the temporary buffer is passed to the command handler instead.
305259995Selan  * Likewise for backslash-newlines.
305359995Selan  *
305459995Selan  * Returns nonzero if this was a known # directive.
305559995Selan  * Otherwise, returns zero, without advancing the input pointer.
305659995Selan  */
305759995Selan 
305859995Selan static int
handle_directive(ip,op)305959995Selan handle_directive (ip, op)
306059995Selan      FILE_BUF *ip, *op;
306159995Selan {
306259995Selan   register U_CHAR *bp, *cp;
306359995Selan   register struct directive *kt;
306459995Selan   register int ident_length;
306559995Selan   U_CHAR *resume_p;
306659995Selan 
306759995Selan   /* Nonzero means we must copy the entire command
306859995Selan      to get rid of comments or backslash-newlines.  */
306959995Selan   int copy_command = 0;
307059995Selan 
307159995Selan   U_CHAR *ident, *after_ident;
307259995Selan 
307359995Selan   bp = ip->bufp;
307459995Selan 
307559995Selan   /* Record where the directive started.  do_xifdef needs this.  */
307659995Selan   directive_start = bp - 1;
307759995Selan 
307859995Selan   /* Skip whitespace and \-newline.  */
307959995Selan   while (1) {
308059995Selan     if (is_hor_space[*bp]) {
308159995Selan       if ((*bp == '\f' || *bp == '\v') && pedantic)
308259995Selan 	pedwarn ("%s in preprocessing directive",
308359995Selan 		 *bp == '\f' ? "formfeed" : "vertical tab");
308459995Selan       bp++;
308559995Selan     } else if (*bp == '/' && bp[1] == '*') {
308659995Selan       ip->bufp = bp;
308759995Selan       skip_to_end_of_comment (ip, &ip->lineno, 0);
308859995Selan       bp = ip->bufp;
308959995Selan     } else if (*bp == '\\' && bp[1] == '\n') {
309059995Selan       bp += 2; ip->lineno++;
309159995Selan     } else break;
309259995Selan   }
309359995Selan 
309459995Selan   /* Now find end of directive name.
309559995Selan      If we encounter a backslash-newline, exchange it with any following
309659995Selan      symbol-constituents so that we end up with a contiguous name.  */
309759995Selan 
309859995Selan   cp = bp;
309959995Selan   while (1) {
310059995Selan     if (is_idchar[*cp])
310159995Selan       cp++;
310259995Selan     else {
310359995Selan       if (*cp == '\\' && cp[1] == '\n')
310459995Selan 	name_newline_fix (cp);
310559995Selan       if (is_idchar[*cp])
310659995Selan 	cp++;
310759995Selan       else break;
310859995Selan     }
310959995Selan   }
311059995Selan   ident_length = cp - bp;
311159995Selan   ident = bp;
311259995Selan   after_ident = cp;
311359995Selan 
311459995Selan   /* A line of just `#' becomes blank.  */
311559995Selan 
311659995Selan   if (ident_length == 0 && *after_ident == '\n') {
311759995Selan     ip->bufp = after_ident;
311859995Selan     return 1;
311959995Selan   }
312059995Selan 
312159995Selan   if (ident_length == 0 || !is_idstart[*ident]) {
312259995Selan     U_CHAR *p = ident;
312359995Selan     while (is_idchar[*p]) {
312459995Selan       if (*p < '0' || *p > '9')
312559995Selan 	break;
312659995Selan       p++;
312759995Selan     }
312859995Selan     /* Handle # followed by a line number.  */
312959995Selan     if (p != ident && !is_idchar[*p]) {
313059995Selan       static struct directive line_directive_table[] = {
313159995Selan 	{  4, do_line, "line", T_LINE},
313259995Selan       };
313359995Selan       if (pedantic)
313459995Selan 	pedwarn ("`#' followed by integer");
313559995Selan       after_ident = ident;
313659995Selan       kt = line_directive_table;
313759995Selan       goto old_linenum;
313859995Selan     }
313959995Selan 
314059995Selan     /* Avoid error for `###' and similar cases unless -pedantic.  */
314159995Selan     if (p == ident) {
314259995Selan       while (*p == '#' || is_hor_space[*p]) p++;
314359995Selan       if (*p == '\n') {
314459995Selan 	if (pedantic && !lang_asm)
314559995Selan 	  warning ("invalid preprocessor directive");
314659995Selan 	return 0;
314759995Selan       }
314859995Selan     }
314959995Selan 
315059995Selan     if (!lang_asm)
315159995Selan       error ("invalid preprocessor directive name");
315259995Selan 
315359995Selan     return 0;
315459995Selan   }
315559995Selan 
315659995Selan   /*
315759995Selan    * Decode the keyword and call the appropriate expansion
315859995Selan    * routine, after moving the input pointer up to the next line.
315959995Selan    */
316059995Selan   for (kt = directive_table; kt->length > 0; kt++) {
316159995Selan     if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length)) {
316259995Selan       register U_CHAR *buf;
316359995Selan       register U_CHAR *limit;
316459995Selan       int unterminated;
316559995Selan       int junk;
316659995Selan       int *already_output = 0;
316759995Selan 
316859995Selan       /* Nonzero means do not delete comments within the directive.
316959995Selan 	 #define needs this when -traditional.  */
317059995Selan       int keep_comments;
317159995Selan 
317259995Selan     old_linenum:
317359995Selan 
317459995Selan       limit = ip->buf + ip->length;
317559995Selan       unterminated = 0;
317659995Selan       keep_comments = traditional && kt->traditional_comments;
317759995Selan       /* #import is defined only in Objective C, or when on the NeXT.  */
317859995Selan       if (kt->type == T_IMPORT && !(objc || lookup ("__NeXT__", -1, -1)))
317959995Selan 	break;
318059995Selan 
318159995Selan       /* Find the end of this command (first newline not backslashed
318259995Selan 	 and not in a string or comment).
318359995Selan 	 Set COPY_COMMAND if the command must be copied
318459995Selan 	 (it contains a backslash-newline or a comment).  */
318559995Selan 
318659995Selan       buf = bp = after_ident;
318759995Selan       while (bp < limit) {
318859995Selan 	register U_CHAR c = *bp++;
318959995Selan 	switch (c) {
319059995Selan 	case '\\':
319159995Selan 	  if (bp < limit) {
319259995Selan 	    if (*bp == '\n') {
319359995Selan 	      ip->lineno++;
319459995Selan 	      copy_command = 1;
319559995Selan 	    }
319659995Selan 	    bp++;
319759995Selan 	  }
319859995Selan 	  break;
319959995Selan 
320059995Selan 	case '\'':
320159995Selan 	case '\"':
320259995Selan 	  bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, &copy_command, &unterminated);
320359995Selan 	  /* Don't bother calling the directive if we already got an error
320459995Selan 	     message due to unterminated string.  Skip everything and pretend
320559995Selan 	     we called the directive.  */
320659995Selan 	  if (unterminated) {
320759995Selan 	    if (traditional) {
320859995Selan 	      /* Traditional preprocessing permits unterminated strings.  */
320959995Selan 	      ip->bufp = bp;
321059995Selan 	      goto endloop1;
321159995Selan 	    }
321259995Selan 	    ip->bufp = bp;
321359995Selan 	    return 1;
321459995Selan 	  }
321559995Selan 	  break;
321659995Selan 
321759995Selan 	  /* <...> is special for #include.  */
321859995Selan 	case '<':
321959995Selan 	  if (!kt->angle_brackets)
322059995Selan 	    break;
322159995Selan 	  while (*bp && *bp != '>') bp++;
322259995Selan 	  break;
322359995Selan 
322459995Selan 	case '/':
322559995Selan 	  if (*bp == '\\' && bp[1] == '\n')
322659995Selan 	    newline_fix (bp);
322759995Selan 	  if (*bp == '*'
322859995Selan 	      || (cplusplus_comments && *bp == '/')) {
322959995Selan 	    U_CHAR *obp = bp - 1;
323059995Selan 	    ip->bufp = bp + 1;
323159995Selan 	    skip_to_end_of_comment (ip, &ip->lineno, 0);
323259995Selan 	    bp = ip->bufp;
323359995Selan 	    /* No need to copy the command because of a comment at the end;
323459995Selan 	       just don't include the comment in the directive.  */
323559995Selan 	    if (bp == limit || *bp == '\n') {
323659995Selan 	      bp = obp;
323759995Selan 	      goto endloop1;
323859995Selan 	    }
323959995Selan 	    /* Don't remove the comments if -traditional.  */
324059995Selan 	    if (! keep_comments)
324159995Selan 	      copy_command++;
324259995Selan 	  }
324359995Selan 	  break;
324459995Selan 
324559995Selan 	case '\f':
324659995Selan 	case '\v':
324759995Selan 	  if (pedantic)
324859995Selan 	    pedwarn ("%s in preprocessing directive",
324959995Selan 		     c == '\f' ? "formfeed" : "vertical tab");
325059995Selan 	  break;
325159995Selan 
325259995Selan 	case '\n':
325359995Selan 	  --bp;		/* Point to the newline */
325459995Selan 	  ip->bufp = bp;
325559995Selan 	  goto endloop1;
325659995Selan 	}
325759995Selan       }
325859995Selan       ip->bufp = bp;
325959995Selan 
326059995Selan     endloop1:
326159995Selan       resume_p = ip->bufp;
326259995Selan       /* BP is the end of the directive.
326359995Selan 	 RESUME_P is the next interesting data after the directive.
326459995Selan 	 A comment may come between.  */
326559995Selan 
326659995Selan       /* If a directive should be copied through, and -E was given,
326759995Selan 	 pass it through before removing comments.  */
326859995Selan       if (!no_output && kt->pass_thru && put_out_comments) {
326959995Selan         int len;
327059995Selan 
327159995Selan 	/* Output directive name.  */
327259995Selan         check_expand (op, kt->length + 2);
327359995Selan 	/* Make sure # is at the start of a line */
327459995Selan 	if (op->bufp > op->buf && op->bufp[-1] != '\n') {
327559995Selan 	  op->lineno++;
327659995Selan 	  *op->bufp++ = '\n';
327759995Selan 	}
327859995Selan         *op->bufp++ = '#';
327959995Selan         bcopy (kt->name, op->bufp, kt->length);
328059995Selan         op->bufp += kt->length;
328159995Selan 
328259995Selan 	/* Output arguments.  */
328359995Selan 	len = (bp - buf);
328459995Selan 	check_expand (op, len);
328559995Selan 	bcopy (buf, op->bufp, len);
328659995Selan 	op->bufp += len;
328759995Selan 	/* Take account of any (escaped) newlines just output.  */
328859995Selan 	while (--len >= 0)
328959995Selan 	  if (buf[len] == '\n')
329059995Selan 	    op->lineno++;
329159995Selan 
329259995Selan 	already_output = &junk;
329359995Selan       }				/* Don't we need a newline or #line? */
329459995Selan 
329559995Selan       if (copy_command) {
329659995Selan 	register U_CHAR *xp = buf;
329759995Selan 	/* Need to copy entire command into temp buffer before dispatching */
329859995Selan 
329959995Selan 	cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus
330059995Selan 						  some slop */
330159995Selan 	buf = cp;
330259995Selan 
330359995Selan 	/* Copy to the new buffer, deleting comments
330459995Selan 	   and backslash-newlines (and whitespace surrounding the latter).  */
330559995Selan 
330659995Selan 	while (xp < bp) {
330759995Selan 	  register U_CHAR c = *xp++;
330859995Selan 	  *cp++ = c;
330959995Selan 
331059995Selan 	  switch (c) {
331159995Selan 	  case '\n':
331259995Selan 	    abort ();  /* A bare newline should never part of the line.  */
331359995Selan 	    break;
331459995Selan 
331559995Selan 	    /* <...> is special for #include.  */
331659995Selan 	  case '<':
331759995Selan 	    if (!kt->angle_brackets)
331859995Selan 	      break;
331959995Selan 	    while (xp < bp && c != '>') {
332059995Selan 	      c = *xp++;
332159995Selan 	      if (c == '\\' && xp < bp && *xp == '\n')
332259995Selan 		xp++;
332359995Selan 	      else
332459995Selan 		*cp++ = c;
332559995Selan 	    }
332659995Selan 	    break;
332759995Selan 
332859995Selan 	  case '\\':
332959995Selan 	    if (*xp == '\n') {
333059995Selan 	      xp++;
333159995Selan 	      cp--;
333259995Selan 	      if (cp != buf && is_space[cp[-1]]) {
333359995Selan 		while (cp != buf && is_space[cp[-1]]) cp--;
333459995Selan 		cp++;
333559995Selan 		SKIP_WHITE_SPACE (xp);
333659995Selan 	      } else if (is_space[*xp]) {
333759995Selan 		*cp++ = *xp++;
333859995Selan 		SKIP_WHITE_SPACE (xp);
333959995Selan 	      }
334059995Selan 	    } else {
334159995Selan 	      *cp++ = *xp++;
334259995Selan 	    }
334359995Selan 	    break;
334459995Selan 
334559995Selan 	  case '\'':
334659995Selan 	  case '\"':
334759995Selan 	    {
334859995Selan 	      register U_CHAR *bp1
334959995Selan 		= skip_quoted_string (xp - 1, bp, ip->lineno,
335059995Selan 				      NULL_PTR, NULL_PTR, NULL_PTR);
335159995Selan 	      while (xp != bp1)
335259995Selan 		if (*xp == '\\') {
335359995Selan 		  if (*++xp != '\n')
335459995Selan 		    *cp++ = '\\';
335559995Selan 		  else
335659995Selan 		    xp++;
335759995Selan 		} else
335859995Selan 		  *cp++ = *xp++;
335959995Selan 	    }
336059995Selan 	    break;
336159995Selan 
336259995Selan 	  case '/':
336359995Selan 	    if (*xp == '*'
336459995Selan 		|| (cplusplus_comments && *xp == '/')) {
336559995Selan 	      ip->bufp = xp + 1;
336659995Selan 	      /* If we already copied the command through,
336759995Selan 		 already_output != 0 prevents outputting comment now.  */
336859995Selan 	      skip_to_end_of_comment (ip, already_output, 0);
336959995Selan 	      if (keep_comments)
337059995Selan 		while (xp != ip->bufp)
337159995Selan 		  *cp++ = *xp++;
337259995Selan 	      /* Delete or replace the slash.  */
337359995Selan 	      else if (traditional)
337459995Selan 		cp--;
337559995Selan 	      else
337659995Selan 		cp[-1] = ' ';
337759995Selan 	      xp = ip->bufp;
337859995Selan 	    }
337959995Selan 	  }
338059995Selan 	}
338159995Selan 
338259995Selan 	/* Null-terminate the copy.  */
338359995Selan 
338459995Selan 	*cp = 0;
338559995Selan       } else
338659995Selan 	cp = bp;
338759995Selan 
338859995Selan       ip->bufp = resume_p;
338959995Selan 
339059995Selan       /* Some directives should be written out for cc1 to process,
339159995Selan 	 just as if they were not defined.  And sometimes we're copying
339259995Selan 	 definitions through.  */
339359995Selan 
339459995Selan       if (!no_output && already_output == 0
339559995Selan 	  && (kt->pass_thru
339659995Selan 	      || (kt->type == T_DEFINE
339759995Selan 		  && (dump_macros == dump_names
339859995Selan 		      || dump_macros == dump_definitions)))) {
339959995Selan         int len;
340059995Selan 
340159995Selan 	/* Output directive name.  */
340259995Selan         check_expand (op, kt->length + 1);
340359995Selan         *op->bufp++ = '#';
340459995Selan         bcopy (kt->name, op->bufp, kt->length);
340559995Selan         op->bufp += kt->length;
340659995Selan 
340759995Selan 	if (kt->pass_thru || dump_macros == dump_definitions) {
340859995Selan 	  /* Output arguments.  */
340959995Selan 	  len = (cp - buf);
341059995Selan 	  check_expand (op, len);
341159995Selan 	  bcopy (buf, op->bufp, len);
341259995Selan 	  op->bufp += len;
341359995Selan 	} else if (kt->type == T_DEFINE && dump_macros == dump_names) {
341459995Selan 	  U_CHAR *xp = buf;
341559995Selan 	  U_CHAR *yp;
341659995Selan 	  SKIP_WHITE_SPACE (xp);
341759995Selan 	  yp = xp;
341859995Selan 	  while (is_idchar[*xp]) xp++;
341959995Selan 	  len = (xp - yp);
342059995Selan 	  check_expand (op, len + 1);
342159995Selan 	  *op->bufp++ = ' ';
342259995Selan 	  bcopy (yp, op->bufp, len);
342359995Selan 	  op->bufp += len;
342459995Selan 	}
342559995Selan       }				/* Don't we need a newline or #line? */
342659995Selan 
342759995Selan       /* Call the appropriate command handler.  buf now points to
342859995Selan 	 either the appropriate place in the input buffer, or to
342959995Selan 	 the temp buffer if it was necessary to make one.  cp
343059995Selan 	 points to the first char after the contents of the (possibly
343159995Selan 	 copied) command, in either case. */
343259995Selan       (*kt->func) (buf, cp, op, kt);
343359995Selan       check_expand (op, ip->length - (ip->bufp - ip->buf));
343459995Selan 
343559995Selan       return 1;
343659995Selan     }
343759995Selan   }
343859995Selan 
343959995Selan   /* It is deliberate that we don't warn about undefined directives.
344059995Selan      That is the responsibility of cc1.  */
344159995Selan   return 0;
344259995Selan }
344359995Selan 
344459995Selan static struct tm *
timestamp()344559995Selan timestamp ()
344659995Selan {
344759995Selan   static struct tm *timebuf;
344859995Selan   if (!timebuf) {
344959995Selan     time_t t = time (0);
345059995Selan     timebuf = localtime (&t);
345159995Selan   }
345259995Selan   return timebuf;
345359995Selan }
345459995Selan 
345559995Selan static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
345659995Selan 			     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
345759995Selan 			    };
345859995Selan 
345959995Selan /*
346059995Selan  * expand things like __FILE__.  Place the expansion into the output
346159995Selan  * buffer *without* rescanning.
346259995Selan  */
346359995Selan 
346459995Selan static void
special_symbol(hp,op)346559995Selan special_symbol (hp, op)
346659995Selan      HASHNODE *hp;
346759995Selan      FILE_BUF *op;
346859995Selan {
346959995Selan   char *buf;
347059995Selan   int i, len;
347159995Selan   int true_indepth;
347259995Selan   FILE_BUF *ip = NULL;
347359995Selan   struct tm *timebuf;
347459995Selan 
347559995Selan   int paren = 0;		/* For special `defined' keyword */
347659995Selan 
347759995Selan   if (pcp_outfile && pcp_inside_if
347859995Selan       && hp->type != T_SPEC_DEFINED && hp->type != T_CONST)
347959995Selan     error ("Predefined macro `%s' used inside `#if' during precompilation",
348059995Selan 	   hp->name);
348159995Selan 
348259995Selan   for (i = indepth; i >= 0; i--)
348359995Selan     if (instack[i].fname != NULL) {
348459995Selan       ip = &instack[i];
348559995Selan       break;
348659995Selan     }
348759995Selan   if (ip == NULL) {
348859995Selan     error ("cccp error: not in any file?!");
348959995Selan     return;			/* the show must go on */
349059995Selan   }
349159995Selan 
349259995Selan   switch (hp->type) {
349359995Selan   case T_FILE:
349459995Selan   case T_BASE_FILE:
349559995Selan     {
349659995Selan       char *string;
349759995Selan       if (hp->type == T_FILE)
349859995Selan 	string = ip->nominal_fname;
349959995Selan       else
350059995Selan 	string = instack[0].nominal_fname;
350159995Selan 
350259995Selan       if (string)
350359995Selan 	{
350459995Selan 	  buf = (char *) alloca (3 + strlen (string));
350559995Selan 	  sprintf (buf, "\"%s\"", string);
350659995Selan 	}
350759995Selan       else
350859995Selan 	buf = "\"\"";
350959995Selan 
351059995Selan       break;
351159995Selan     }
351259995Selan 
351359995Selan   case T_INCLUDE_LEVEL:
351459995Selan     true_indepth = 0;
351559995Selan     for (i = indepth; i >= 0; i--)
351659995Selan       if (instack[i].fname != NULL)
351759995Selan         true_indepth++;
351859995Selan 
351959995Selan     buf = (char *) alloca (8);	/* Eight bytes ought to be more than enough */
352059995Selan     sprintf (buf, "%d", true_indepth - 1);
352159995Selan     break;
352259995Selan 
352359995Selan   case T_VERSION:
352459995Selan     buf = (char *) alloca (3 + strlen (version_string));
352559995Selan     sprintf (buf, "\"%s\"", version_string);
352659995Selan     break;
352759995Selan 
352859995Selan   case T_SIZE_TYPE:
352959995Selan     buf = (char *) alloca (3 + strlen (SIZE_TYPE));
353059995Selan     sprintf (buf, "%s", SIZE_TYPE);
353159995Selan     break;
353259995Selan 
353359995Selan   case T_PTRDIFF_TYPE:
353459995Selan     buf = (char *) alloca (3 + strlen (PTRDIFF_TYPE));
353559995Selan     sprintf (buf, "%s", PTRDIFF_TYPE);
353659995Selan     break;
353759995Selan 
353859995Selan   case T_WCHAR_TYPE:
353959995Selan     buf = (char *) alloca (3 + strlen (WCHAR_TYPE));
354059995Selan     sprintf (buf, "%s", WCHAR_TYPE);
354159995Selan     break;
354259995Selan 
354359995Selan   case T_CONST:
354459995Selan     buf = (char *) alloca (4 * sizeof (int));
354559995Selan     sprintf (buf, "%d", hp->value.ival);
354659995Selan     if (pcp_inside_if && pcp_outfile)
354759995Selan       /* Output a precondition for this macro use */
354859995Selan       fprintf (pcp_outfile, "#define %s %d\n", hp->name, hp->value.ival);
354959995Selan     break;
355059995Selan 
355159995Selan   case T_SPECLINE:
355259995Selan     buf = (char *) alloca (10);
355359995Selan     sprintf (buf, "%d", ip->lineno);
355459995Selan     break;
355559995Selan 
355659995Selan   case T_DATE:
355759995Selan   case T_TIME:
355859995Selan     buf = (char *) alloca (20);
355959995Selan     timebuf = timestamp ();
356059995Selan     if (hp->type == T_DATE)
356159995Selan       sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],
356259995Selan 	      timebuf->tm_mday, timebuf->tm_year + 1900);
356359995Selan     else
356459995Selan       sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
356559995Selan 	      timebuf->tm_sec);
356659995Selan     break;
356759995Selan 
356859995Selan   case T_SPEC_DEFINED:
356959995Selan     buf = " 0 ";		/* Assume symbol is not defined */
357059995Selan     ip = &instack[indepth];
357159995Selan     SKIP_WHITE_SPACE (ip->bufp);
357259995Selan     if (*ip->bufp == '(') {
357359995Selan       paren++;
357459995Selan       ip->bufp++;			/* Skip over the paren */
357559995Selan       SKIP_WHITE_SPACE (ip->bufp);
357659995Selan     }
357759995Selan 
357859995Selan     if (!is_idstart[*ip->bufp])
357959995Selan       goto oops;
358059995Selan     if (hp = lookup (ip->bufp, -1, -1)) {
358159995Selan       if (pcp_outfile && pcp_inside_if
358259995Selan 	  && hp->value.defn->predefined)
358359995Selan 	/* Output a precondition for this macro use. */
358459995Selan 	fprintf (pcp_outfile, "#define %s\n", hp->name);
358559995Selan       buf = " 1 ";
358659995Selan     }
358759995Selan     else
358859995Selan       if (pcp_outfile && pcp_inside_if)	{
358959995Selan 	/* Output a precondition for this macro use */
359059995Selan 	U_CHAR *cp = ip->bufp;
359159995Selan 	fprintf (pcp_outfile, "#undef ");
359259995Selan 	while (is_idchar[*cp]) /* Ick! */
359359995Selan 	  fputc (*cp++, pcp_outfile);
359459995Selan 	putc ('\n', pcp_outfile);
359559995Selan       }
359659995Selan     while (is_idchar[*ip->bufp])
359759995Selan       ++ip->bufp;
359859995Selan     SKIP_WHITE_SPACE (ip->bufp);
359959995Selan     if (paren) {
360059995Selan       if (*ip->bufp != ')')
360159995Selan 	goto oops;
360259995Selan       ++ip->bufp;
360359995Selan     }
360459995Selan     break;
360559995Selan 
360659995Selan oops:
360759995Selan 
360859995Selan     error ("`defined' without an identifier");
360959995Selan     break;
361059995Selan 
361159995Selan   default:
361259995Selan     error ("cccp error: invalid special hash type"); /* time for gdb */
361359995Selan     abort ();
361459995Selan   }
361559995Selan   len = strlen (buf);
361659995Selan   check_expand (op, len);
361759995Selan   bcopy (buf, op->bufp, len);
361859995Selan   op->bufp += len;
361959995Selan 
362059995Selan   return;
362159995Selan }
362259995Selan 
362359995Selan 
362459995Selan /* Routines to handle #directives */
362559995Selan 
362659995Selan /* Handle #include and #import.
362759995Selan    This function expects to see "fname" or <fname> on the input.  */
362859995Selan 
362959995Selan static int
do_include(buf,limit,op,keyword)363059995Selan do_include (buf, limit, op, keyword)
363159995Selan      U_CHAR *buf, *limit;
363259995Selan      FILE_BUF *op;
363359995Selan      struct directive *keyword;
363459995Selan {
363559995Selan   int importing = (keyword->type == T_IMPORT);
363659995Selan   int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
363759995Selan   static int import_warning = 0;
363859995Selan   char *fname;		/* Dynamically allocated fname buffer */
363959995Selan   char *pcftry;
364059995Selan   char *pcfname;
364159995Selan   U_CHAR *fbeg, *fend;		/* Beginning and end of fname */
364259995Selan 
364359995Selan   struct file_name_list *search_start = include; /* Chain of dirs to search */
364459995Selan   struct file_name_list dsp[1];	/* First in chain, if #include "..." */
364559995Selan   struct file_name_list *searchptr = 0;
364659995Selan   int flen;
364759995Selan 
364859995Selan   int f;			/* file number */
364959995Selan 
365059995Selan   int retried = 0;		/* Have already tried macro
365159995Selan 				   expanding the include line*/
365259995Selan   FILE_BUF trybuf;		/* It got expanded into here */
365359995Selan   int angle_brackets = 0;	/* 0 for "...", 1 for <...> */
365459995Selan   int pcf = -1;
365559995Selan   char *pcfbuf;
365659995Selan   int pcfbuflimit;
365759995Selan   int pcfnum;
365859995Selan   f= -1;			/* JF we iz paranoid! */
365959995Selan 
366059995Selan   if (importing && warn_import && !inhibit_warnings
366159995Selan       && !instack[indepth].system_header_p && !import_warning) {
366259995Selan     import_warning = 1;
366359995Selan     warning ("using `#import' is not recommended");
366459995Selan     fprintf (stderr, "The fact that a certain header file need not be processed more than once\n");
366559995Selan     fprintf (stderr, "should be indicated in the header file, not where it is used.\n");
366659995Selan     fprintf (stderr, "The best way to do this is with a conditional of this form:\n\n");
366759995Selan     fprintf (stderr, "  #ifndef _FOO_H_INCLUDED\n");
366859995Selan     fprintf (stderr, "  #define _FOO_H_INCLUDED\n");
366959995Selan     fprintf (stderr, "  ... <real contents of file> ...\n");
367059995Selan     fprintf (stderr, "  #endif /* Not _FOO_H_INCLUDED */\n\n");
367159995Selan     fprintf (stderr, "Then users can use `#include' any number of times.\n");
367259995Selan     fprintf (stderr, "GNU C automatically avoids processing the file more than once\n");
367359995Selan     fprintf (stderr, "when it is equipped with such a conditional.\n");
367459995Selan   }
367559995Selan 
367659995Selan get_filename:
367759995Selan 
367859995Selan   fbeg = buf;
367959995Selan   SKIP_WHITE_SPACE (fbeg);
368059995Selan   /* Discard trailing whitespace so we can easily see
368159995Selan      if we have parsed all the significant chars we were given.  */
368259995Selan   while (limit != fbeg && is_hor_space[limit[-1]]) limit--;
368359995Selan 
368459995Selan   switch (*fbeg++) {
368559995Selan   case '\"':
368659995Selan     {
368759995Selan       FILE_BUF *fp;
368859995Selan       /* Copy the operand text, concatenating the strings.  */
368959995Selan       {
369059995Selan 	U_CHAR *fin = fbeg;
369159995Selan 	fbeg = (U_CHAR *) alloca (limit - fbeg + 1);
369259995Selan 	fend = fbeg;
369359995Selan 	while (fin != limit) {
369459995Selan 	  while (fin != limit && *fin != '\"')
369559995Selan 	    *fend++ = *fin++;
369659995Selan 	  fin++;
369759995Selan 	  if (fin == limit)
369859995Selan 	    break;
369959995Selan 	  /* If not at the end, there had better be another string.  */
370059995Selan 	  /* Skip just horiz space, and don't go past limit.  */
370159995Selan 	  while (fin != limit && is_hor_space[*fin]) fin++;
370259995Selan 	  if (fin != limit && *fin == '\"')
370359995Selan 	    fin++;
370459995Selan 	  else
370559995Selan 	    goto fail;
370659995Selan 	}
370759995Selan       }
370859995Selan       *fend++ = 0;
370959995Selan 
371059995Selan       /* We have "filename".  Figure out directory this source
371159995Selan 	 file is coming from and put it on the front of the list. */
371259995Selan 
371359995Selan       /* If -I- was specified, don't search current dir, only spec'd ones. */
371459995Selan       if (ignore_srcdir) break;
371559995Selan 
371659995Selan       for (fp = &instack[indepth]; fp >= instack; fp--)
371759995Selan 	{
371859995Selan 	  int n;
371959995Selan 	  char *ep,*nam;
372059995Selan 
372159995Selan 	  if ((nam = fp->nominal_fname) != NULL) {
372259995Selan 	    /* Found a named file.  Figure out dir of the file,
372359995Selan 	       and put it in front of the search list.  */
372459995Selan 	    dsp[0].next = search_start;
372559995Selan 	    search_start = dsp;
372659995Selan #ifndef VMS
372759995Selan 	    ep = rindex (nam, '/');
372859995Selan #else				/* VMS */
372959995Selan 	    ep = rindex (nam, ']');
373059995Selan 	    if (ep == NULL) ep = rindex (nam, '>');
373159995Selan 	    if (ep == NULL) ep = rindex (nam, ':');
373259995Selan 	    if (ep != NULL) ep++;
373359995Selan #endif				/* VMS */
373459995Selan 	    if (ep != NULL) {
373559995Selan 	      n = ep - nam;
373659995Selan 	      dsp[0].fname = (char *) alloca (n + 1);
373759995Selan 	      strncpy (dsp[0].fname, nam, n);
373859995Selan 	      dsp[0].fname[n] = '\0';
373959995Selan 	      if (n + INCLUDE_LEN_FUDGE > max_include_len)
374059995Selan 		max_include_len = n + INCLUDE_LEN_FUDGE;
374159995Selan 	    } else {
374259995Selan 	      dsp[0].fname = 0; /* Current directory */
374359995Selan 	    }
374459995Selan 	    break;
374559995Selan 	  }
374659995Selan 	}
374759995Selan       break;
374859995Selan     }
374959995Selan 
375059995Selan   case '<':
375159995Selan     fend = fbeg;
375259995Selan     while (fend != limit && *fend != '>') fend++;
375359995Selan     if (*fend == '>' && fend + 1 == limit) {
375459995Selan       angle_brackets = 1;
375559995Selan       /* If -I-, start with the first -I dir after the -I-.  */
375659995Selan       if (first_bracket_include)
375759995Selan 	search_start = first_bracket_include;
375859995Selan       break;
375959995Selan     }
376059995Selan     goto fail;
376159995Selan 
376259995Selan   default:
376359995Selan   fail:
376459995Selan     if (retried) {
376559995Selan       if (importing)
376659995Selan         error ("`#import' expects \"fname\" or <fname>");
376759995Selan       else
376859995Selan         error ("`#include' expects \"fname\" or <fname>");
376959995Selan       return 0;
377059995Selan     } else {
377159995Selan       trybuf = expand_to_temp_buffer (buf, limit, 0, 0);
377259995Selan       buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
377359995Selan       bcopy (trybuf.buf, buf, trybuf.bufp - trybuf.buf);
377459995Selan       limit = buf + (trybuf.bufp - trybuf.buf);
377559995Selan       free (trybuf.buf);
377659995Selan       retried++;
377759995Selan       goto get_filename;
377859995Selan     }
377959995Selan   }
378059995Selan 
378159995Selan   /* For #include_next, skip in the search path
378259995Selan      past the dir in which the containing file was found.  */
378359995Selan   if (skip_dirs) {
378459995Selan     FILE_BUF *fp;
378559995Selan     for (fp = &instack[indepth]; fp >= instack; fp--)
378659995Selan       if (fp->fname != NULL) {
378759995Selan 	/* fp->dir is null if the containing file was specified
378859995Selan 	   with an absolute file name.  In that case, don't skip anything.  */
378959995Selan 	if (fp->dir)
379059995Selan 	  search_start = fp->dir->next;
379159995Selan 	break;
379259995Selan       }
379359995Selan   }
379459995Selan 
379559995Selan   flen = fend - fbeg;
379659995Selan   /* Allocate this permanently, because it gets stored in the definitions
379759995Selan      of macros.  */
379859995Selan   fname = (char *) xmalloc (max_include_len + flen + 2);
379959995Selan   /* + 2 above for slash and terminating null.  */
380059995Selan 
380159995Selan   /* If specified file name is absolute, just open it.  */
380259995Selan 
380359995Selan   if (*fbeg == '/') {
380459995Selan     strncpy (fname, fbeg, flen);
380559995Selan     fname[flen] = 0;
380659995Selan     if (redundant_include_p (fname))
380759995Selan       return 0;
380859995Selan     if (importing)
380959995Selan       f = lookup_import (fname);
381059995Selan     else
381159995Selan       f = open (fname, O_RDONLY, 0666);
381259995Selan     if (f == -2)
381359995Selan       return 0;		/* Already included this file */
381459995Selan   } else {
381559995Selan     /* Search directory path, trying to open the file.
381659995Selan        Copy each filename tried into FNAME.  */
381759995Selan 
381859995Selan     for (searchptr = search_start; searchptr; searchptr = searchptr->next) {
381959995Selan       if (searchptr->fname) {
382059995Selan 	/* The empty string in a search path is ignored.
382159995Selan 	   This makes it possible to turn off entirely
382259995Selan 	   a standard piece of the list.  */
382359995Selan 	if (searchptr->fname[0] == 0)
382459995Selan 	  continue;
382559995Selan 	strcpy (fname, searchptr->fname);
382659995Selan 	strcat (fname, "/");
382759995Selan 	fname[strlen (fname) + flen] = 0;
382859995Selan       } else {
382959995Selan 	fname[0] = 0;
383059995Selan       }
383159995Selan       strncat (fname, fbeg, flen);
383259995Selan #ifdef VMS
383359995Selan       /* Change this 1/2 Unix 1/2 VMS file specification into a
383459995Selan          full VMS file specification */
383559995Selan       if (searchptr->fname && (searchptr->fname[0] != 0)) {
383659995Selan 	/* Fix up the filename */
383759995Selan 	hack_vms_include_specification (fname);
383859995Selan       } else {
383959995Selan       	/* This is a normal VMS filespec, so use it unchanged.  */
384059995Selan 	strncpy (fname, fbeg, flen);
384159995Selan 	fname[flen] = 0;
384259995Selan       }
384359995Selan #endif /* VMS */
384459995Selan       if (importing)
384559995Selan 	f = lookup_import (fname);
384659995Selan       else
384759995Selan 	f = open (fname, O_RDONLY, 0666);
384859995Selan       if (f == -2)
384959995Selan 	return 0;			/* Already included this file */
385059995Selan       if (redundant_include_p (fname)) {
385159995Selan 	close (f);
385259995Selan 	return 0;
385359995Selan       }
385459995Selan       if (f >= 0)
385559995Selan 	break;
385659995Selan     }
385759995Selan   }
385859995Selan 
385959995Selan   if (f < 0) {
386059995Selan     /* A file that was not found.  */
386159995Selan 
386259995Selan     strncpy (fname, fbeg, flen);
386359995Selan     fname[flen] = 0;
386459995Selan     if (search_start)
386559995Selan       error_from_errno (fname);
386659995Selan     else
386759995Selan       error ("No include path in which to find %s", fname);
386859995Selan 
386959995Selan     /* For -M, add this file to the dependencies.  */
387059995Selan     if (print_deps > (angle_brackets || (system_include_depth > 0))) {
387159995Selan       /* Break the line before this.  */
387259995Selan       deps_output ("", 0);
387359995Selan 
387459995Selan       /* If it was requested as a system header file,
387559995Selan 	 then assume it belongs in the first place to look for such.  */
387659995Selan       if (angle_brackets) {
387759995Selan 	for (searchptr = search_start; searchptr; searchptr = searchptr->next) {
387859995Selan 	  if (searchptr->fname) {
387959995Selan 	    if (searchptr->fname[0] == 0)
388059995Selan 	      continue;
388159995Selan 	    deps_output (searchptr->fname, 0);
388259995Selan 	    deps_output ("/", 0);
388359995Selan 	    break;
388459995Selan 	  }
388559995Selan 	}
388659995Selan       }
388759995Selan       /* Otherwise, omit the directory, as if the file existed
388859995Selan 	 in the directory with the source.  */
388959995Selan       deps_output (fbeg, flen);
389059995Selan       deps_output (" ", 0);
389159995Selan     }
389259995Selan   } else {
389359995Selan     struct stat stat_f;
389459995Selan 
389559995Selan     /* Check to see if this include file is a once-only include file.
389659995Selan        If so, give up.  */
389759995Selan 
389859995Selan     struct file_name_list* ptr;
389959995Selan 
390059995Selan     for (ptr = dont_repeat_files; ptr; ptr = ptr->next) {
390159995Selan       if (!strcmp (ptr->fname, fname)) {
390259995Selan 	close (f);
390359995Selan         return 0;				/* This file was once'd. */
390459995Selan       }
390559995Selan     }
390659995Selan 
390759995Selan     for (ptr = all_include_files; ptr; ptr = ptr->next) {
390859995Selan       if (!strcmp (ptr->fname, fname))
390959995Selan         break;				/* This file was included before. */
391059995Selan     }
391159995Selan 
391259995Selan     if (ptr == 0) {
391359995Selan       /* This is the first time for this file.  */
391459995Selan       /* Add it to list of files included.  */
391559995Selan 
391659995Selan       ptr = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
391759995Selan       ptr->control_macro = 0;
391859995Selan       ptr->next = all_include_files;
391959995Selan       all_include_files = ptr;
392059995Selan       ptr->fname = savestring (fname);
392159995Selan 
392259995Selan       /* For -M, add this file to the dependencies.  */
392359995Selan       if (print_deps > (angle_brackets || (system_include_depth > 0))) {
392459995Selan 	deps_output ("", 0);
392559995Selan 	deps_output (fname, 0);
392659995Selan 	deps_output (" ", 0);
392759995Selan       }
392859995Selan     }
392959995Selan 
393059995Selan     /* Handle -H option.  */
393159995Selan     if (print_include_names)
393259995Selan       fprintf (stderr, "%s\n", fname);
393359995Selan 
393459995Selan     if (angle_brackets)
393559995Selan       system_include_depth++;
393659995Selan 
393759995Selan     /* Actually process the file.  */
393859995Selan     add_import (f, fname);	/* Record file on "seen" list for #import. */
393959995Selan 
394059995Selan     pcftry = (char *) alloca (strlen (fname) + 30);
394159995Selan     pcfbuf = 0;
394259995Selan     pcfnum = 0;
394359995Selan 
394459995Selan     fstat (f, &stat_f);
394559995Selan 
394659995Selan     if (!no_precomp)
394759995Selan       do {
394859995Selan 	sprintf (pcftry, "%s%d", fname, pcfnum++);
394959995Selan 
395059995Selan 	pcf = open (pcftry, O_RDONLY, 0666);
395159995Selan 	if (pcf != -1)
395259995Selan 	  {
395359995Selan 	    struct stat s;
395459995Selan 
395559995Selan 	    fstat (pcf, &s);
395659995Selan 	    if (bcmp (&stat_f.st_ino, &s.st_ino, sizeof (s.st_ino))
395759995Selan 		|| stat_f.st_dev != s.st_dev)
395859995Selan 	      {
395959995Selan 		pcfbuf = check_precompiled (pcf, fname, &pcfbuflimit);
396059995Selan 		/* Don't need it any more.  */
396159995Selan 		close (pcf);
396259995Selan 	      }
396359995Selan 	    else
396459995Selan 	      {
396559995Selan 		/* Don't need it at all.  */
396659995Selan 		close (pcf);
396759995Selan 		break;
396859995Selan 	      }
396959995Selan 	  }
397059995Selan       } while (pcf != -1 && !pcfbuf);
397159995Selan 
397259995Selan     /* Actually process the file */
397359995Selan     if (pcfbuf) {
397459995Selan       pcfname = xmalloc (strlen (pcftry) + 1);
397559995Selan       strcpy (pcfname, pcftry);
397659995Selan       pcfinclude (pcfbuf, pcfbuflimit, fname, op);
397759995Selan     }
397859995Selan     else
397959995Selan       finclude (f, fname, op, is_system_include (fname), searchptr);
398059995Selan 
398159995Selan     if (angle_brackets)
398259995Selan       system_include_depth--;
398359995Selan   }
398459995Selan   return 0;
398559995Selan }
398659995Selan 
398759995Selan /* Return nonzero if there is no need to include file NAME
398859995Selan    because it has already been included and it contains a conditional
398959995Selan    to make a repeated include do nothing.  */
399059995Selan 
399159995Selan static int
redundant_include_p(name)399259995Selan redundant_include_p (name)
399359995Selan      char *name;
399459995Selan {
399559995Selan   struct file_name_list *l = all_include_files;
399659995Selan   for (; l; l = l->next)
399759995Selan     if (! strcmp (name, l->fname)
399859995Selan 	&& l->control_macro
399959995Selan 	&& lookup (l->control_macro, -1, -1))
400059995Selan       return 1;
400159995Selan   return 0;
400259995Selan }
400359995Selan 
400459995Selan /* Return nonzero if the given FILENAME is an absolute pathname which
400559995Selan    designates a file within one of the known "system" include file
400659995Selan    directories.  We assume here that if the given FILENAME looks like
400759995Selan    it is the name of a file which resides either directly in a "system"
400859995Selan    include file directory, or within any subdirectory thereof, then the
400959995Selan    given file must be a "system" include file.  This function tells us
401059995Selan    if we should suppress pedantic errors/warnings for the given FILENAME.  */
401159995Selan 
401259995Selan static int
is_system_include(filename)401359995Selan is_system_include (filename)
401459995Selan     register char *filename;
401559995Selan {
401659995Selan   struct file_name_list *searchptr;
401759995Selan 
401859995Selan   for (searchptr = first_system_include; searchptr;
401959995Selan        searchptr = searchptr->next)
402059995Selan     if (searchptr->fname) {
402159995Selan       register char *sys_dir = searchptr->fname;
402259995Selan       register unsigned length = strlen (sys_dir);
402359995Selan 
402459995Selan       if (! strncmp (sys_dir, filename, length) && filename[length] == '/')
402559995Selan 	return 1;
402659995Selan     }
402759995Selan   return 0;
402859995Selan }
402959995Selan 
403059995Selan /* Process the contents of include file FNAME, already open on descriptor F,
403159995Selan    with output to OP.
403259995Selan    SYSTEM_HEADER_P is 1 if this file was specified using <...>.
403359995Selan    DIRPTR is the link in the dir path through which this file was found,
403459995Selan    or 0 if the file name was absolute.  */
403559995Selan 
403659995Selan static void
finclude(f,fname,op,system_header_p,dirptr)403759995Selan finclude (f, fname, op, system_header_p, dirptr)
403859995Selan      int f;
403959995Selan      char *fname;
404059995Selan      FILE_BUF *op;
404159995Selan      int system_header_p;
404259995Selan      struct file_name_list *dirptr;
404359995Selan {
404459995Selan   int st_mode;
404559995Selan   long st_size;
404659995Selan   long i;
404759995Selan   FILE_BUF *fp;			/* For input stack frame */
404859995Selan   int missing_newline = 0;
404959995Selan 
405059995Selan   CHECK_DEPTH (return;);
405159995Selan 
405259995Selan   if (file_size_and_mode (f, &st_mode, &st_size) < 0)
405359995Selan     {
405459995Selan       perror_with_name (fname);
405559995Selan       close (f);
405659995Selan       return;
405759995Selan     }
405859995Selan 
405959995Selan   fp = &instack[indepth + 1];
406059995Selan   bzero (fp, sizeof (FILE_BUF));
406159995Selan   fp->nominal_fname = fp->fname = fname;
406259995Selan   fp->length = 0;
406359995Selan   fp->lineno = 1;
406459995Selan   fp->if_stack = if_stack;
406559995Selan   fp->system_header_p = system_header_p;
406659995Selan   fp->dir = dirptr;
406759995Selan 
406859995Selan   if (S_ISREG (st_mode)) {
406959995Selan     fp->buf = (U_CHAR *) xmalloc (st_size + 2);
407059995Selan     fp->bufp = fp->buf;
407159995Selan 
407259995Selan     /* Read the file contents, knowing that st_size is an upper bound
407359995Selan        on the number of bytes we can read.  */
407459995Selan     while (st_size > 0) {
407559995Selan       i = read (f, fp->buf + fp->length, st_size);
407659995Selan       if (i <= 0) {
407759995Selan 	if (i == 0) break;
407859995Selan 	goto nope;
407959995Selan       }
408059995Selan       fp->length += i;
408159995Selan       st_size -= i;
408259995Selan     }
408359995Selan   }
408459995Selan   else {
408559995Selan     /* Cannot count its file size before reading.
408659995Selan        First read the entire file into heap and
408759995Selan        copy them into buffer on stack. */
408859995Selan 
408959995Selan     U_CHAR *bufp;
409059995Selan     U_CHAR *basep;
409159995Selan     int bsize = 2000;
409259995Selan 
409359995Selan     st_size = 0;
409459995Selan     basep = (U_CHAR *) xmalloc (bsize + 2);
409559995Selan     fp->buf = basep; /* So it will get freed, on error.  */
409659995Selan     bufp = basep;
409759995Selan 
409859995Selan     for (;;) {
409959995Selan       i = read (f, bufp, bsize - st_size);
410059995Selan       if (i < 0)
410159995Selan 	goto nope;      /* error! */
410259995Selan       if (i == 0)
410359995Selan 	break;	/* End of file */
410459995Selan       st_size += i;
410559995Selan       bufp += i;
410659995Selan       if (bsize == st_size) {	/* Buffer is full! */
410759995Selan 	  bsize *= 2;
410859995Selan 	  basep = (U_CHAR *) xrealloc (basep, bsize + 2);
410959995Selan 	  fp->buf = basep;
411059995Selan 	  bufp = basep + st_size;	/* May have moved */
411159995Selan 	}
411259995Selan     }
411359995Selan     fp->bufp = fp->buf;
411459995Selan     fp->length = st_size;
411559995Selan   }
411659995Selan 
411759995Selan   /* Close descriptor now, so nesting does not use lots of descriptors.  */
411859995Selan   close (f);
411959995Selan 
412059995Selan   /* Must do this before calling trigraph_pcp, so that the correct file name
412159995Selan      will be printed in warning messages.  */
412259995Selan 
412359995Selan   indepth++;
412459995Selan   input_file_stack_tick++;
412559995Selan 
412659995Selan   if (!no_trigraphs)
412759995Selan     trigraph_pcp (fp);
412859995Selan 
412959995Selan   if ((fp->length > 0 && fp->buf[fp->length - 1] != '\n')
413059995Selan       /* Backslash-newline at end is not good enough.  */
413159995Selan       || (fp->length > 1 && fp->buf[fp->length - 2] == '\\')) {
413259995Selan     fp->buf[fp->length++] = '\n';
413359995Selan     missing_newline = 1;
413459995Selan   }
413559995Selan   fp->buf[fp->length] = '\0';
413659995Selan 
413759995Selan   output_line_command (fp, op, 0, enter_file);
413859995Selan   rescan (op, 0);
413959995Selan 
414059995Selan   if (pedantic && missing_newline)
414159995Selan     pedwarn ("file does not end in newline");
414259995Selan 
414359995Selan   indepth--;
414459995Selan   input_file_stack_tick++;
414559995Selan   output_line_command (&instack[indepth], op, 0, leave_file);
414659995Selan   free (fp->buf);
414759995Selan   return;
414859995Selan 
414959995Selan  nope:
415059995Selan 
415159995Selan   perror_with_name (fname);
415259995Selan   close (f);
415359995Selan   free (fp->buf);
415459995Selan }
415559995Selan 
415659995Selan /* Record that inclusion of the file named FILE
415759995Selan    should be controlled by the macro named MACRO_NAME.
415859995Selan    This means that trying to include the file again
415959995Selan    will do something if that macro is defined.  */
416059995Selan 
416159995Selan static void
record_control_macro(file,macro_name)416259995Selan record_control_macro (file, macro_name)
416359995Selan      char *file;
416459995Selan      U_CHAR *macro_name;
416559995Selan {
416659995Selan   struct file_name_list *new;
416759995Selan 
416859995Selan   for (new = all_include_files; new; new = new->next) {
416959995Selan     if (!strcmp (new->fname, file)) {
417059995Selan       new->control_macro = macro_name;
417159995Selan       return;
417259995Selan     }
417359995Selan   }
417459995Selan 
417559995Selan   /* If the file is not in all_include_files, something's wrong.  */
417659995Selan   abort ();
417759995Selan }
417859995Selan 
417959995Selan /* Maintain and search list of included files, for #import.  */
418059995Selan 
418159995Selan #define IMPORT_HASH_SIZE 31
418259995Selan 
418359995Selan struct import_file {
418459995Selan   char *name;
418559995Selan   ino_t inode;
418659995Selan   dev_t dev;
418759995Selan   struct import_file *next;
418859995Selan };
418959995Selan 
419059995Selan /* Hash table of files already included with #include or #import.  */
419159995Selan 
419259995Selan static struct import_file *import_hash_table[IMPORT_HASH_SIZE];
419359995Selan 
419459995Selan /* Hash a file name for import_hash_table.  */
419559995Selan 
419659995Selan static int
import_hash(f)419759995Selan import_hash (f)
419859995Selan      char *f;
419959995Selan {
420059995Selan   int val = 0;
420159995Selan 
420259995Selan   while (*f) val += *f++;
420359995Selan   return (val%IMPORT_HASH_SIZE);
420459995Selan }
420559995Selan 
420659995Selan /* Search for file FILENAME in import_hash_table.
420759995Selan    Return -2 if found, either a matching name or a matching inode.
420859995Selan    Otherwise, open the file and return a file descriptor if successful
420959995Selan    or -1 if unsuccessful.  */
421059995Selan 
421159995Selan static int
lookup_import(filename)421259995Selan lookup_import (filename)
421359995Selan      char *filename;
421459995Selan {
421559995Selan   struct import_file *i;
421659995Selan   int h;
421759995Selan   int hashval;
421859995Selan   struct stat sb;
421959995Selan   int fd;
422059995Selan 
422159995Selan   hashval = import_hash (filename);
422259995Selan 
422359995Selan   /* Attempt to find file in list of already included files */
422459995Selan   i = import_hash_table[hashval];
422559995Selan 
422659995Selan   while (i) {
422759995Selan     if (!strcmp (filename, i->name))
422859995Selan       return -2;		/* return found */
422959995Selan     i = i->next;
423059995Selan   }
423159995Selan   /* Open it and try a match on inode/dev */
423259995Selan   fd = open (filename, O_RDONLY, 0666);
423359995Selan   if (fd < 0)
423459995Selan     return fd;
423559995Selan   fstat (fd, &sb);
423659995Selan   for (h = 0; h < IMPORT_HASH_SIZE; h++) {
423759995Selan     i = import_hash_table[h];
423859995Selan     while (i) {
423959995Selan       /* Compare the inode and the device.
424059995Selan 	 Supposedly on some systems the inode is not a scalar.  */
424159995Selan       if (!bcmp (&i->inode, &sb.st_ino, sizeof (sb.st_ino))
424259995Selan 	  && i->dev == sb.st_dev) {
424359995Selan         close (fd);
424459995Selan         return -2;		/* return found */
424559995Selan       }
424659995Selan       i = i->next;
424759995Selan     }
424859995Selan   }
424959995Selan   return fd;			/* Not found, return open file */
425059995Selan }
425159995Selan 
425259995Selan /* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
425359995Selan 
425459995Selan static void
add_import(fd,fname)425559995Selan add_import (fd, fname)
425659995Selan      int fd;
425759995Selan      char *fname;
425859995Selan {
425959995Selan   struct import_file *i;
426059995Selan   int hashval;
426159995Selan   struct stat sb;
426259995Selan 
426359995Selan   hashval = import_hash (fname);
426459995Selan   fstat (fd, &sb);
426559995Selan   i = (struct import_file *)xmalloc (sizeof (struct import_file));
426659995Selan   i->name = (char *)xmalloc (strlen (fname)+1);
426759995Selan   strcpy (i->name, fname);
426859995Selan   bcopy (&sb.st_ino, &i->inode, sizeof (sb.st_ino));
426959995Selan   i->dev = sb.st_dev;
427059995Selan   i->next = import_hash_table[hashval];
427159995Selan   import_hash_table[hashval] = i;
427259995Selan }
427359995Selan 
427459995Selan /* Load the specified precompiled header into core, and verify its
427559995Selan    preconditions.  PCF indicates the file descriptor to read, which must
427659995Selan    be a regular file.  FNAME indicates the file name of the original
427759995Selan    header.  *LIMIT will be set to an address one past the end of the file.
427859995Selan    If the preconditions of the file are not satisfied, the buffer is
427959995Selan    freed and we return 0.  If the preconditions are satisfied, return
428059995Selan    the address of the buffer following the preconditions.  The buffer, in
428159995Selan    this case, should never be freed because various pieces of it will
428259995Selan    be referred to until all precompiled strings are output at the end of
428359995Selan    the run.
428459995Selan */
428559995Selan static char *
check_precompiled(pcf,fname,limit)428659995Selan check_precompiled (pcf, fname, limit)
428759995Selan      int pcf;
428859995Selan      char *fname;
428959995Selan      char **limit;
429059995Selan {
429159995Selan   int st_mode;
429259995Selan   long st_size;
429359995Selan   int length = 0;
429459995Selan   char *buf;
429559995Selan   char *dollar_loc;
429659995Selan   int i;
429759995Selan   char *cp;
429859995Selan 
429959995Selan   if (pcp_outfile)
430059995Selan     return 0;
430159995Selan 
430259995Selan   if (file_size_and_mode (pcf, &st_mode, &st_size) < 0)
430359995Selan     return 0;
430459995Selan 
430559995Selan   if (S_ISREG (st_mode))
430659995Selan     {
430759995Selan       buf = xmalloc (st_size + 2);
430859995Selan       while (st_size > 0)
430959995Selan 	{
431059995Selan 	  i = read (pcf, buf + length, st_size);
431159995Selan 	  if (i < 0)
431259995Selan 	    goto nope;
431359995Selan 	  if (i == 0)
431459995Selan 	    break;
431559995Selan 	  length += i;
431659995Selan 	  st_size -= i;
431759995Selan 	}
431859995Selan     }
431959995Selan   else
432059995Selan     abort ();
432159995Selan 
432259995Selan   if (length > 0 && buf[length-1] != '\n')
432359995Selan     buf[length++] = '\n';
432459995Selan   buf[length] = '\0';
432559995Selan 
432659995Selan   *limit = buf + length;
432759995Selan 
432859995Selan   /* File is in core.  Check the preconditions. */
432959995Selan   if (!check_preconditions (buf))
433059995Selan     goto nope;
433159995Selan   for (cp = buf; *cp; cp++)
433259995Selan     ;
433359995Selan #ifdef DEBUG_PCP
433459995Selan   fprintf (stderr, "Using preinclude %s\n", fname);
433559995Selan #endif
433659995Selan   return cp + 1;
433759995Selan 
433859995Selan  nope:
433959995Selan #ifdef DEBUG_PCP
434059995Selan   fprintf (stderr, "Cannot use preinclude %s\n", fname);
434159995Selan #endif
434259995Selan   free (buf);
434359995Selan   return 0;
434459995Selan }
434559995Selan 
434659995Selan /* PREC (null terminated) points to the preconditions of a
434759995Selan    precompiled header.  These are a series of #define and #undef
434859995Selan    lines which must match the current contents of the hash
434959995Selan    table.  */
435059995Selan static int
check_preconditions(prec)435159995Selan check_preconditions (prec)
435259995Selan      char *prec;
435359995Selan {
435459995Selan   MACRODEF mdef;
435559995Selan   char *lineend;
435659995Selan 
435759995Selan   while (*prec) {
435859995Selan     lineend = (char *) index (prec, '\n');
435959995Selan 
436059995Selan     if (*prec++ != '#') {
436159995Selan       error ("Bad format encountered while reading precompiled file");
436259995Selan       return 0;
436359995Selan     }
436459995Selan     if (!strncmp (prec, "define", 6)) {
436559995Selan       HASHNODE *hp;
436659995Selan 
436759995Selan       prec += 6;
436859995Selan       mdef = create_definition (prec, lineend, NULL_PTR);
436959995Selan 
437059995Selan       if (mdef.defn == 0)
437159995Selan 	abort();
437259995Selan 
437359995Selan       if ((hp = lookup (mdef.symnam, mdef.symlen, -1)) == NULL
437459995Selan 	  || (hp->type != T_MACRO && hp->type != T_CONST)
437559995Selan 	  || (hp->type == T_MACRO
437659995Selan 	      && !compare_defs (mdef.defn, hp->value.defn)
437759995Selan 	      && (mdef.defn->length != 2
437859995Selan 		  || mdef.defn->expansion[0] != '\n'
437959995Selan 		  || mdef.defn->expansion[1] != ' ')))
438059995Selan 	return 0;
438159995Selan     } else if (!strncmp (prec, "undef", 5)) {
438259995Selan       char *name;
438359995Selan       int len;
438459995Selan 
438559995Selan       prec += 5;
438659995Selan       while (is_hor_space[*prec])
438759995Selan 	prec++;
438859995Selan       name = prec;
438959995Selan       while (is_idchar[*prec])
439059995Selan 	prec++;
439159995Selan       len = prec - name;
439259995Selan 
439359995Selan       if (lookup (name, len, -1))
439459995Selan 	return 0;
439559995Selan     } else {
439659995Selan       error ("Bad format encountered while reading precompiled file");
439759995Selan       return 0;
439859995Selan     }
439959995Selan     prec = lineend + 1;
440059995Selan   }
440159995Selan   /* They all passed successfully */
440259995Selan   return 1;
440359995Selan }
440459995Selan 
440559995Selan /* Process the main body of a precompiled file.  BUF points to the
440659995Selan    string section of the file, following the preconditions.  LIMIT is one
440759995Selan    character past the end.  NAME is the name of the file being read
440859995Selan    in.  OP is the main output buffer */
440959995Selan static void
pcfinclude(buf,limit,name,op)441059995Selan pcfinclude (buf, limit, name, op)
441159995Selan      U_CHAR *buf, *limit, *name;
441259995Selan      FILE_BUF *op;
441359995Selan {
441459995Selan   FILE_BUF tmpbuf;
441559995Selan   int nstrings;
441659995Selan   U_CHAR *cp = buf;
441759995Selan 
441859995Selan   /* First in the file comes 4 bytes indicating the number of strings, */
441959995Selan   /* in network byte order. (MSB first).  */
442059995Selan   nstrings = *cp++;
442159995Selan   nstrings = (nstrings << 8) | *cp++;
442259995Selan   nstrings = (nstrings << 8) | *cp++;
442359995Selan   nstrings = (nstrings << 8) | *cp++;
442459995Selan 
442559995Selan   /* Looping over each string... */
442659995Selan   while (nstrings--) {
442759995Selan     U_CHAR *string_start;
442859995Selan     U_CHAR *endofthiskey;
442959995Selan     STRINGDEF *str;
443059995Selan     int nkeys;
443159995Selan 
443259995Selan     /* Each string starts with a STRINGDEF structure (str), followed */
443359995Selan     /* by the text of the string (string_start) */
443459995Selan 
443559995Selan     /* First skip to a longword boundary */
443659995Selan     /* ??? Why a 4-byte boundary?  On all machines? */
443759995Selan     /* NOTE: This works correctly even if HOST_WIDE_INT
443859995Selan        is narrower than a pointer.
443959995Selan        Do not try risky measures here to get another type to use!
444059995Selan        Do not include gstddef.h or stddef.h--either one will fail!  */
444159995Selan     if ((HOST_WIDE_INT) cp & 3)
444259995Selan       cp += 4 - ((HOST_WIDE_INT) cp & 3);
444359995Selan 
444459995Selan     /* Now get the string. */
444559995Selan     str = (STRINGDEF *) cp;
444659995Selan     string_start = cp += sizeof (STRINGDEF);
444759995Selan 
444859995Selan     for (; *cp; cp++)		/* skip the string */
444959995Selan       ;
445059995Selan 
445159995Selan     /* We need to macro expand the string here to ensure that the
445259995Selan        proper definition environment is in place.  If it were only
445359995Selan        expanded when we find out it is needed, macros necessary for
445459995Selan        its proper expansion might have had their definitions changed. */
445559995Selan     tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0);
445659995Selan     /* Lineno is already set in the precompiled file */
445759995Selan     str->contents = tmpbuf.buf;
445859995Selan     str->len = tmpbuf.length;
445959995Selan     str->writeflag = 0;
446059995Selan     str->filename = name;
446159995Selan     str->output_mark = outbuf.bufp - outbuf.buf;
446259995Selan 
446359995Selan     str->chain = 0;
446459995Selan     *stringlist_tailp = str;
446559995Selan     stringlist_tailp = &str->chain;
446659995Selan 
446759995Selan     /* Next comes a fourbyte number indicating the number of keys */
446859995Selan     /* for this string. */
446959995Selan     nkeys = *cp++;
447059995Selan     nkeys = (nkeys << 8) | *cp++;
447159995Selan     nkeys = (nkeys << 8) | *cp++;
447259995Selan     nkeys = (nkeys << 8) | *cp++;
447359995Selan 
447459995Selan     /* If this number is -1, then the string is mandatory. */
447559995Selan     if (nkeys == -1)
447659995Selan       str->writeflag = 1;
447759995Selan     else
447859995Selan       /* Otherwise, for each key, */
447959995Selan       for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) {
448059995Selan 	KEYDEF *kp = (KEYDEF *) cp;
448159995Selan 	HASHNODE *hp;
448259995Selan 
448359995Selan 	/* It starts with a KEYDEF structure */
448459995Selan 	cp += sizeof (KEYDEF);
448559995Selan 
448659995Selan 	/* Find the end of the key.  At the end of this for loop we
448759995Selan 	   advance CP to the start of the next key using this variable. */
448859995Selan 	endofthiskey = cp + strlen (cp);
448959995Selan 	kp->str = str;
449059995Selan 
449159995Selan 	/* Expand the key, and enter it into the hash table. */
449259995Selan 	tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0);
449359995Selan 	tmpbuf.bufp = tmpbuf.buf;
449459995Selan 
449559995Selan 	while (is_hor_space[*tmpbuf.bufp])
449659995Selan 	  tmpbuf.bufp++;
449759995Selan 	if (!is_idstart[*tmpbuf.bufp]
449859995Selan 	    || tmpbuf.bufp == tmpbuf.buf + tmpbuf.length) {
449959995Selan 	  str->writeflag = 1;
450059995Selan 	  continue;
450159995Selan 	}
450259995Selan 
450359995Selan 	hp = lookup (tmpbuf.bufp, -1, -1);
450459995Selan 	if (hp == NULL) {
450559995Selan 	  kp->chain = 0;
450659995Selan 	  install (tmpbuf.bufp, -1, T_PCSTRING, 0, (char *) kp, -1);
450759995Selan 	}
450859995Selan 	else if (hp->type == T_PCSTRING) {
450959995Selan 	  kp->chain = hp->value.keydef;
451059995Selan 	  hp->value.keydef = kp;
451159995Selan 	}
451259995Selan 	else
451359995Selan 	  str->writeflag = 1;
451459995Selan       }
451559995Selan   }
451659995Selan   /* This output_line_command serves to switch us back to the current
451759995Selan      input file in case some of these strings get output (which will
451859995Selan      result in line commands for the header file being output). */
451959995Selan   output_line_command (&instack[indepth], op, 0, enter_file);
452059995Selan }
452159995Selan 
452259995Selan /* Called from rescan when it hits a key for strings.  Mark them all */
452359995Selan  /* used and clean up. */
452459995Selan static void
pcstring_used(hp)452559995Selan pcstring_used (hp)
452659995Selan      HASHNODE *hp;
452759995Selan {
452859995Selan   KEYDEF *kp, *tmp;
452959995Selan 
453059995Selan   for (kp = hp->value.keydef; kp; kp = kp->chain)
453159995Selan     kp->str->writeflag = 1;
453259995Selan   delete_macro (hp);
453359995Selan }
453459995Selan 
453559995Selan /* Write the output, interspersing precompiled strings in their */
453659995Selan  /* appropriate places. */
453759995Selan static void
write_output()453859995Selan write_output ()
453959995Selan {
454059995Selan   STRINGDEF *next_string;
454159995Selan   U_CHAR *cur_buf_loc;
454259995Selan   int line_command_len = 80;
454359995Selan   char *line_command = xmalloc (line_command_len);
454459995Selan   int len;
454559995Selan 
454659995Selan   /* In each run through the loop, either cur_buf_loc == */
454759995Selan   /* next_string_loc, in which case we print a series of strings, or */
454859995Selan   /* it is less than next_string_loc, in which case we write some of */
454959995Selan   /* the buffer. */
455059995Selan   cur_buf_loc = outbuf.buf;
455159995Selan   next_string = stringlist;
455259995Selan 
455359995Selan   while (cur_buf_loc < outbuf.bufp || next_string) {
455459995Selan     if (next_string
455559995Selan 	&& cur_buf_loc - outbuf.buf == next_string->output_mark) {
455659995Selan       if (next_string->writeflag) {
455759995Selan 	len = strlen (next_string->filename);
455859995Selan 	if (len > line_command_len)
455959995Selan 	  line_command = xrealloc (line_command,
456059995Selan 				   line_command_len *= 2);
456159995Selan 	sprintf (line_command, "\n# %d \"%s\"\n",
456259995Selan 		 next_string->lineno, next_string->filename);
456359995Selan 	write (fileno (stdout), line_command,
456459995Selan 	       strlen (line_command));
456559995Selan 	write (fileno (stdout),
456659995Selan 	       next_string->contents, next_string->len);
456759995Selan       }
456859995Selan       next_string = next_string->chain;
456959995Selan     }
457059995Selan     else {
457159995Selan       len = (next_string
457259995Selan 	     ? (next_string->output_mark
457359995Selan 		- (cur_buf_loc - outbuf.buf))
457459995Selan 	     : outbuf.bufp - cur_buf_loc);
457559995Selan 
457659995Selan       write (fileno (stdout), cur_buf_loc, len);
457759995Selan       cur_buf_loc += len;
457859995Selan     }
457959995Selan   }
458059995Selan }
458159995Selan 
458259995Selan /* Pass a directive through to the output file.
458359995Selan    BUF points to the contents of the directive, as a contiguous string.
458459995Selan    LIMIT points to the first character past the end of the directive.
458559995Selan    KEYWORD is the keyword-table entry for the directive.  */
458659995Selan 
458759995Selan static void
pass_thru_directive(buf,limit,op,keyword)458859995Selan pass_thru_directive (buf, limit, op, keyword)
458959995Selan      U_CHAR *buf, *limit;
459059995Selan      FILE_BUF *op;
459159995Selan      struct directive *keyword;
459259995Selan {
459359995Selan   register unsigned keyword_length = keyword->length;
459459995Selan 
459559995Selan   check_expand (op, 1 + keyword_length + (limit - buf));
459659995Selan   *op->bufp++ = '#';
459759995Selan   bcopy (keyword->name, op->bufp, keyword_length);
459859995Selan   op->bufp += keyword_length;
459959995Selan   if (limit != buf && buf[0] != ' ')
460059995Selan     *op->bufp++ = ' ';
460159995Selan   bcopy (buf, op->bufp, limit - buf);
460259995Selan   op->bufp += (limit - buf);
460359995Selan #if 0
460459995Selan   *op->bufp++ = '\n';
460559995Selan   /* Count the line we have just made in the output,
460659995Selan      to get in sync properly.  */
460759995Selan   op->lineno++;
460859995Selan #endif
460959995Selan }
461059995Selan 
461159995Selan /* The arglist structure is built by do_define to tell
461259995Selan    collect_definition where the argument names begin.  That
461359995Selan    is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
461459995Selan    would contain pointers to the strings x, y, and z.
461559995Selan    Collect_definition would then build a DEFINITION node,
461659995Selan    with reflist nodes pointing to the places x, y, and z had
461759995Selan    appeared.  So the arglist is just convenience data passed
461859995Selan    between these two routines.  It is not kept around after
461959995Selan    the current #define has been processed and entered into the
462059995Selan    hash table. */
462159995Selan 
462259995Selan struct arglist {
462359995Selan   struct arglist *next;
462459995Selan   U_CHAR *name;
462559995Selan   int length;
462659995Selan   int argno;
462759995Selan   char rest_args;
462859995Selan };
462959995Selan 
463059995Selan /* Create a DEFINITION node from a #define directive.  Arguments are
463159995Selan    as for do_define. */
463259995Selan static MACRODEF
create_definition(buf,limit,op)463359995Selan create_definition (buf, limit, op)
463459995Selan      U_CHAR *buf, *limit;
463559995Selan      FILE_BUF *op;
463659995Selan {
463759995Selan   U_CHAR *bp;			/* temp ptr into input buffer */
463859995Selan   U_CHAR *symname;		/* remember where symbol name starts */
463959995Selan   int sym_length;		/* and how long it is */
464059995Selan   int line = instack[indepth].lineno;
464159995Selan   char *file = instack[indepth].nominal_fname;
464259995Selan   int rest_args = 0;
464359995Selan 
464459995Selan   DEFINITION *defn;
464559995Selan   int arglengths = 0;		/* Accumulate lengths of arg names
464659995Selan 				   plus number of args.  */
464759995Selan   MACRODEF mdef;
464859995Selan 
464959995Selan   bp = buf;
465059995Selan 
465159995Selan   while (is_hor_space[*bp])
465259995Selan     bp++;
465359995Selan 
465459995Selan   symname = bp;			/* remember where it starts */
465559995Selan   sym_length = check_macro_name (bp, "macro");
465659995Selan   bp += sym_length;
465759995Selan 
465859995Selan   /* Lossage will occur if identifiers or control keywords are broken
465959995Selan      across lines using backslash.  This is not the right place to take
466059995Selan      care of that. */
466159995Selan 
466259995Selan   if (*bp == '(') {
466359995Selan     struct arglist *arg_ptrs = NULL;
466459995Selan     int argno = 0;
466559995Selan 
466659995Selan     bp++;			/* skip '(' */
466759995Selan     SKIP_WHITE_SPACE (bp);
466859995Selan 
466959995Selan     /* Loop over macro argument names.  */
467059995Selan     while (*bp != ')') {
467159995Selan       struct arglist *temp;
467259995Selan 
467359995Selan       temp = (struct arglist *) alloca (sizeof (struct arglist));
467459995Selan       temp->name = bp;
467559995Selan       temp->next = arg_ptrs;
467659995Selan       temp->argno = argno++;
467759995Selan       temp->rest_args = 0;
467859995Selan       arg_ptrs = temp;
467959995Selan 
468059995Selan       if (rest_args)
468159995Selan 	pedwarn ("another parameter follows `%s'",
468259995Selan 		 rest_extension);
468359995Selan 
468459995Selan       if (!is_idstart[*bp])
468559995Selan 	pedwarn ("invalid character in macro parameter name");
468659995Selan 
468759995Selan       /* Find the end of the arg name.  */
468859995Selan       while (is_idchar[*bp]) {
468959995Selan 	bp++;
469059995Selan 	/* do we have a "special" rest-args extension here? */
469159995Selan 	if (limit - bp > REST_EXTENSION_LENGTH &&
469259995Selan 	    strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
469359995Selan 	  rest_args = 1;
469459995Selan 	  temp->rest_args = 1;
469559995Selan 	  break;
469659995Selan 	}
469759995Selan       }
469859995Selan       temp->length = bp - temp->name;
469959995Selan       if (rest_args == 1)
470059995Selan 	bp += REST_EXTENSION_LENGTH;
470159995Selan       arglengths += temp->length + 2;
470259995Selan       SKIP_WHITE_SPACE (bp);
470359995Selan       if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
470459995Selan 	error ("badly punctuated parameter list in `#define'");
470559995Selan 	goto nope;
470659995Selan       }
470759995Selan       if (*bp == ',') {
470859995Selan 	bp++;
470959995Selan 	SKIP_WHITE_SPACE (bp);
471059995Selan       }
471159995Selan       if (bp >= limit) {
471259995Selan 	error ("unterminated parameter list in `#define'");
471359995Selan 	goto nope;
471459995Selan       }
471559995Selan       {
471659995Selan 	struct arglist *otemp;
471759995Selan 
471859995Selan 	for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
471959995Selan 	  if (temp->length == otemp->length &&
472059995Selan 	    strncmp(temp->name, otemp->name, temp->length) == 0) {
472159995Selan 	      U_CHAR *name;
472259995Selan 
472359995Selan 	      name = (U_CHAR *) alloca(temp->length + 1);
472459995Selan 	      (void) strncpy(name, temp->name, temp->length);
472559995Selan 	      name[temp->length] = '\0';
472659995Selan 	      error ("duplicate argument name `%s' in `#define'", name);
472759995Selan 	      goto nope;
472859995Selan 	  }
472959995Selan       }
473059995Selan     }
473159995Selan 
473259995Selan     ++bp;			/* skip paren */
473359995Selan     /* Skip exactly one space or tab if any.  */
473459995Selan     if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp;
473559995Selan     /* now everything from bp before limit is the definition. */
473659995Selan     defn = collect_expansion (bp, limit, argno, arg_ptrs);
473759995Selan     defn->rest_args = rest_args;
473859995Selan 
473959995Selan     /* Now set defn->args.argnames to the result of concatenating
474059995Selan        the argument names in reverse order
474159995Selan        with comma-space between them.  */
474259995Selan     defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1);
474359995Selan     {
474459995Selan       struct arglist *temp;
474559995Selan       int i = 0;
474659995Selan       for (temp = arg_ptrs; temp; temp = temp->next) {
474759995Selan 	bcopy (temp->name, &defn->args.argnames[i], temp->length);
474859995Selan 	i += temp->length;
474959995Selan 	if (temp->next != 0) {
475059995Selan 	  defn->args.argnames[i++] = ',';
475159995Selan 	  defn->args.argnames[i++] = ' ';
475259995Selan 	}
475359995Selan       }
475459995Selan       defn->args.argnames[i] = 0;
475559995Selan     }
475659995Selan   } else {
475759995Selan     /* simple expansion or empty definition; gobble it */
475859995Selan     if (is_hor_space[*bp])
475959995Selan       ++bp;		/* skip exactly one blank/tab char */
476059995Selan     /* now everything from bp before limit is the definition. */
476159995Selan     defn = collect_expansion (bp, limit, -1, NULL_PTR);
476259995Selan     defn->args.argnames = (U_CHAR *) "";
476359995Selan   }
476459995Selan 
476559995Selan   defn->line = line;
476659995Selan   defn->file = file;
476759995Selan 
476859995Selan   /* OP is null if this is a predefinition */
476959995Selan   defn->predefined = !op;
477059995Selan   mdef.defn = defn;
477159995Selan   mdef.symnam = symname;
477259995Selan   mdef.symlen = sym_length;
477359995Selan 
477459995Selan   return mdef;
477559995Selan 
477659995Selan  nope:
477759995Selan   mdef.defn = 0;
477859995Selan   return mdef;
477959995Selan }
478059995Selan 
478159995Selan /* Process a #define command.
478259995Selan BUF points to the contents of the #define command, as a contiguous string.
478359995Selan LIMIT points to the first character past the end of the definition.
478459995Selan KEYWORD is the keyword-table entry for #define.  */
478559995Selan 
478659995Selan static int
do_define(buf,limit,op,keyword)478759995Selan do_define (buf, limit, op, keyword)
478859995Selan      U_CHAR *buf, *limit;
478959995Selan      FILE_BUF *op;
479059995Selan      struct directive *keyword;
479159995Selan {
479259995Selan   int hashcode;
479359995Selan   MACRODEF mdef;
479459995Selan 
479559995Selan   /* If this is a precompiler run (with -pcp) pass thru #define commands.  */
479659995Selan   if (pcp_outfile && op)
479759995Selan     pass_thru_directive (buf, limit, op, keyword);
479859995Selan 
479959995Selan   mdef = create_definition (buf, limit, op);
480059995Selan   if (mdef.defn == 0)
480159995Selan     goto nope;
480259995Selan 
480359995Selan   hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE);
480459995Selan 
480559995Selan   {
480659995Selan     HASHNODE *hp;
480759995Selan     if ((hp = lookup (mdef.symnam, mdef.symlen, hashcode)) != NULL) {
480859995Selan       int ok = 0;
480959995Selan       /* Redefining a precompiled key is ok.  */
481059995Selan       if (hp->type == T_PCSTRING)
481159995Selan 	ok = 1;
481259995Selan       /* Redefining a macro is ok if the definitions are the same.  */
481359995Selan       else if (hp->type == T_MACRO)
481459995Selan 	ok = ! compare_defs (mdef.defn, hp->value.defn);
481559995Selan       /* Redefining a constant is ok with -D.  */
481659995Selan       else if (hp->type == T_CONST)
481759995Selan         ok = ! done_initializing;
481859995Selan       /* Print the warning if it's not ok.  */
481959995Selan       if (!ok) {
482059995Selan 	U_CHAR *msg;		/* what pain... */
482159995Selan 
482259995Selan         /* If we are passing through #define and #undef directives, do
482359995Selan 	   that for this re-definition now.  */
482459995Selan         if (debug_output && op)
482559995Selan 	  pass_thru_directive (buf, limit, op, keyword);
482659995Selan 
482759995Selan 	msg = (U_CHAR *) alloca (mdef.symlen + 22);
482859995Selan 	*msg = '`';
482959995Selan 	bcopy (mdef.symnam, msg + 1, mdef.symlen);
483059995Selan 	strcpy ((char *) (msg + mdef.symlen + 1), "' redefined");
483159995Selan 	pedwarn (msg);
483259995Selan 	if (hp->type == T_MACRO)
483359995Selan 	  pedwarn_with_file_and_line (hp->value.defn->file, hp->value.defn->line,
483459995Selan 				      "this is the location of the previous definition");
483559995Selan       }
483659995Selan       /* Replace the old definition.  */
483759995Selan       hp->type = T_MACRO;
483859995Selan       hp->value.defn = mdef.defn;
483959995Selan     } else {
484059995Selan       /* If we are passing through #define and #undef directives, do
484159995Selan 	 that for this new definition now.  */
484259995Selan       if (debug_output && op)
484359995Selan 	pass_thru_directive (buf, limit, op, keyword);
484459995Selan       install (mdef.symnam, mdef.symlen, T_MACRO, 0,
484559995Selan 	       (char *) mdef.defn, hashcode);
484659995Selan     }
484759995Selan   }
484859995Selan 
484959995Selan   return 0;
485059995Selan 
485159995Selan nope:
485259995Selan 
485359995Selan   return 1;
485459995Selan }
485559995Selan 
485659995Selan /* Check a purported macro name SYMNAME, and yield its length.
485759995Selan    USAGE is the kind of name this is intended for.  */
485859995Selan 
485959995Selan static int
check_macro_name(symname,usage)486059995Selan check_macro_name (symname, usage)
486159995Selan      U_CHAR *symname;
486259995Selan      char *usage;
486359995Selan {
486459995Selan   U_CHAR *p;
486559995Selan   int sym_length;
486659995Selan 
486759995Selan   for (p = symname; is_idchar[*p]; p++)
486859995Selan     ;
486959995Selan   sym_length = p - symname;
487059995Selan   if (sym_length == 0)
487159995Selan     error ("invalid %s name", usage);
487259995Selan   else if (!is_idstart[*symname]) {
487359995Selan     U_CHAR *msg;			/* what pain... */
487459995Selan     msg = (U_CHAR *) alloca (sym_length + 1);
487559995Selan     bcopy (symname, msg, sym_length);
487659995Selan     msg[sym_length] = 0;
487759995Selan     error ("invalid %s name `%s'", usage, msg);
487859995Selan   } else {
487959995Selan     if (! strncmp (symname, "defined", 7) && sym_length == 7)
488059995Selan       error ("invalid %s name `defined'", usage);
488159995Selan   }
488259995Selan   return sym_length;
488359995Selan }
488459995Selan 
488559995Selan /*
488659995Selan  * return zero if two DEFINITIONs are isomorphic
488759995Selan  */
488859995Selan static int
compare_defs(d1,d2)488959995Selan compare_defs (d1, d2)
489059995Selan      DEFINITION *d1, *d2;
489159995Selan {
489259995Selan   register struct reflist *a1, *a2;
489359995Selan   register U_CHAR *p1 = d1->expansion;
489459995Selan   register U_CHAR *p2 = d2->expansion;
489559995Selan   int first = 1;
489659995Selan 
489759995Selan   if (d1->nargs != d2->nargs)
489859995Selan     return 1;
489959995Selan   if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
490059995Selan     return 1;
490159995Selan   for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
490259995Selan        a1 = a1->next, a2 = a2->next) {
490359995Selan     if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars))
490459995Selan 	  || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
490559995Selan 	|| a1->argno != a2->argno
490659995Selan 	|| a1->stringify != a2->stringify
490759995Selan 	|| a1->raw_before != a2->raw_before
490859995Selan 	|| a1->raw_after != a2->raw_after)
490959995Selan       return 1;
491059995Selan     first = 0;
491159995Selan     p1 += a1->nchars;
491259995Selan     p2 += a2->nchars;
491359995Selan   }
491459995Selan   if (a1 != a2)
491559995Selan     return 1;
491659995Selan   if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
491759995Selan 		     p2, d2->length - (p2 - d2->expansion), 1))
491859995Selan     return 1;
491959995Selan   return 0;
492059995Selan }
492159995Selan 
492259995Selan /* Return 1 if two parts of two macro definitions are effectively different.
492359995Selan    One of the parts starts at BEG1 and has LEN1 chars;
492459995Selan    the other has LEN2 chars at BEG2.
492559995Selan    Any sequence of whitespace matches any other sequence of whitespace.
492659995Selan    FIRST means these parts are the first of a macro definition;
492759995Selan     so ignore leading whitespace entirely.
492859995Selan    LAST means these parts are the last of a macro definition;
492959995Selan     so ignore trailing whitespace entirely.  */
493059995Selan 
493159995Selan static int
comp_def_part(first,beg1,len1,beg2,len2,last)493259995Selan comp_def_part (first, beg1, len1, beg2, len2, last)
493359995Selan      int first;
493459995Selan      U_CHAR *beg1, *beg2;
493559995Selan      int len1, len2;
493659995Selan      int last;
493759995Selan {
493859995Selan   register U_CHAR *end1 = beg1 + len1;
493959995Selan   register U_CHAR *end2 = beg2 + len2;
494059995Selan   if (first) {
494159995Selan     while (beg1 != end1 && is_space[*beg1]) beg1++;
494259995Selan     while (beg2 != end2 && is_space[*beg2]) beg2++;
494359995Selan   }
494459995Selan   if (last) {
494559995Selan     while (beg1 != end1 && is_space[end1[-1]]) end1--;
494659995Selan     while (beg2 != end2 && is_space[end2[-1]]) end2--;
494759995Selan   }
494859995Selan   while (beg1 != end1 && beg2 != end2) {
494959995Selan     if (is_space[*beg1] && is_space[*beg2]) {
495059995Selan       while (beg1 != end1 && is_space[*beg1]) beg1++;
495159995Selan       while (beg2 != end2 && is_space[*beg2]) beg2++;
495259995Selan     } else if (*beg1 == *beg2) {
495359995Selan       beg1++; beg2++;
495459995Selan     } else break;
495559995Selan   }
495659995Selan   return (beg1 != end1) || (beg2 != end2);
495759995Selan }
495859995Selan 
495959995Selan /* Read a replacement list for a macro with parameters.
496059995Selan    Build the DEFINITION structure.
496159995Selan    Reads characters of text starting at BUF until END.
496259995Selan    ARGLIST specifies the formal parameters to look for
496359995Selan    in the text of the definition; NARGS is the number of args
496459995Selan    in that list, or -1 for a macro name that wants no argument list.
496559995Selan    MACRONAME is the macro name itself (so we can avoid recursive expansion)
496659995Selan    and NAMELEN is its length in characters.
496759995Selan 
496859995Selan Note that comments and backslash-newlines have already been deleted
496959995Selan from the argument.  */
497059995Selan 
497159995Selan /* Leading and trailing Space, Tab, etc. are converted to markers
497259995Selan    Newline Space, Newline Tab, etc.
497359995Selan    Newline Space makes a space in the final output
497459995Selan    but is discarded if stringified.  (Newline Tab is similar but
497559995Selan    makes a Tab instead.)
497659995Selan 
497759995Selan    If there is no trailing whitespace, a Newline Space is added at the end
497859995Selan    to prevent concatenation that would be contrary to the standard.  */
497959995Selan 
498059995Selan static DEFINITION *
collect_expansion(buf,end,nargs,arglist)498159995Selan collect_expansion (buf, end, nargs, arglist)
498259995Selan      U_CHAR *buf, *end;
498359995Selan      int nargs;
498459995Selan      struct arglist *arglist;
498559995Selan {
498659995Selan   DEFINITION *defn;
498759995Selan   register U_CHAR *p, *limit, *lastp, *exp_p;
498859995Selan   struct reflist *endpat = NULL;
498959995Selan   /* Pointer to first nonspace after last ## seen.  */
499059995Selan   U_CHAR *concat = 0;
499159995Selan   /* Pointer to first nonspace after last single-# seen.  */
499259995Selan   U_CHAR *stringify = 0;
499359995Selan   int maxsize;
499459995Selan   int expected_delimiter = '\0';
499559995Selan 
499659995Selan   /* Scan thru the replacement list, ignoring comments and quoted
499759995Selan      strings, picking up on the macro calls.  It does a linear search
499859995Selan      thru the arg list on every potential symbol.  Profiling might say
499959995Selan      that something smarter should happen. */
500059995Selan 
500159995Selan   if (end < buf)
500259995Selan     abort ();
500359995Selan 
500459995Selan   /* Find the beginning of the trailing whitespace.  */
500559995Selan   /* Find end of leading whitespace.  */
500659995Selan   limit = end;
500759995Selan   p = buf;
500859995Selan   while (p < limit && is_space[limit[-1]]) limit--;
500959995Selan   while (p < limit && is_space[*p]) p++;
501059995Selan 
501159995Selan   /* Allocate space for the text in the macro definition.
501259995Selan      Leading and trailing whitespace chars need 2 bytes each.
501359995Selan      Each other input char may or may not need 1 byte,
501459995Selan      so this is an upper bound.
501559995Selan      The extra 2 are for invented trailing newline-marker and final null.  */
501659995Selan   maxsize = (sizeof (DEFINITION)
501759995Selan 	     + 2 * (end - limit) + 2 * (p - buf)
501859995Selan 	     + (limit - p) + 3);
501959995Selan   defn = (DEFINITION *) xcalloc (1, maxsize);
502059995Selan 
502159995Selan   defn->nargs = nargs;
502259995Selan   exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION);
502359995Selan   lastp = exp_p;
502459995Selan 
502559995Selan   p = buf;
502659995Selan 
502759995Selan   /* Convert leading whitespace to Newline-markers.  */
502859995Selan   while (p < limit && is_space[*p]) {
502959995Selan     *exp_p++ = '\n';
503059995Selan     *exp_p++ = *p++;
503159995Selan   }
503259995Selan 
503359995Selan   if (limit - p >= 2 && p[0] == '#' && p[1] == '#') {
503459995Selan     error ("`##' at start of macro definition");
503559995Selan     p += 2;
503659995Selan   }
503759995Selan 
503859995Selan   /* Process the main body of the definition.  */
503959995Selan   while (p < limit) {
504059995Selan     int skipped_arg = 0;
504159995Selan     register U_CHAR c = *p++;
504259995Selan 
504359995Selan     *exp_p++ = c;
504459995Selan 
504559995Selan     if (!traditional) {
504659995Selan       switch (c) {
504759995Selan       case '\'':
504859995Selan       case '\"':
504959995Selan         if (expected_delimiter != '\0') {
505059995Selan           if (c == expected_delimiter)
505159995Selan             expected_delimiter = '\0';
505259995Selan         } else
505359995Selan           expected_delimiter = c;
505459995Selan 	break;
505559995Selan 
505659995Selan 	/* Special hack: if a \# is written in the #define
505759995Selan 	   include a # in the definition.  This is useless for C code
505859995Selan 	   but useful for preprocessing other things.  */
505959995Selan 
506059995Selan       case '\\':
506159995Selan 	/* \# quotes a # even outside of strings.  */
506259995Selan 	if (p < limit && *p == '#' && !expected_delimiter) {
506359995Selan 	  exp_p--;
506459995Selan 	  *exp_p++ = *p++;
506559995Selan 	} else if (p < limit && expected_delimiter) {
506659995Selan 	  /* In a string, backslash goes through
506759995Selan 	     and makes next char ordinary.  */
506859995Selan 	  *exp_p++ = *p++;
506959995Selan 	}
507059995Selan 	break;
507159995Selan 
507259995Selan       case '#':
507359995Selan 	/* # is ordinary inside a string.  */
507459995Selan 	if (expected_delimiter)
507559995Selan 	  break;
507659995Selan 	if (p < limit && *p == '#') {
507759995Selan 	  /* ##: concatenate preceding and following tokens.  */
507859995Selan 	  /* Take out the first #, discard preceding whitespace.  */
507959995Selan 	  exp_p--;
508059995Selan 	  while (exp_p > lastp && is_hor_space[exp_p[-1]])
508159995Selan 	    --exp_p;
508259995Selan 	  /* Skip the second #.  */
508359995Selan 	  p++;
508459995Selan 	  /* Discard following whitespace.  */
508559995Selan 	  SKIP_WHITE_SPACE (p);
508659995Selan 	  concat = p;
508759995Selan 	  if (p == limit)
508859995Selan 	    error ("`##' at end of macro definition");
508959995Selan 	} else {
509059995Selan 	  /* Single #: stringify following argument ref.
509159995Selan 	     Don't leave the # in the expansion.  */
509259995Selan 	  exp_p--;
509359995Selan 	  SKIP_WHITE_SPACE (p);
509459995Selan 	  if (p == limit || ! is_idstart[*p] || nargs <= 0)
509559995Selan 	    error ("`#' operator is not followed by a macro argument name");
509659995Selan 	  else
509759995Selan 	    stringify = p;
509859995Selan 	}
509959995Selan 	break;
510059995Selan       }
510159995Selan     } else {
510259995Selan       /* In -traditional mode, recognize arguments inside strings and
510359995Selan 	 and character constants, and ignore special properties of #.
510459995Selan 	 Arguments inside strings are considered "stringified", but no
510559995Selan 	 extra quote marks are supplied.  */
510659995Selan       switch (c) {
510759995Selan       case '\'':
510859995Selan       case '\"':
510959995Selan 	if (expected_delimiter != '\0') {
511059995Selan 	  if (c == expected_delimiter)
511159995Selan 	    expected_delimiter = '\0';
511259995Selan 	} else
511359995Selan 	  expected_delimiter = c;
511459995Selan 	break;
511559995Selan 
511659995Selan       case '\\':
511759995Selan 	/* Backslash quotes delimiters and itself, but not macro args.  */
511859995Selan 	if (expected_delimiter != 0 && p < limit
511959995Selan 	    && (*p == expected_delimiter || *p == '\\')) {
512059995Selan 	  *exp_p++ = *p++;
512159995Selan 	  continue;
512259995Selan 	}
512359995Selan 	break;
512459995Selan 
512559995Selan       case '/':
512659995Selan 	if (expected_delimiter != '\0') /* No comments inside strings.  */
512759995Selan 	  break;
512859995Selan 	if (*p == '*') {
512959995Selan 	  /* If we find a comment that wasn't removed by handle_directive,
513059995Selan 	     this must be -traditional.  So replace the comment with
513159995Selan 	     nothing at all.  */
513259995Selan 	  exp_p--;
513359995Selan 	  p += 1;
513459995Selan 	  while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
513559995Selan 	    p++;
513659995Selan #if 0
513759995Selan 	  /* Mark this as a concatenation-point, as if it had been ##.  */
513859995Selan 	  concat = p;
513959995Selan #endif
514059995Selan 	}
514159995Selan 	break;
514259995Selan       }
514359995Selan     }
514459995Selan 
514559995Selan     /* Handle the start of a symbol.  */
514659995Selan     if (is_idchar[c] && nargs > 0) {
514759995Selan       U_CHAR *id_beg = p - 1;
514859995Selan       int id_len;
514959995Selan 
515059995Selan       --exp_p;
515159995Selan       while (p != limit && is_idchar[*p]) p++;
515259995Selan       id_len = p - id_beg;
515359995Selan 
515459995Selan       if (is_idstart[c]) {
515559995Selan 	register struct arglist *arg;
515659995Selan 
515759995Selan 	for (arg = arglist; arg != NULL; arg = arg->next) {
515859995Selan 	  struct reflist *tpat;
515959995Selan 
516059995Selan 	  if (arg->name[0] == c
516159995Selan 	      && arg->length == id_len
516259995Selan 	      && strncmp (arg->name, id_beg, id_len) == 0) {
516359995Selan 	    if (expected_delimiter && warn_stringify) {
516459995Selan 	      if (traditional) {
516559995Selan 		warning ("macro argument `%.*s' is stringified.",
516659995Selan 			 id_len, arg->name);
516759995Selan 	      } else {
516859995Selan 		warning ("macro arg `%.*s' would be stringified with -traditional.",
516959995Selan 			 id_len, arg->name);
517059995Selan 	      }
517159995Selan 	    }
517259995Selan 	    /* If ANSI, don't actually substitute inside a string.  */
517359995Selan 	    if (!traditional && expected_delimiter)
517459995Selan 	      break;
517559995Selan 	    /* make a pat node for this arg and append it to the end of
517659995Selan 	       the pat list */
517759995Selan 	    tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
517859995Selan 	    tpat->next = NULL;
517959995Selan 	    tpat->raw_before = concat == id_beg;
518059995Selan 	    tpat->raw_after = 0;
518159995Selan 	    tpat->rest_args = arg->rest_args;
518259995Selan 	    tpat->stringify = (traditional ? expected_delimiter != '\0'
518359995Selan 			       : stringify == id_beg);
518459995Selan 
518559995Selan 	    if (endpat == NULL)
518659995Selan 	      defn->pattern = tpat;
518759995Selan 	    else
518859995Selan 	      endpat->next = tpat;
518959995Selan 	    endpat = tpat;
519059995Selan 
519159995Selan 	    tpat->argno = arg->argno;
519259995Selan 	    tpat->nchars = exp_p - lastp;
519359995Selan 	    {
519459995Selan 	      register U_CHAR *p1 = p;
519559995Selan 	      SKIP_WHITE_SPACE (p1);
519659995Selan 	      if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
519759995Selan 		tpat->raw_after = 1;
519859995Selan 	    }
519959995Selan 	    lastp = exp_p;	/* place to start copying from next time */
520059995Selan 	    skipped_arg = 1;
520159995Selan 	    break;
520259995Selan 	  }
520359995Selan 	}
520459995Selan       }
520559995Selan 
520659995Selan       /* If this was not a macro arg, copy it into the expansion.  */
520759995Selan       if (! skipped_arg) {
520859995Selan 	register U_CHAR *lim1 = p;
520959995Selan 	p = id_beg;
521059995Selan 	while (p != lim1)
521159995Selan 	  *exp_p++ = *p++;
521259995Selan 	if (stringify == id_beg)
521359995Selan 	  error ("`#' operator should be followed by a macro argument name");
521459995Selan       }
521559995Selan     }
521659995Selan   }
521759995Selan 
521859995Selan   if (limit < end) {
521959995Selan     /* Convert trailing whitespace to Newline-markers.  */
522059995Selan     while (limit < end && is_space[*limit]) {
522159995Selan       *exp_p++ = '\n';
522259995Selan       *exp_p++ = *limit++;
522359995Selan     }
522459995Selan   } else if (!traditional && expected_delimiter == 0) {
522559995Selan     /* There is no trailing whitespace, so invent some in ANSI mode.
522659995Selan        But not if "inside a string" (which in ANSI mode
522759995Selan        happens only for -D option).  */
522859995Selan     *exp_p++ = '\n';
522959995Selan     *exp_p++ = ' ';
523059995Selan   }
523159995Selan 
523259995Selan   *exp_p = '\0';
523359995Selan 
523459995Selan   defn->length = exp_p - defn->expansion;
523559995Selan 
523659995Selan   /* Crash now if we overrun the allocated size.  */
523759995Selan   if (defn->length + 1 > maxsize)
523859995Selan     abort ();
523959995Selan 
524059995Selan #if 0
524159995Selan /* This isn't worth the time it takes.  */
524259995Selan   /* give back excess storage */
524359995Selan   defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
524459995Selan #endif
524559995Selan 
524659995Selan   return defn;
524759995Selan }
524859995Selan 
524959995Selan static int
do_assert(buf,limit,op,keyword)525059995Selan do_assert (buf, limit, op, keyword)
525159995Selan      U_CHAR *buf, *limit;
525259995Selan      FILE_BUF *op;
525359995Selan      struct directive *keyword;
525459995Selan {
525559995Selan   U_CHAR *bp;			/* temp ptr into input buffer */
525659995Selan   U_CHAR *symname;		/* remember where symbol name starts */
525759995Selan   int sym_length;		/* and how long it is */
525859995Selan   struct arglist *tokens = NULL;
525959995Selan 
526059995Selan   if (pedantic && done_initializing && !instack[indepth].system_header_p)
526159995Selan     pedwarn ("ANSI C does not allow `#assert'");
526259995Selan 
526359995Selan   bp = buf;
526459995Selan 
526559995Selan   while (is_hor_space[*bp])
526659995Selan     bp++;
526759995Selan 
526859995Selan   symname = bp;			/* remember where it starts */
526959995Selan   sym_length = check_macro_name (bp, "assertion");
527059995Selan   bp += sym_length;
527159995Selan   /* #define doesn't do this, but we should.  */
527259995Selan   SKIP_WHITE_SPACE (bp);
527359995Selan 
527459995Selan   /* Lossage will occur if identifiers or control tokens are broken
527559995Selan      across lines using backslash.  This is not the right place to take
527659995Selan      care of that. */
527759995Selan 
527859995Selan   if (*bp != '(') {
527959995Selan     error ("missing token-sequence in `#assert'");
528059995Selan     return 1;
528159995Selan   }
528259995Selan 
528359995Selan   {
528459995Selan     int error_flag = 0;
528559995Selan 
528659995Selan     bp++;			/* skip '(' */
528759995Selan     SKIP_WHITE_SPACE (bp);
528859995Selan 
528959995Selan     tokens = read_token_list (&bp, limit, &error_flag);
529059995Selan     if (error_flag)
529159995Selan       return 1;
529259995Selan     if (tokens == 0) {
529359995Selan       error ("empty token-sequence in `#assert'");
529459995Selan       return 1;
529559995Selan     }
529659995Selan 
529759995Selan     ++bp;			/* skip paren */
529859995Selan     SKIP_WHITE_SPACE (bp);
529959995Selan   }
530059995Selan 
530159995Selan   /* If this name isn't already an assertion name, make it one.
530259995Selan      Error if it was already in use in some other way.  */
530359995Selan 
530459995Selan   {
530559995Selan     ASSERTION_HASHNODE *hp;
530659995Selan     int hashcode = hashf (symname, sym_length, ASSERTION_HASHSIZE);
530759995Selan     struct tokenlist_list *value
530859995Selan       = (struct tokenlist_list *) xmalloc (sizeof (struct tokenlist_list));
530959995Selan 
531059995Selan     hp = assertion_lookup (symname, sym_length, hashcode);
531159995Selan     if (hp == NULL) {
531259995Selan       if (sym_length == 7 && ! strncmp (symname, "defined", sym_length))
531359995Selan 	error ("`defined' redefined as assertion");
531459995Selan       hp = assertion_install (symname, sym_length, hashcode);
531559995Selan     }
531659995Selan 
531759995Selan     /* Add the spec'd token-sequence to the list of such.  */
531859995Selan     value->tokens = tokens;
531959995Selan     value->next = hp->value;
532059995Selan     hp->value = value;
532159995Selan   }
532259995Selan 
532359995Selan   return 0;
532459995Selan }
532559995Selan 
532659995Selan static int
do_unassert(buf,limit,op,keyword)532759995Selan do_unassert (buf, limit, op, keyword)
532859995Selan      U_CHAR *buf, *limit;
532959995Selan      FILE_BUF *op;
533059995Selan      struct directive *keyword;
533159995Selan {
533259995Selan   U_CHAR *bp;			/* temp ptr into input buffer */
533359995Selan   U_CHAR *symname;		/* remember where symbol name starts */
533459995Selan   int sym_length;		/* and how long it is */
533559995Selan 
533659995Selan   struct arglist *tokens = NULL;
533759995Selan   int tokens_specified = 0;
533859995Selan 
533959995Selan   if (pedantic && done_initializing && !instack[indepth].system_header_p)
534059995Selan     pedwarn ("ANSI C does not allow `#unassert'");
534159995Selan 
534259995Selan   bp = buf;
534359995Selan 
534459995Selan   while (is_hor_space[*bp])
534559995Selan     bp++;
534659995Selan 
534759995Selan   symname = bp;			/* remember where it starts */
534859995Selan   sym_length = check_macro_name (bp, "assertion");
534959995Selan   bp += sym_length;
535059995Selan   /* #define doesn't do this, but we should.  */
535159995Selan   SKIP_WHITE_SPACE (bp);
535259995Selan 
535359995Selan   /* Lossage will occur if identifiers or control tokens are broken
535459995Selan      across lines using backslash.  This is not the right place to take
535559995Selan      care of that. */
535659995Selan 
535759995Selan   if (*bp == '(') {
535859995Selan     int error_flag = 0;
535959995Selan 
536059995Selan     bp++;			/* skip '(' */
536159995Selan     SKIP_WHITE_SPACE (bp);
536259995Selan 
536359995Selan     tokens = read_token_list (&bp, limit, &error_flag);
536459995Selan     if (error_flag)
536559995Selan       return 1;
536659995Selan     if (tokens == 0) {
536759995Selan       error ("empty token list in `#unassert'");
536859995Selan       return 1;
536959995Selan     }
537059995Selan 
537159995Selan     tokens_specified = 1;
537259995Selan 
537359995Selan     ++bp;			/* skip paren */
537459995Selan     SKIP_WHITE_SPACE (bp);
537559995Selan   }
537659995Selan 
537759995Selan   {
537859995Selan     ASSERTION_HASHNODE *hp;
537959995Selan     int hashcode = hashf (symname, sym_length, ASSERTION_HASHSIZE);
538059995Selan     struct tokenlist_list *tail, *prev;
538159995Selan 
538259995Selan     hp = assertion_lookup (symname, sym_length, hashcode);
538359995Selan     if (hp == NULL)
538459995Selan       return 1;
538559995Selan 
538659995Selan     /* If no token list was specified, then eliminate this assertion
538759995Selan        entirely.  */
538859995Selan     if (! tokens_specified) {
538959995Selan       struct tokenlist_list *next;
539059995Selan       for (tail = hp->value; tail; tail = next) {
539159995Selan 	next = tail->next;
539259995Selan 	free_token_list (tail->tokens);
539359995Selan 	free (tail);
539459995Selan       }
539559995Selan       delete_assertion (hp);
539659995Selan     } else {
539759995Selan       /* If a list of tokens was given, then delete any matching list.  */
539859995Selan 
539959995Selan       tail = hp->value;
540059995Selan       prev = 0;
540159995Selan       while (tail) {
540259995Selan 	struct tokenlist_list *next = tail->next;
540359995Selan 	if (compare_token_lists (tail->tokens, tokens)) {
540459995Selan 	  if (prev)
540559995Selan 	    prev->next = next;
540659995Selan 	  else
540759995Selan 	    hp->value = tail->next;
540859995Selan 	  free_token_list (tail->tokens);
540959995Selan 	  free (tail);
541059995Selan 	} else {
541159995Selan 	  prev = tail;
541259995Selan 	}
541359995Selan 	tail = next;
541459995Selan       }
541559995Selan     }
541659995Selan   }
541759995Selan 
541859995Selan   return 0;
541959995Selan }
542059995Selan 
542159995Selan /* Test whether there is an assertion named NAME
542259995Selan    and optionally whether it has an asserted token list TOKENS.
542359995Selan    NAME is not null terminated; its length is SYM_LENGTH.
542459995Selan    If TOKENS_SPECIFIED is 0, then don't check for any token list.  */
542559995Selan 
542659995Selan int
check_assertion(name,sym_length,tokens_specified,tokens)542759995Selan check_assertion (name, sym_length, tokens_specified, tokens)
542859995Selan      U_CHAR *name;
542959995Selan      int sym_length;
543059995Selan      int tokens_specified;
543159995Selan      struct arglist *tokens;
543259995Selan {
543359995Selan   ASSERTION_HASHNODE *hp;
543459995Selan   int hashcode = hashf (name, sym_length, ASSERTION_HASHSIZE);
543559995Selan 
543659995Selan   if (pedantic && !instack[indepth].system_header_p)
543759995Selan     pedwarn ("ANSI C does not allow testing assertions");
543859995Selan 
543959995Selan   hp = assertion_lookup (name, sym_length, hashcode);
544059995Selan   if (hp == NULL)
544159995Selan     /* It is not an assertion; just return false.  */
544259995Selan     return 0;
544359995Selan 
544459995Selan   /* If no token list was specified, then value is 1.  */
544559995Selan   if (! tokens_specified)
544659995Selan     return 1;
544759995Selan 
544859995Selan   {
544959995Selan     struct tokenlist_list *tail;
545059995Selan 
545159995Selan     tail = hp->value;
545259995Selan 
545359995Selan     /* If a list of tokens was given,
545459995Selan        then succeed if the assertion records a matching list.  */
545559995Selan 
545659995Selan     while (tail) {
545759995Selan       if (compare_token_lists (tail->tokens, tokens))
545859995Selan 	return 1;
545959995Selan       tail = tail->next;
546059995Selan     }
546159995Selan 
546259995Selan     /* Fail if the assertion has no matching list.  */
546359995Selan     return 0;
546459995Selan   }
546559995Selan }
546659995Selan 
546759995Selan /* Compare two lists of tokens for equality including order of tokens.  */
546859995Selan 
546959995Selan static int
compare_token_lists(l1,l2)547059995Selan compare_token_lists (l1, l2)
547159995Selan      struct arglist *l1, *l2;
547259995Selan {
547359995Selan   while (l1 && l2) {
547459995Selan     if (l1->length != l2->length)
547559995Selan       return 0;
547659995Selan     if (strncmp (l1->name, l2->name, l1->length))
547759995Selan       return 0;
547859995Selan     l1 = l1->next;
547959995Selan     l2 = l2->next;
548059995Selan   }
548159995Selan 
548259995Selan   /* Succeed if both lists end at the same time.  */
548359995Selan   return l1 == l2;
548459995Selan }
548559995Selan 
548659995Selan /* Read a space-separated list of tokens ending in a close parenthesis.
548759995Selan    Return a list of strings, in the order they were written.
548859995Selan    (In case of error, return 0 and store -1 in *ERROR_FLAG.)
548959995Selan    Parse the text starting at *BPP, and update *BPP.
549059995Selan    Don't parse beyond LIMIT.  */
549159995Selan 
549259995Selan static struct arglist *
read_token_list(bpp,limit,error_flag)549359995Selan read_token_list (bpp, limit, error_flag)
549459995Selan      U_CHAR **bpp;
549559995Selan      U_CHAR *limit;
549659995Selan      int *error_flag;
549759995Selan {
549859995Selan   struct arglist *token_ptrs = 0;
549959995Selan   U_CHAR *bp = *bpp;
550059995Selan   int depth = 1;
550159995Selan 
550259995Selan   *error_flag = 0;
550359995Selan 
550459995Selan   /* Loop over the assertion value tokens.  */
550559995Selan   while (depth > 0) {
550659995Selan     struct arglist *temp;
550759995Selan     int eofp = 0;
550859995Selan     U_CHAR *beg = bp;
550959995Selan 
551059995Selan     /* Find the end of the token.  */
551159995Selan     if (*bp == '(') {
551259995Selan       bp++;
551359995Selan       depth++;
551459995Selan     } else if (*bp == ')') {
551559995Selan       depth--;
551659995Selan       if (depth == 0)
551759995Selan 	break;
551859995Selan       bp++;
551959995Selan     } else if (*bp == '"' || *bp == '\'')
552059995Selan       bp = skip_quoted_string (bp, limit, 0, NULL_PTR, NULL_PTR, &eofp);
552159995Selan     else
552259995Selan       while (! is_hor_space[*bp] && *bp != '(' && *bp != ')'
552359995Selan 	     && *bp != '"' && *bp != '\'' && bp != limit)
552459995Selan 	bp++;
552559995Selan 
552659995Selan     temp = (struct arglist *) xmalloc (sizeof (struct arglist));
552759995Selan     temp->name = (U_CHAR *) xmalloc (bp - beg + 1);
552859995Selan     bcopy (beg, temp->name, bp - beg);
552959995Selan     temp->name[bp - beg] = 0;
553059995Selan     temp->next = token_ptrs;
553159995Selan     token_ptrs = temp;
553259995Selan     temp->length = bp - beg;
553359995Selan 
553459995Selan     SKIP_WHITE_SPACE (bp);
553559995Selan 
553659995Selan     if (bp >= limit) {
553759995Selan       error ("unterminated token sequence in `#assert' or `#unassert'");
553859995Selan       *error_flag = -1;
553959995Selan       return 0;
554059995Selan     }
554159995Selan   }
554259995Selan   *bpp = bp;
554359995Selan 
554459995Selan   /* We accumulated the names in reverse order.
554559995Selan      Now reverse them to get the proper order.  */
554659995Selan   {
554759995Selan     register struct arglist *prev = 0, *this, *next;
554859995Selan     for (this = token_ptrs; this; this = next) {
554959995Selan       next = this->next;
555059995Selan       this->next = prev;
555159995Selan       prev = this;
555259995Selan     }
555359995Selan     return prev;
555459995Selan   }
555559995Selan }
555659995Selan 
555759995Selan static void
free_token_list(tokens)555859995Selan free_token_list (tokens)
555959995Selan      struct arglist *tokens;
556059995Selan {
556159995Selan   while (tokens) {
556259995Selan     struct arglist *next = tokens->next;
556359995Selan     free (tokens->name);
556459995Selan     free (tokens);
556559995Selan     tokens = next;
556659995Selan   }
556759995Selan }
556859995Selan 
556959995Selan /*
557059995Selan  * Install a name in the assertion hash table.
557159995Selan  *
557259995Selan  * If LEN is >= 0, it is the length of the name.
557359995Selan  * Otherwise, compute the length by scanning the entire name.
557459995Selan  *
557559995Selan  * If HASH is >= 0, it is the precomputed hash code.
557659995Selan  * Otherwise, compute the hash code.
557759995Selan  */
557859995Selan static ASSERTION_HASHNODE *
assertion_install(name,len,hash)557959995Selan assertion_install (name, len, hash)
558059995Selan      U_CHAR *name;
558159995Selan      int len;
558259995Selan      int hash;
558359995Selan {
558459995Selan   register ASSERTION_HASHNODE *hp;
558559995Selan   register int i, bucket;
558659995Selan   register U_CHAR *p, *q;
558759995Selan 
558859995Selan   i = sizeof (ASSERTION_HASHNODE) + len + 1;
558959995Selan   hp = (ASSERTION_HASHNODE *) xmalloc (i);
559059995Selan   bucket = hash;
559159995Selan   hp->bucket_hdr = &assertion_hashtab[bucket];
559259995Selan   hp->next = assertion_hashtab[bucket];
559359995Selan   assertion_hashtab[bucket] = hp;
559459995Selan   hp->prev = NULL;
559559995Selan   if (hp->next != NULL)
559659995Selan     hp->next->prev = hp;
559759995Selan   hp->length = len;
559859995Selan   hp->value = 0;
559959995Selan   hp->name = ((U_CHAR *) hp) + sizeof (ASSERTION_HASHNODE);
560059995Selan   p = hp->name;
560159995Selan   q = name;
560259995Selan   for (i = 0; i < len; i++)
560359995Selan     *p++ = *q++;
560459995Selan   hp->name[len] = 0;
560559995Selan   return hp;
560659995Selan }
560759995Selan 
560859995Selan /*
560959995Selan  * find the most recent hash node for name name (ending with first
561059995Selan  * non-identifier char) installed by install
561159995Selan  *
561259995Selan  * If LEN is >= 0, it is the length of the name.
561359995Selan  * Otherwise, compute the length by scanning the entire name.
561459995Selan  *
561559995Selan  * If HASH is >= 0, it is the precomputed hash code.
561659995Selan  * Otherwise, compute the hash code.
561759995Selan  */
561859995Selan static ASSERTION_HASHNODE *
assertion_lookup(name,len,hash)561959995Selan assertion_lookup (name, len, hash)
562059995Selan      U_CHAR *name;
562159995Selan      int len;
562259995Selan      int hash;
562359995Selan {
562459995Selan   register U_CHAR *bp;
562559995Selan   register ASSERTION_HASHNODE *bucket;
562659995Selan 
562759995Selan   bucket = assertion_hashtab[hash];
562859995Selan   while (bucket) {
562959995Selan     if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
563059995Selan       return bucket;
563159995Selan     bucket = bucket->next;
563259995Selan   }
563359995Selan   return NULL;
563459995Selan }
563559995Selan 
563659995Selan static void
delete_assertion(hp)563759995Selan delete_assertion (hp)
563859995Selan      ASSERTION_HASHNODE *hp;
563959995Selan {
564059995Selan 
564159995Selan   if (hp->prev != NULL)
564259995Selan     hp->prev->next = hp->next;
564359995Selan   if (hp->next != NULL)
564459995Selan     hp->next->prev = hp->prev;
564559995Selan 
564659995Selan   /* make sure that the bucket chain header that
564759995Selan      the deleted guy was on points to the right thing afterwards. */
564859995Selan   if (hp == *hp->bucket_hdr)
564959995Selan     *hp->bucket_hdr = hp->next;
565059995Selan 
565159995Selan   free (hp);
565259995Selan }
565359995Selan 
565459995Selan /*
565559995Selan  * interpret #line command.  Remembers previously seen fnames
565659995Selan  * in its very own hash table.
565759995Selan  */
565859995Selan #define FNAME_HASHSIZE 37
565959995Selan 
566059995Selan static int
do_line(buf,limit,op,keyword)566159995Selan do_line (buf, limit, op, keyword)
566259995Selan      U_CHAR *buf, *limit;
566359995Selan      FILE_BUF *op;
566459995Selan      struct directive *keyword;
566559995Selan {
566659995Selan   register U_CHAR *bp;
566759995Selan   FILE_BUF *ip = &instack[indepth];
566859995Selan   FILE_BUF tem;
566959995Selan   int new_lineno;
567059995Selan   enum file_change_code file_change = same_file;
567159995Selan 
567259995Selan   /* Expand any macros.  */
567359995Selan   tem = expand_to_temp_buffer (buf, limit, 0, 0);
567459995Selan 
567559995Selan   /* Point to macroexpanded line, which is null-terminated now.  */
567659995Selan   bp = tem.buf;
567759995Selan   SKIP_WHITE_SPACE (bp);
567859995Selan 
567959995Selan   if (!isdigit (*bp)) {
568059995Selan     error ("invalid format `#line' command");
568159995Selan     return 0;
568259995Selan   }
568359995Selan 
568459995Selan   /* The Newline at the end of this line remains to be processed.
568559995Selan      To put the next line at the specified line number,
568659995Selan      we must store a line number now that is one less.  */
568759995Selan   new_lineno = atoi (bp) - 1;
568859995Selan 
568959995Selan   /* skip over the line number.  */
569059995Selan   while (isdigit (*bp))
569159995Selan     bp++;
569259995Selan 
569359995Selan #if 0 /* #line 10"foo.c" is supposed to be allowed.  */
569459995Selan   if (*bp && !is_space[*bp]) {
569559995Selan     error ("invalid format `#line' command");
569659995Selan     return;
569759995Selan   }
569859995Selan #endif
569959995Selan 
570059995Selan   SKIP_WHITE_SPACE (bp);
570159995Selan 
570259995Selan   if (*bp == '\"') {
570359995Selan     static HASHNODE *fname_table[FNAME_HASHSIZE];
570459995Selan     HASHNODE *hp, **hash_bucket;
570559995Selan     U_CHAR *fname;
570659995Selan     int fname_length;
570759995Selan 
570859995Selan     fname = ++bp;
570959995Selan 
571059995Selan     while (*bp && *bp != '\"')
571159995Selan       bp++;
571259995Selan     if (*bp != '\"') {
571359995Selan       error ("invalid format `#line' command");
571459995Selan       return 0;
571559995Selan     }
571659995Selan 
571759995Selan     fname_length = bp - fname;
571859995Selan 
571959995Selan     bp++;
572059995Selan     SKIP_WHITE_SPACE (bp);
572159995Selan     if (*bp) {
572259995Selan       if (*bp == '1')
572359995Selan 	file_change = enter_file;
572459995Selan       else if (*bp == '2')
572559995Selan 	file_change = leave_file;
572659995Selan       else if (*bp == '3')
572759995Selan 	ip->system_header_p = 1;
572859995Selan       else {
572959995Selan 	error ("invalid format `#line' command");
573059995Selan 	return 0;
573159995Selan       }
573259995Selan 
573359995Selan       bp++;
573459995Selan       SKIP_WHITE_SPACE (bp);
573559995Selan       if (*bp == '3') {
573659995Selan 	ip->system_header_p = 1;
573759995Selan 	bp++;
573859995Selan 	SKIP_WHITE_SPACE (bp);
573959995Selan       }
574059995Selan       if (*bp) {
574159995Selan 	error ("invalid format `#line' command");
574259995Selan 	return 0;
574359995Selan       }
574459995Selan     }
574559995Selan 
574659995Selan     hash_bucket =
574759995Selan       &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
574859995Selan     for (hp = *hash_bucket; hp != NULL; hp = hp->next)
574959995Selan       if (hp->length == fname_length &&
575059995Selan 	  strncmp (hp->value.cpval, fname, fname_length) == 0) {
575159995Selan 	ip->nominal_fname = hp->value.cpval;
575259995Selan 	break;
575359995Selan       }
575459995Selan     if (hp == 0) {
575559995Selan       /* Didn't find it; cons up a new one.  */
575659995Selan       hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1);
575759995Selan       hp->next = *hash_bucket;
575859995Selan       *hash_bucket = hp;
575959995Selan 
576059995Selan       hp->length = fname_length;
576159995Selan       ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
576259995Selan       bcopy (fname, hp->value.cpval, fname_length);
576359995Selan     }
576459995Selan   } else if (*bp) {
576559995Selan     error ("invalid format `#line' command");
576659995Selan     return 0;
576759995Selan   }
576859995Selan 
576959995Selan   ip->lineno = new_lineno;
577059995Selan   output_line_command (ip, op, 0, file_change);
577159995Selan   check_expand (op, ip->length - (ip->bufp - ip->buf));
577259995Selan   return 0;
577359995Selan }
577459995Selan 
577559995Selan /*
577659995Selan  * remove the definition of a symbol from the symbol table.
577759995Selan  * according to un*x /lib/cpp, it is not an error to undef
577859995Selan  * something that has no definitions, so it isn't one here either.
577959995Selan  */
578059995Selan 
578159995Selan static int
do_undef(buf,limit,op,keyword)578259995Selan do_undef (buf, limit, op, keyword)
578359995Selan      U_CHAR *buf, *limit;
578459995Selan      FILE_BUF *op;
578559995Selan      struct directive *keyword;
578659995Selan {
578759995Selan   int sym_length;
578859995Selan   HASHNODE *hp;
578959995Selan   U_CHAR *orig_buf = buf;
579059995Selan 
579159995Selan   /* If this is a precompiler run (with -pcp) pass thru #undef commands.  */
579259995Selan   if (pcp_outfile && op)
579359995Selan     pass_thru_directive (buf, limit, op, keyword);
579459995Selan 
579559995Selan   SKIP_WHITE_SPACE (buf);
579659995Selan   sym_length = check_macro_name (buf, "macro");
579759995Selan 
579859995Selan   while ((hp = lookup (buf, sym_length, -1)) != NULL) {
579959995Selan     /* If we are generating additional info for debugging (with -g) we
580059995Selan        need to pass through all effective #undef commands.  */
580159995Selan     if (debug_output && op)
580259995Selan       pass_thru_directive (orig_buf, limit, op, keyword);
580359995Selan     if (hp->type != T_MACRO)
580459995Selan       warning ("undefining `%s'", hp->name);
580559995Selan     delete_macro (hp);
580659995Selan   }
580759995Selan 
580859995Selan   if (pedantic) {
580959995Selan     buf += sym_length;
581059995Selan     SKIP_WHITE_SPACE (buf);
581159995Selan     if (buf != limit)
581259995Selan       pedwarn ("garbage after `#undef' directive");
581359995Selan   }
581459995Selan   return 0;
581559995Selan }
581659995Selan 
581759995Selan /*
581859995Selan  * Report a fatal error detected by the program we are processing.
581959995Selan  * Use the text of the line in the error message, then terminate.
582059995Selan  * (We use error() because it prints the filename & line#.)
582159995Selan  */
582259995Selan 
582359995Selan static int
do_error(buf,limit,op,keyword)582459995Selan do_error (buf, limit, op, keyword)
582559995Selan      U_CHAR *buf, *limit;
582659995Selan      FILE_BUF *op;
582759995Selan      struct directive *keyword;
582859995Selan {
582959995Selan   int length = limit - buf;
583059995Selan   char *copy = (char *) xmalloc (length + 1);
583159995Selan   bcopy (buf, copy, length);
583259995Selan   copy[length] = 0;
583359995Selan   SKIP_WHITE_SPACE (copy);
583459995Selan   error ("#error %s", copy);
583559995Selan   exit (FAILURE_EXIT_CODE);
583659995Selan   /* NOTREACHED */
583759995Selan   return 0;
583859995Selan }
583959995Selan 
584059995Selan /*
584159995Selan  * Report a warning detected by the program we are processing.
584259995Selan  * Use the text of the line in the warning message, then continue.
584359995Selan  * (We use error() because it prints the filename & line#.)
584459995Selan  */
584559995Selan 
584659995Selan static int
do_warning(buf,limit,op,keyword)584759995Selan do_warning (buf, limit, op, keyword)
584859995Selan      U_CHAR *buf, *limit;
584959995Selan      FILE_BUF *op;
585059995Selan      struct directive *keyword;
585159995Selan {
585259995Selan   int length = limit - buf;
585359995Selan   char *copy = (char *) xmalloc (length + 1);
585459995Selan   bcopy (buf, copy, length);
585559995Selan   copy[length] = 0;
585659995Selan   SKIP_WHITE_SPACE (copy);
585759995Selan   warning ("#warning %s", copy);
585859995Selan   return 0;
585959995Selan }
586059995Selan 
586159995Selan /* Remember the name of the current file being read from so that we can
586259995Selan    avoid ever including it again.  */
586359995Selan 
586459995Selan static int
do_once()586559995Selan do_once ()
586659995Selan {
586759995Selan   int i;
586859995Selan   FILE_BUF *ip = NULL;
586959995Selan 
587059995Selan   for (i = indepth; i >= 0; i--)
587159995Selan     if (instack[i].fname != NULL) {
587259995Selan       ip = &instack[i];
587359995Selan       break;
587459995Selan     }
587559995Selan 
587659995Selan   if (ip != NULL) {
587759995Selan     struct file_name_list *new;
587859995Selan 
587959995Selan     new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
588059995Selan     new->next = dont_repeat_files;
588159995Selan     dont_repeat_files = new;
588259995Selan     new->fname = savestring (ip->fname);
588359995Selan     new->control_macro = 0;
588459995Selan   }
588559995Selan   return 0;
588659995Selan }
588759995Selan 
588859995Selan /* #ident has already been copied to the output file, so just ignore it.  */
588959995Selan 
589059995Selan static int
do_ident(buf,limit)589159995Selan do_ident (buf, limit)
589259995Selan      U_CHAR *buf, *limit;
589359995Selan {
589459995Selan   /* Allow #ident in system headers, since that's not user's fault.  */
589559995Selan   if (pedantic && !instack[indepth].system_header_p)
589659995Selan     pedwarn ("ANSI C does not allow `#ident'");
589759995Selan   return 0;
589859995Selan }
589959995Selan 
590059995Selan /* #pragma and its argument line have already been copied to the output file.
590159995Selan    Just check for some recognized pragmas that need validation here.  */
590259995Selan 
590359995Selan static int
do_pragma(buf,limit)590459995Selan do_pragma (buf, limit)
590559995Selan      U_CHAR *buf, *limit;
590659995Selan {
590759995Selan   while (*buf == ' ' || *buf == '\t')
590859995Selan     buf++;
590959995Selan   if (!strncmp (buf, "once", 4)) {
591059995Selan     /* Allow #pragma once in system headers, since that's not the user's
591159995Selan        fault.  */
591259995Selan     if (!instack[indepth].system_header_p)
591359995Selan       warning ("`#pragma once' is obsolete");
591459995Selan     do_once ();
591559995Selan   }
591659995Selan 
591759995Selan   if (!strncmp (buf, "implementation", 14)) {
591859995Selan     /* Be quiet about `#pragma implementation' for a file only if it hasn't
591959995Selan        been included yet.  */
592059995Selan     struct file_name_list *ptr;
592159995Selan     U_CHAR *p = buf + 14, *fname, *inc_fname;
592259995Selan     SKIP_WHITE_SPACE (p);
592359995Selan     if (*p == '\n' || *p != '\"')
592459995Selan       return 0;
592559995Selan 
592659995Selan     fname = p + 1;
592759995Selan     if (p = (U_CHAR *) index (fname, '\"'))
592859995Selan       *p = '\0';
592959995Selan 
593059995Selan     for (ptr = all_include_files; ptr; ptr = ptr->next) {
593159995Selan       inc_fname = (U_CHAR *) rindex (ptr->fname, '/');
593259995Selan       inc_fname = inc_fname ? inc_fname + 1 : (U_CHAR *) ptr->fname;
593359995Selan       if (inc_fname && !strcmp (inc_fname, fname))
593459995Selan 	warning ("`#pragma implementation' for `%s' appears after file is included",
593559995Selan 		 fname);
593659995Selan     }
593759995Selan   }
593859995Selan 
593959995Selan   return 0;
594059995Selan }
594159995Selan 
594259995Selan #if 0
594359995Selan /* This was a fun hack, but #pragma seems to start to be useful.
594459995Selan    By failing to recognize it, we pass it through unchanged to cc1.  */
594559995Selan 
594659995Selan /*
594759995Selan  * the behavior of the #pragma directive is implementation defined.
594859995Selan  * this implementation defines it as follows.
594959995Selan  */
595059995Selan 
595159995Selan static int
595259995Selan do_pragma ()
595359995Selan {
595459995Selan   close (0);
595559995Selan   if (open ("/dev/tty", O_RDONLY, 0666) != 0)
595659995Selan     goto nope;
595759995Selan   close (1);
595859995Selan   if (open ("/dev/tty", O_WRONLY, 0666) != 1)
595959995Selan     goto nope;
596059995Selan   execl ("/usr/games/hack", "#pragma", 0);
596159995Selan   execl ("/usr/games/rogue", "#pragma", 0);
596259995Selan   execl ("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0);
596359995Selan   execl ("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0);
596459995Selan nope:
596559995Selan   fatal ("You are in a maze of twisty compiler features, all different");
596659995Selan }
596759995Selan #endif
596859995Selan 
596959995Selan /* Just ignore #sccs, on systems where we define it at all.  */
597059995Selan 
597159995Selan static int
do_sccs()597259995Selan do_sccs ()
597359995Selan {
597459995Selan   if (pedantic)
597559995Selan     pedwarn ("ANSI C does not allow `#sccs'");
597659995Selan   return 0;
597759995Selan }
597859995Selan 
597959995Selan /*
598059995Selan  * handle #if command by
598159995Selan  *   1) inserting special `defined' keyword into the hash table
598259995Selan  *	that gets turned into 0 or 1 by special_symbol (thus,
598359995Selan  *	if the luser has a symbol called `defined' already, it won't
598459995Selan  *      work inside the #if command)
598559995Selan  *   2) rescan the input into a temporary output buffer
598659995Selan  *   3) pass the output buffer to the yacc parser and collect a value
598759995Selan  *   4) clean up the mess left from steps 1 and 2.
598859995Selan  *   5) call conditional_skip to skip til the next #endif (etc.),
598959995Selan  *      or not, depending on the value from step 3.
599059995Selan  */
599159995Selan 
599259995Selan static int
do_if(buf,limit,op,keyword)599359995Selan do_if (buf, limit, op, keyword)
599459995Selan      U_CHAR *buf, *limit;
599559995Selan      FILE_BUF *op;
599659995Selan      struct directive *keyword;
599759995Selan {
599859995Selan   int value;
599959995Selan   FILE_BUF *ip = &instack[indepth];
600059995Selan 
600159995Selan   value = eval_if_expression (buf, limit - buf);
600259995Selan   conditional_skip (ip, value == 0, T_IF, NULL_PTR);
600359995Selan   return 0;
600459995Selan }
600559995Selan 
600659995Selan /*
600759995Selan  * handle a #elif directive by not changing  if_stack  either.
600859995Selan  * see the comment above do_else.
600959995Selan  */
601059995Selan 
601159995Selan static int
do_elif(buf,limit,op,keyword)601259995Selan do_elif (buf, limit, op, keyword)
601359995Selan      U_CHAR *buf, *limit;
601459995Selan      FILE_BUF *op;
601559995Selan      struct directive *keyword;
601659995Selan {
601759995Selan   int value;
601859995Selan   FILE_BUF *ip = &instack[indepth];
601959995Selan 
602059995Selan   if (if_stack == instack[indepth].if_stack) {
602159995Selan     error ("`#elif' not within a conditional");
602259995Selan     return 0;
602359995Selan   } else {
602459995Selan     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
602559995Selan       error ("`#elif' after `#else'");
602659995Selan       fprintf (stderr, " (matches line %d", if_stack->lineno);
602759995Selan       if (if_stack->fname != NULL && ip->fname != NULL &&
602859995Selan 	  strcmp (if_stack->fname, ip->nominal_fname) != 0)
602959995Selan 	fprintf (stderr, ", file %s", if_stack->fname);
603059995Selan       fprintf (stderr, ")\n");
603159995Selan     }
603259995Selan     if_stack->type = T_ELIF;
603359995Selan   }
603459995Selan 
603559995Selan   if (if_stack->if_succeeded)
603659995Selan     skip_if_group (ip, 0);
603759995Selan   else {
603859995Selan     value = eval_if_expression (buf, limit - buf);
603959995Selan     if (value == 0)
604059995Selan       skip_if_group (ip, 0);
604159995Selan     else {
604259995Selan       ++if_stack->if_succeeded;	/* continue processing input */
604359995Selan       output_line_command (ip, op, 1, same_file);
604459995Selan     }
604559995Selan   }
604659995Selan   return 0;
604759995Selan }
604859995Selan 
604959995Selan /*
605059995Selan  * evaluate a #if expression in BUF, of length LENGTH,
605159995Selan  * then parse the result as a C expression and return the value as an int.
605259995Selan  */
605359995Selan static int
eval_if_expression(buf,length)605459995Selan eval_if_expression (buf, length)
605559995Selan      U_CHAR *buf;
605659995Selan      int length;
605759995Selan {
605859995Selan   FILE_BUF temp_obuf;
605959995Selan   HASHNODE *save_defined;
606059995Selan   int value;
606159995Selan 
606259995Selan   save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, 0, -1);
606359995Selan   pcp_inside_if = 1;
606459995Selan   temp_obuf = expand_to_temp_buffer (buf, buf + length, 0, 1);
606559995Selan   pcp_inside_if = 0;
606659995Selan   delete_macro (save_defined);	/* clean up special symbol */
606759995Selan 
606859995Selan   value = parse_c_expression (temp_obuf.buf);
606959995Selan 
607059995Selan   free (temp_obuf.buf);
607159995Selan 
607259995Selan   return value;
607359995Selan }
607459995Selan 
607559995Selan /*
607659995Selan  * routine to handle ifdef/ifndef.  Try to look up the symbol,
607759995Selan  * then do or don't skip to the #endif/#else/#elif depending
607859995Selan  * on what directive is actually being processed.
607959995Selan  */
608059995Selan 
608159995Selan static int
do_xifdef(buf,limit,op,keyword)608259995Selan do_xifdef (buf, limit, op, keyword)
608359995Selan      U_CHAR *buf, *limit;
608459995Selan      FILE_BUF *op;
608559995Selan      struct directive *keyword;
608659995Selan {
608759995Selan   int skip;
608859995Selan   FILE_BUF *ip = &instack[indepth];
608959995Selan   U_CHAR *end;
609059995Selan   int start_of_file = 0;
609159995Selan   U_CHAR *control_macro = 0;
609259995Selan 
609359995Selan   /* Detect a #ifndef at start of file (not counting comments).  */
609459995Selan   if (ip->fname != 0 && keyword->type == T_IFNDEF) {
609559995Selan     U_CHAR *p = ip->buf;
609659995Selan     while (p != directive_start) {
609759995Selan       char c = *p++;
609859995Selan       if (is_space[c])
609959995Selan 	;
610059995Selan       else if (c == '/' && p != ip->bufp && *p == '*') {
610159995Selan 	/* Skip this comment.  */
610259995Selan 	int junk;
610359995Selan 	U_CHAR *save_bufp = ip->bufp;
610459995Selan 	ip->bufp = p + 1;
610559995Selan 	p = skip_to_end_of_comment (ip, &junk, 1);
610659995Selan 	ip->bufp = save_bufp;
610759995Selan       } else {
610859995Selan 	goto fail;
610959995Selan       }
611059995Selan     }
611159995Selan     /* If we get here, this conditional is the beginning of the file.  */
611259995Selan     start_of_file = 1;
611359995Selan   fail: ;
611459995Selan   }
611559995Selan 
611659995Selan   /* Discard leading and trailing whitespace.  */
611759995Selan   SKIP_WHITE_SPACE (buf);
611859995Selan   while (limit != buf && is_hor_space[limit[-1]]) limit--;
611959995Selan 
612059995Selan   /* Find the end of the identifier at the beginning.  */
612159995Selan   for (end = buf; is_idchar[*end]; end++);
612259995Selan 
612359995Selan   if (end == buf) {
612459995Selan     skip = (keyword->type == T_IFDEF);
612559995Selan     if (! traditional)
612659995Selan       pedwarn (end == limit ? "`#%s' with no argument"
612759995Selan 	       : "`#%s' argument starts with punctuation",
612859995Selan 	       keyword->name);
612959995Selan   } else {
613059995Selan     HASHNODE *hp;
613159995Selan 
613259995Selan     if (pedantic && buf[0] >= '0' && buf[0] <= '9')
613359995Selan       pedwarn ("`#%s' argument starts with a digit", keyword->name);
613459995Selan     else if (end != limit && !traditional)
613559995Selan       pedwarn ("garbage at end of `#%s' argument", keyword->name);
613659995Selan 
613759995Selan     hp = lookup (buf, end-buf, -1);
613859995Selan 
613959995Selan     if (pcp_outfile) {
614059995Selan       /* Output a precondition for this macro.  */
614159995Selan       if (hp && hp->value.defn->predefined)
614259995Selan 	fprintf(pcp_outfile, "#define %s\n", hp->name);
614359995Selan       else {
614459995Selan 	U_CHAR *cp = buf;
614559995Selan 	fprintf(pcp_outfile, "#undef ");
614659995Selan 	while (is_idchar[*cp]) /* Ick! */
614759995Selan 	  fputc (*cp++, pcp_outfile);
614859995Selan 	putc ('\n', pcp_outfile);
614959995Selan       }
615059995Selan     }
615159995Selan 
615259995Selan     skip = (hp == NULL) ^ (keyword->type == T_IFNDEF);
615359995Selan     if (start_of_file && !skip) {
615459995Selan       control_macro = (U_CHAR *) xmalloc (end - buf + 1);
615559995Selan       bcopy (buf, control_macro, end - buf);
615659995Selan       control_macro[end - buf] = 0;
615759995Selan     }
615859995Selan   }
615959995Selan 
616059995Selan   conditional_skip (ip, skip, T_IF, control_macro);
616159995Selan   return 0;
616259995Selan }
616359995Selan 
616459995Selan /* Push TYPE on stack; then, if SKIP is nonzero, skip ahead.
616559995Selan    If this is a #ifndef starting at the beginning of a file,
616659995Selan    CONTROL_MACRO is the macro name tested by the #ifndef.
616759995Selan    Otherwise, CONTROL_MACRO is 0.  */
616859995Selan 
616959995Selan static void
conditional_skip(ip,skip,type,control_macro)617059995Selan conditional_skip (ip, skip, type, control_macro)
617159995Selan      FILE_BUF *ip;
617259995Selan      int skip;
617359995Selan      enum node_type type;
617459995Selan      U_CHAR *control_macro;
617559995Selan {
617659995Selan   IF_STACK_FRAME *temp;
617759995Selan 
617859995Selan   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
617959995Selan   temp->fname = ip->nominal_fname;
618059995Selan   temp->lineno = ip->lineno;
618159995Selan   temp->next = if_stack;
618259995Selan   temp->control_macro = control_macro;
618359995Selan   if_stack = temp;
618459995Selan 
618559995Selan   if_stack->type = type;
618659995Selan 
618759995Selan   if (skip != 0) {
618859995Selan     skip_if_group (ip, 0);
618959995Selan     return;
619059995Selan   } else {
619159995Selan     ++if_stack->if_succeeded;
619259995Selan     output_line_command (ip, &outbuf, 1, same_file);
619359995Selan   }
619459995Selan }
619559995Selan 
619659995Selan /*
619759995Selan  * skip to #endif, #else, or #elif.  adjust line numbers, etc.
619859995Selan  * leaves input ptr at the sharp sign found.
619959995Selan  * If ANY is nonzero, return at next directive of any sort.
620059995Selan  */
620159995Selan static void
skip_if_group(ip,any)620259995Selan skip_if_group (ip, any)
620359995Selan      FILE_BUF *ip;
620459995Selan      int any;
620559995Selan {
620659995Selan   register U_CHAR *bp = ip->bufp, *cp;
620759995Selan   register U_CHAR *endb = ip->buf + ip->length;
620859995Selan   struct directive *kt;
620959995Selan   IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */
621059995Selan   U_CHAR *beg_of_line = bp;
621159995Selan   register int ident_length;
621259995Selan   U_CHAR *ident, *after_ident;
621359995Selan 
621459995Selan   while (bp < endb) {
621559995Selan     switch (*bp++) {
621659995Selan     case '/':			/* possible comment */
621759995Selan       if (*bp == '\\' && bp[1] == '\n')
621859995Selan 	newline_fix (bp);
621959995Selan       if (*bp == '*'
622059995Selan 	  || (cplusplus_comments && *bp == '/')) {
622159995Selan 	ip->bufp = ++bp;
622259995Selan 	bp = skip_to_end_of_comment (ip, &ip->lineno, 0);
622359995Selan       }
622459995Selan       break;
622559995Selan     case '\"':
622659995Selan     case '\'':
622759995Selan       bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno,
622859995Selan 			       NULL_PTR, NULL_PTR);
622959995Selan       break;
623059995Selan     case '\\':
623159995Selan       /* Char after backslash loses its special meaning.  */
623259995Selan       if (bp < endb) {
623359995Selan 	if (*bp == '\n')
623459995Selan 	  ++ip->lineno;		/* But do update the line-count.  */
623559995Selan 	bp++;
623659995Selan       }
623759995Selan       break;
623859995Selan     case '\n':
623959995Selan       ++ip->lineno;
624059995Selan       beg_of_line = bp;
624159995Selan       break;
624259995Selan     case '#':
624359995Selan       ip->bufp = bp - 1;
624459995Selan 
624559995Selan       /* # keyword: a # must be first nonblank char on the line */
624659995Selan       if (beg_of_line == 0)
624759995Selan 	break;
624859995Selan       /* Scan from start of line, skipping whitespace, comments
624959995Selan 	 and backslash-newlines, and see if we reach this #.
625059995Selan 	 If not, this # is not special.  */
625159995Selan       bp = beg_of_line;
625259995Selan       while (1) {
625359995Selan 	if (is_hor_space[*bp])
625459995Selan 	  bp++;
625559995Selan 	else if (*bp == '\\' && bp[1] == '\n')
625659995Selan 	  bp += 2;
625759995Selan 	else if (*bp == '/' && bp[1] == '*') {
625859995Selan 	  bp += 2;
625959995Selan 	  while (!(*bp == '*' && bp[1] == '/'))
626059995Selan 	    bp++;
626159995Selan 	  bp += 2;
626259995Selan 	} else if (cplusplus_comments && *bp == '/' && bp[1] == '/') {
626359995Selan 	  bp += 2;
626459995Selan 	  while (*bp++ != '\n') ;
626559995Selan         }
626659995Selan 	else break;
626759995Selan       }
626859995Selan       if (bp != ip->bufp) {
626959995Selan 	bp = ip->bufp + 1;	/* Reset bp to after the #.  */
627059995Selan 	break;
627159995Selan       }
627259995Selan 
627359995Selan       bp = ip->bufp + 1;	/* Point after the '#' */
627459995Selan 
627559995Selan       /* Skip whitespace and \-newline.  */
627659995Selan       while (1) {
627759995Selan 	if (is_hor_space[*bp])
627859995Selan 	  bp++;
627959995Selan 	else if (*bp == '\\' && bp[1] == '\n')
628059995Selan 	  bp += 2;
628159995Selan 	else if (*bp == '/' && bp[1] == '*') {
628259995Selan 	  bp += 2;
628359995Selan 	  while (!(*bp == '*' && bp[1] == '/')) {
628459995Selan 	    if (*bp == '\n')
628559995Selan 	      ip->lineno++;
628659995Selan 	    bp++;
628759995Selan 	  }
628859995Selan 	  bp += 2;
628959995Selan 	} else if (cplusplus_comments && *bp == '/' && bp[1] == '/') {
629059995Selan 	  bp += 2;
629159995Selan 	  while (*bp++ != '\n') ;
629259995Selan         }
629359995Selan 	else break;
629459995Selan       }
629559995Selan 
629659995Selan       cp = bp;
629759995Selan 
629859995Selan       /* Now find end of directive name.
629959995Selan 	 If we encounter a backslash-newline, exchange it with any following
630059995Selan 	 symbol-constituents so that we end up with a contiguous name.  */
630159995Selan 
630259995Selan       while (1) {
630359995Selan 	if (is_idchar[*bp])
630459995Selan 	  bp++;
630559995Selan 	else {
630659995Selan 	  if (*bp == '\\' && bp[1] == '\n')
630759995Selan 	    name_newline_fix (bp);
630859995Selan 	  if (is_idchar[*bp])
630959995Selan 	    bp++;
631059995Selan 	  else break;
631159995Selan 	}
631259995Selan       }
631359995Selan       ident_length = bp - cp;
631459995Selan       ident = cp;
631559995Selan       after_ident = bp;
631659995Selan 
631759995Selan       /* A line of just `#' becomes blank.  */
631859995Selan 
631959995Selan       if (ident_length == 0 && *after_ident == '\n') {
632059995Selan 	continue;
632159995Selan       }
632259995Selan 
632359995Selan       if (ident_length == 0 || !is_idstart[*ident]) {
632459995Selan 	U_CHAR *p = ident;
632559995Selan 	while (is_idchar[*p]) {
632659995Selan 	  if (*p < '0' || *p > '9')
632759995Selan 	    break;
632859995Selan 	  p++;
632959995Selan 	}
633059995Selan 	/* Handle # followed by a line number.  */
633159995Selan 	if (p != ident && !is_idchar[*p]) {
633259995Selan 	  if (pedantic)
633359995Selan 	    pedwarn ("`#' followed by integer");
633459995Selan 	  continue;
633559995Selan 	}
633659995Selan 
633759995Selan 	/* Avoid error for `###' and similar cases unless -pedantic.  */
633859995Selan 	if (p == ident) {
633959995Selan 	  while (*p == '#' || is_hor_space[*p]) p++;
634059995Selan 	  if (*p == '\n') {
634159995Selan 	    if (pedantic && !lang_asm)
634259995Selan 	      pedwarn ("invalid preprocessor directive");
634359995Selan 	    continue;
634459995Selan 	  }
634559995Selan 	}
634659995Selan 
634759995Selan 	if (!lang_asm && pedantic)
634859995Selan 	  pedwarn ("invalid preprocessor directive name");
634959995Selan 	continue;
635059995Selan       }
635159995Selan 
635259995Selan       for (kt = directive_table; kt->length >= 0; kt++) {
635359995Selan 	IF_STACK_FRAME *temp;
635459995Selan 	if (ident_length == kt->length
635559995Selan 	    && strncmp (cp, kt->name, kt->length) == 0) {
635659995Selan 	  /* If we are asked to return on next directive, do so now.  */
635759995Selan 	  if (any)
635859995Selan 	    return;
635959995Selan 
636059995Selan 	  switch (kt->type) {
636159995Selan 	  case T_IF:
636259995Selan 	  case T_IFDEF:
636359995Selan 	  case T_IFNDEF:
636459995Selan 	    temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
636559995Selan 	    temp->next = if_stack;
636659995Selan 	    if_stack = temp;
636759995Selan 	    temp->lineno = ip->lineno;
636859995Selan 	    temp->fname = ip->nominal_fname;
636959995Selan 	    temp->type = kt->type;
637059995Selan 	    break;
637159995Selan 	  case T_ELSE:
637259995Selan 	  case T_ENDIF:
637359995Selan 	    if (pedantic && if_stack != save_if_stack)
637459995Selan 	      validate_else (bp);
637559995Selan 	  case T_ELIF:
637659995Selan 	    if (if_stack == instack[indepth].if_stack) {
637759995Selan 	      error ("`#%s' not within a conditional", kt->name);
637859995Selan 	      break;
637959995Selan 	    }
638059995Selan 	    else if (if_stack == save_if_stack)
638159995Selan 	      return;		/* found what we came for */
638259995Selan 
638359995Selan 	    if (kt->type != T_ENDIF) {
638459995Selan 	      if (if_stack->type == T_ELSE)
638559995Selan 		error ("`#else' or `#elif' after `#else'");
638659995Selan 	      if_stack->type = kt->type;
638759995Selan 	      break;
638859995Selan 	    }
638959995Selan 
639059995Selan 	    temp = if_stack;
639159995Selan 	    if_stack = if_stack->next;
639259995Selan 	    free (temp);
639359995Selan 	    break;
639459995Selan 	  }
639559995Selan 	  break;
639659995Selan 	}
639759995Selan       }
639859995Selan       /* Don't let erroneous code go by.  */
639959995Selan       if (kt->length < 0 && !lang_asm && pedantic)
640059995Selan 	pedwarn ("invalid preprocessor directive name");
640159995Selan     }
640259995Selan   }
640359995Selan   ip->bufp = bp;
640459995Selan   /* after this returns, rescan will exit because ip->bufp
640559995Selan      now points to the end of the buffer.
640659995Selan      rescan is responsible for the error message also.  */
640759995Selan }
640859995Selan 
640959995Selan /*
641059995Selan  * handle a #else directive.  Do this by just continuing processing
641159995Selan  * without changing  if_stack ;  this is so that the error message
641259995Selan  * for missing #endif's etc. will point to the original #if.  It
641359995Selan  * is possible that something different would be better.
641459995Selan  */
641559995Selan 
641659995Selan static int
do_else(buf,limit,op,keyword)641759995Selan do_else (buf, limit, op, keyword)
641859995Selan      U_CHAR *buf, *limit;
641959995Selan      FILE_BUF *op;
642059995Selan      struct directive *keyword;
642159995Selan {
642259995Selan   FILE_BUF *ip = &instack[indepth];
642359995Selan 
642459995Selan   if (pedantic) {
642559995Selan     SKIP_WHITE_SPACE (buf);
642659995Selan     if (buf != limit)
642759995Selan       pedwarn ("text following `#else' violates ANSI standard");
642859995Selan   }
642959995Selan 
643059995Selan   if (if_stack == instack[indepth].if_stack) {
643159995Selan     error ("`#else' not within a conditional");
643259995Selan     return 0;
643359995Selan   } else {
643459995Selan     /* #ifndef can't have its special treatment for containing the whole file
643559995Selan        if it has a #else clause.  */
643659995Selan     if_stack->control_macro = 0;
643759995Selan 
643859995Selan     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
643959995Selan       error ("`#else' after `#else'");
644059995Selan       fprintf (stderr, " (matches line %d", if_stack->lineno);
644159995Selan       if (strcmp (if_stack->fname, ip->nominal_fname) != 0)
644259995Selan 	fprintf (stderr, ", file %s", if_stack->fname);
644359995Selan       fprintf (stderr, ")\n");
644459995Selan     }
644559995Selan     if_stack->type = T_ELSE;
644659995Selan   }
644759995Selan 
644859995Selan   if (if_stack->if_succeeded)
644959995Selan     skip_if_group (ip, 0);
645059995Selan   else {
645159995Selan     ++if_stack->if_succeeded;	/* continue processing input */
645259995Selan     output_line_command (ip, op, 1, same_file);
645359995Selan   }
645459995Selan   return 0;
645559995Selan }
645659995Selan 
645759995Selan /*
645859995Selan  * unstack after #endif command
645959995Selan  */
646059995Selan 
646159995Selan static int
do_endif(buf,limit,op,keyword)646259995Selan do_endif (buf, limit, op, keyword)
646359995Selan      U_CHAR *buf, *limit;
646459995Selan      FILE_BUF *op;
646559995Selan      struct directive *keyword;
646659995Selan {
646759995Selan   if (pedantic) {
646859995Selan     SKIP_WHITE_SPACE (buf);
646959995Selan     if (buf != limit)
647059995Selan       pedwarn ("text following `#endif' violates ANSI standard");
647159995Selan   }
647259995Selan 
647359995Selan   if (if_stack == instack[indepth].if_stack)
647459995Selan     error ("unbalanced `#endif'");
647559995Selan   else {
647659995Selan     IF_STACK_FRAME *temp = if_stack;
647759995Selan     if_stack = if_stack->next;
647859995Selan     if (temp->control_macro != 0) {
647959995Selan       /* This #endif matched a #ifndef at the start of the file.
648059995Selan 	 See if it is at the end of the file.  */
648159995Selan       FILE_BUF *ip = &instack[indepth];
648259995Selan       U_CHAR *p = ip->bufp;
648359995Selan       U_CHAR *ep = ip->buf + ip->length;
648459995Selan 
648559995Selan       while (p != ep) {
648659995Selan 	U_CHAR c = *p++;
648759995Selan 	switch (c) {
648859995Selan 	case ' ':
648959995Selan 	case '\t':
649059995Selan 	case '\n':
649159995Selan 	  break;
649259995Selan 	case '/':
649359995Selan 	  if (p != ep && *p == '*') {
649459995Selan 	    /* Skip this comment.  */
649559995Selan 	    int junk;
649659995Selan 	    U_CHAR *save_bufp = ip->bufp;
649759995Selan 	    ip->bufp = p + 1;
649859995Selan 	    p = skip_to_end_of_comment (ip, &junk, 1);
649959995Selan 	    ip->bufp = save_bufp;
650059995Selan 	  }
650159995Selan 	  break;
650259995Selan 	default:
650359995Selan 	  goto fail;
650459995Selan 	}
650559995Selan       }
650659995Selan       /* If we get here, this #endif ends a #ifndef
650759995Selan 	 that contains all of the file (aside from whitespace).
650859995Selan 	 Arrange not to include the file again
650959995Selan 	 if the macro that was tested is defined.  */
651059995Selan       if (indepth != 0)
651159995Selan 	record_control_macro (ip->fname, temp->control_macro);
651259995Selan     fail: ;
651359995Selan     }
651459995Selan     free (temp);
651559995Selan     output_line_command (&instack[indepth], op, 1, same_file);
651659995Selan   }
651759995Selan   return 0;
651859995Selan }
651959995Selan 
652059995Selan /* When an #else or #endif is found while skipping failed conditional,
652159995Selan    if -pedantic was specified, this is called to warn about text after
652259995Selan    the command name.  P points to the first char after the command name.  */
652359995Selan 
652459995Selan static void
validate_else(p)652559995Selan validate_else (p)
652659995Selan      register U_CHAR *p;
652759995Selan {
652859995Selan   /* Advance P over whitespace and comments.  */
652959995Selan   while (1) {
653059995Selan     if (*p == '\\' && p[1] == '\n')
653159995Selan       p += 2;
653259995Selan     if (is_hor_space[*p])
653359995Selan       p++;
653459995Selan     else if (*p == '/') {
653559995Selan       if (p[1] == '\\' && p[2] == '\n')
653659995Selan 	newline_fix (p + 1);
653759995Selan       if (p[1] == '*') {
653859995Selan 	p += 2;
653959995Selan 	/* Don't bother warning about unterminated comments
654059995Selan 	   since that will happen later.  Just be sure to exit.  */
654159995Selan 	while (*p) {
654259995Selan 	  if (p[1] == '\\' && p[2] == '\n')
654359995Selan 	    newline_fix (p + 1);
654459995Selan 	  if (*p == '*' && p[1] == '/') {
654559995Selan 	    p += 2;
654659995Selan 	    break;
654759995Selan 	  }
654859995Selan 	  p++;
654959995Selan 	}
655059995Selan       }
655159995Selan       else if (cplusplus_comments && p[1] == '/') {
655259995Selan 	p += 2;
655359995Selan 	while (*p && *p++ != '\n') ;
655459995Selan       }
655559995Selan     } else break;
655659995Selan   }
655759995Selan   if (*p && *p != '\n')
655859995Selan     pedwarn ("text following `#else' or `#endif' violates ANSI standard");
655959995Selan }
656059995Selan 
656159995Selan /* Skip a comment, assuming the input ptr immediately follows the
656259995Selan    initial slash-star.  Bump *LINE_COUNTER for each newline.
656359995Selan    (The canonical line counter is &ip->lineno.)
656459995Selan    Don't use this routine (or the next one) if bumping the line
656559995Selan    counter is not sufficient to deal with newlines in the string.
656659995Selan 
656759995Selan    If NOWARN is nonzero, don't warn about slash-star inside a comment.
656859995Selan    This feature is useful when processing a comment that is going to be
656959995Selan    processed or was processed at another point in the preprocessor,
657059995Selan    to avoid a duplicate warning.  */
657159995Selan static U_CHAR *
skip_to_end_of_comment(ip,line_counter,nowarn)657259995Selan skip_to_end_of_comment (ip, line_counter, nowarn)
657359995Selan      register FILE_BUF *ip;
657459995Selan      int *line_counter;		/* place to remember newlines, or NULL */
657559995Selan      int nowarn;
657659995Selan {
657759995Selan   register U_CHAR *limit = ip->buf + ip->length;
657859995Selan   register U_CHAR *bp = ip->bufp;
657959995Selan   FILE_BUF *op = &outbuf;	/* JF */
658059995Selan   int output = put_out_comments && !line_counter;
658159995Selan 
658259995Selan 	/* JF this line_counter stuff is a crock to make sure the
658359995Selan 	   comment is only put out once, no matter how many times
658459995Selan 	   the comment is skipped.  It almost works */
658559995Selan   if (output) {
658659995Selan     *op->bufp++ = '/';
658759995Selan     *op->bufp++ = '*';
658859995Selan   }
658959995Selan   if (cplusplus_comments && bp[-1] == '/') {
659059995Selan     if (output) {
659159995Selan       while (bp < limit)
659259995Selan 	if ((*op->bufp++ = *bp++) == '\n') {
659359995Selan 	  bp--;
659459995Selan 	  break;
659559995Selan 	}
659659995Selan       op->bufp[-1] = '*';
659759995Selan       *op->bufp++ = '/';
659859995Selan       *op->bufp++ = '\n';
659959995Selan     } else {
660059995Selan       while (bp < limit) {
660159995Selan 	if (*bp++ == '\n') {
660259995Selan 	  bp--;
660359995Selan 	  break;
660459995Selan 	}
660559995Selan       }
660659995Selan     }
660759995Selan     ip->bufp = bp;
660859995Selan     return bp;
660959995Selan   }
661059995Selan   while (bp < limit) {
661159995Selan     if (output)
661259995Selan       *op->bufp++ = *bp;
661359995Selan     switch (*bp++) {
661459995Selan     case '/':
661559995Selan       if (warn_comments && !nowarn && bp < limit && *bp == '*')
661659995Selan 	warning ("`/*' within comment");
661759995Selan       break;
661859995Selan     case '\n':
661959995Selan       if (line_counter != NULL)
662059995Selan 	++*line_counter;
662159995Selan       if (output)
662259995Selan 	++op->lineno;
662359995Selan       break;
662459995Selan     case '*':
662559995Selan       if (*bp == '\\' && bp[1] == '\n')
662659995Selan 	newline_fix (bp);
662759995Selan       if (*bp == '/') {
662859995Selan         if (output)
662959995Selan 	  *op->bufp++ = '/';
663059995Selan 	ip->bufp = ++bp;
663159995Selan 	return bp;
663259995Selan       }
663359995Selan       break;
663459995Selan     }
663559995Selan   }
663659995Selan   ip->bufp = bp;
663759995Selan   return bp;
663859995Selan }
663959995Selan 
664059995Selan /*
664159995Selan  * Skip over a quoted string.  BP points to the opening quote.
664259995Selan  * Returns a pointer after the closing quote.  Don't go past LIMIT.
664359995Selan  * START_LINE is the line number of the starting point (but it need
664459995Selan  * not be valid if the starting point is inside a macro expansion).
664559995Selan  *
664659995Selan  * The input stack state is not changed.
664759995Selan  *
664859995Selan  * If COUNT_NEWLINES is nonzero, it points to an int to increment
664959995Selan  * for each newline passed.
665059995Selan  *
665159995Selan  * If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
665259995Selan  * if we pass a backslash-newline.
665359995Selan  *
665459995Selan  * If EOFP is nonzero, set *EOFP to 1 if the string is unterminated.
665559995Selan  */
665659995Selan static U_CHAR *
skip_quoted_string(bp,limit,start_line,count_newlines,backslash_newlines_p,eofp)665759995Selan skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp)
665859995Selan      register U_CHAR *bp;
665959995Selan      register U_CHAR *limit;
666059995Selan      int start_line;
666159995Selan      int *count_newlines;
666259995Selan      int *backslash_newlines_p;
666359995Selan      int *eofp;
666459995Selan {
666559995Selan   register U_CHAR c, match;
666659995Selan 
666759995Selan   match = *bp++;
666859995Selan   while (1) {
666959995Selan     if (bp >= limit) {
667059995Selan       error_with_line (line_for_error (start_line),
667159995Selan 		       "unterminated string or character constant");
667259995Selan       if (eofp)
667359995Selan 	*eofp = 1;
667459995Selan       break;
667559995Selan     }
667659995Selan     c = *bp++;
667759995Selan     if (c == '\\') {
667859995Selan       while (*bp == '\\' && bp[1] == '\n') {
667959995Selan 	if (backslash_newlines_p)
668059995Selan 	  *backslash_newlines_p = 1;
668159995Selan 	if (count_newlines)
668259995Selan 	  ++*count_newlines;
668359995Selan 	bp += 2;
668459995Selan       }
668559995Selan       if (*bp == '\n' && count_newlines) {
668659995Selan 	if (backslash_newlines_p)
668759995Selan 	  *backslash_newlines_p = 1;
668859995Selan 	++*count_newlines;
668959995Selan       }
669059995Selan       bp++;
669159995Selan     } else if (c == '\n') {
669259995Selan       if (traditional) {
669359995Selan  	/* Unterminated strings and character constants are 'legal'.  */
669459995Selan  	bp--;	/* Don't consume the newline. */
669559995Selan  	if (eofp)
669659995Selan  	  *eofp = 1;
669759995Selan  	break;
669859995Selan       }
669959995Selan       if (match == '\'') {
670059995Selan 	error_with_line (line_for_error (start_line),
670159995Selan 			 "unterminated character constant");
670259995Selan 	bp--;
670359995Selan 	if (eofp)
670459995Selan 	  *eofp = 1;
670559995Selan 	break;
670659995Selan       }
670759995Selan       if (traditional) {	/* Unterminated strings are 'legal'.  */
670859995Selan 	if (eofp)
670959995Selan 	  *eofp = 1;
671059995Selan 	break;
671159995Selan       }
671259995Selan       /* If not traditional, then allow newlines inside strings.  */
671359995Selan       if (count_newlines)
671459995Selan 	++*count_newlines;
671559995Selan     } else if (c == match)
671659995Selan       break;
671759995Selan   }
671859995Selan   return bp;
671959995Selan }
672059995Selan 
672159995Selan /* Skip across a group of balanced parens, starting from IP->bufp.
672259995Selan    IP->bufp is updated.  Use this with IP->bufp pointing at an open-paren.
672359995Selan 
672459995Selan    This does not handle newlines, because it's used for the arg of #if,
672559995Selan    where there aren't any newlines.  Also, backslash-newline can't appear.  */
672659995Selan 
672759995Selan static U_CHAR *
skip_paren_group(ip)672859995Selan skip_paren_group (ip)
672959995Selan      register FILE_BUF *ip;
673059995Selan {
673159995Selan   U_CHAR *limit = ip->buf + ip->length;
673259995Selan   U_CHAR *p = ip->bufp;
673359995Selan   int depth = 0;
673459995Selan   int lines_dummy = 0;
673559995Selan 
673659995Selan   while (p != limit) {
673759995Selan     int c = *p++;
673859995Selan     switch (c) {
673959995Selan     case '(':
674059995Selan       depth++;
674159995Selan       break;
674259995Selan 
674359995Selan     case ')':
674459995Selan       depth--;
674559995Selan       if (depth == 0)
674659995Selan 	return ip->bufp = p;
674759995Selan       break;
674859995Selan 
674959995Selan     case '/':
675059995Selan       if (*p == '*') {
675159995Selan 	ip->bufp = p;
675259995Selan 	p = skip_to_end_of_comment (ip, &lines_dummy, 0);
675359995Selan 	p = ip->bufp;
675459995Selan       }
675559995Selan 
675659995Selan     case '"':
675759995Selan     case '\'':
675859995Selan       {
675959995Selan 	int eofp = 0;
676059995Selan 	p = skip_quoted_string (p - 1, limit, 0, NULL_PTR, NULL_PTR, &eofp);
676159995Selan 	if (eofp)
676259995Selan 	  return ip->bufp = p;
676359995Selan       }
676459995Selan       break;
676559995Selan     }
676659995Selan   }
676759995Selan 
676859995Selan   ip->bufp = p;
676959995Selan   return p;
677059995Selan }
677159995Selan 
677259995Selan /*
677359995Selan  * write out a #line command, for instance, after an #include file.
677459995Selan  * If CONDITIONAL is nonzero, we can omit the #line if it would
677559995Selan  * appear to be a no-op, and we can output a few newlines instead
677659995Selan  * if we want to increase the line number by a small amount.
677759995Selan  * FILE_CHANGE says whether we are entering a file, leaving, or neither.
677859995Selan  */
677959995Selan 
678059995Selan static void
output_line_command(ip,op,conditional,file_change)678159995Selan output_line_command (ip, op, conditional, file_change)
678259995Selan      FILE_BUF *ip, *op;
678359995Selan      int conditional;
678459995Selan      enum file_change_code file_change;
678559995Selan {
678659995Selan   int len;
678759995Selan   char *line_cmd_buf;
678859995Selan 
678959995Selan   if (no_line_commands
679059995Selan       || ip->fname == NULL
679159995Selan       || no_output) {
679259995Selan     op->lineno = ip->lineno;
679359995Selan     return;
679459995Selan   }
679559995Selan 
679659995Selan   if (conditional) {
679759995Selan     if (ip->lineno == op->lineno)
679859995Selan       return;
679959995Selan 
680059995Selan     /* If the inherited line number is a little too small,
680159995Selan        output some newlines instead of a #line command.  */
680259995Selan     if (ip->lineno > op->lineno && ip->lineno < op->lineno + 8) {
680359995Selan       check_expand (op, 10);
680459995Selan       while (ip->lineno > op->lineno) {
680559995Selan 	*op->bufp++ = '\n';
680659995Selan 	op->lineno++;
680759995Selan       }
680859995Selan       return;
680959995Selan     }
681059995Selan   }
681159995Selan 
681259995Selan   /* Don't output a line number of 0 if we can help it.  */
681359995Selan   if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length
681459995Selan       && *ip->bufp == '\n') {
681559995Selan     ip->lineno++;
681659995Selan     ip->bufp++;
681759995Selan   }
681859995Selan 
681959995Selan   line_cmd_buf = (char *) alloca (strlen (ip->nominal_fname) + 100);
682059995Selan #ifdef OUTPUT_LINE_COMMANDS
682159995Selan   sprintf (line_cmd_buf, "#line %d \"%s\"", ip->lineno, ip->nominal_fname);
682259995Selan #else
682359995Selan   sprintf (line_cmd_buf, "# %d \"%s\"", ip->lineno, ip->nominal_fname);
682459995Selan #endif
682559995Selan   if (file_change != same_file)
682659995Selan     strcat (line_cmd_buf, file_change == enter_file ? " 1" : " 2");
682759995Selan   /* Tell cc1 if following text comes from a system header file.  */
682859995Selan   if (ip->system_header_p)
682959995Selan     strcat (line_cmd_buf, " 3");
683059995Selan   len = strlen (line_cmd_buf);
683159995Selan   line_cmd_buf[len++] = '\n';
683259995Selan   check_expand (op, len + 1);
683359995Selan   if (op->bufp > op->buf && op->bufp[-1] != '\n')
683459995Selan     *op->bufp++ = '\n';
683559995Selan   bcopy (line_cmd_buf, op->bufp, len);
683659995Selan   op->bufp += len;
683759995Selan   op->lineno = ip->lineno;
683859995Selan }
683959995Selan 
684059995Selan /* This structure represents one parsed argument in a macro call.
684159995Selan    `raw' points to the argument text as written (`raw_length' is its length).
684259995Selan    `expanded' points to the argument's macro-expansion
684359995Selan    (its length is `expand_length').
684459995Selan    `stringified_length' is the length the argument would have
684559995Selan    if stringified.
684659995Selan    `use_count' is the number of times this macro arg is substituted
684759995Selan    into the macro.  If the actual use count exceeds 10,
684859995Selan    the value stored is 10.
684959995Selan    `free1' and `free2', if nonzero, point to blocks to be freed
685059995Selan    when the macro argument data is no longer needed.  */
685159995Selan 
685259995Selan struct argdata {
685359995Selan   U_CHAR *raw, *expanded;
685459995Selan   int raw_length, expand_length;
685559995Selan   int stringified_length;
685659995Selan   U_CHAR *free1, *free2;
685759995Selan   char newlines;
685859995Selan   char comments;
685959995Selan   char use_count;
686059995Selan };
686159995Selan 
686259995Selan /* Expand a macro call.
686359995Selan    HP points to the symbol that is the macro being called.
686459995Selan    Put the result of expansion onto the input stack
686559995Selan    so that subsequent input by our caller will use it.
686659995Selan 
686759995Selan    If macro wants arguments, caller has already verified that
686859995Selan    an argument list follows; arguments come from the input stack.  */
686959995Selan 
687059995Selan static void
macroexpand(hp,op)687159995Selan macroexpand (hp, op)
687259995Selan      HASHNODE *hp;
687359995Selan      FILE_BUF *op;
687459995Selan {
687559995Selan   int nargs;
687659995Selan   DEFINITION *defn = hp->value.defn;
687759995Selan   register U_CHAR *xbuf;
687859995Selan   int xbuf_len;
687959995Selan   int start_line = instack[indepth].lineno;
688059995Selan   int rest_args, rest_zero;
688159995Selan 
688259995Selan   CHECK_DEPTH (return;);
688359995Selan 
688459995Selan   /* it might not actually be a macro.  */
688559995Selan   if (hp->type != T_MACRO) {
688659995Selan     special_symbol (hp, op);
688759995Selan     return;
688859995Selan   }
688959995Selan 
689059995Selan   /* This macro is being used inside a #if, which means it must be */
689159995Selan   /* recorded as a precondition.  */
689259995Selan   if (pcp_inside_if && pcp_outfile && defn->predefined)
689359995Selan     dump_single_macro (hp, pcp_outfile);
689459995Selan 
689559995Selan   nargs = defn->nargs;
689659995Selan 
689759995Selan   if (nargs >= 0) {
689859995Selan     register int i;
689959995Selan     struct argdata *args;
690059995Selan     char *parse_error = 0;
690159995Selan 
690259995Selan     args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
690359995Selan 
690459995Selan     for (i = 0; i < nargs; i++) {
690559995Selan       args[i].raw = args[i].expanded = (U_CHAR *) "";
690659995Selan       args[i].raw_length = args[i].expand_length
690759995Selan 	= args[i].stringified_length = 0;
690859995Selan       args[i].free1 = args[i].free2 = 0;
690959995Selan       args[i].use_count = 0;
691059995Selan     }
691159995Selan 
691259995Selan     /* Parse all the macro args that are supplied.  I counts them.
691359995Selan        The first NARGS args are stored in ARGS.
691459995Selan        The rest are discarded.
691559995Selan        If rest_args is set then we assume macarg absorbed the rest of the args.
691659995Selan        */
691759995Selan     i = 0;
691859995Selan     rest_args = 0;
691959995Selan     do {
692059995Selan       /* Discard the open-parenthesis or comma before the next arg.  */
692159995Selan       ++instack[indepth].bufp;
692259995Selan       if (rest_args)
692359995Selan 	continue;
692459995Selan       if (i < nargs || (nargs == 0 && i == 0)) {
692559995Selan 	/* if we are working on last arg which absorbs rest of args... */
692659995Selan 	if (i == nargs - 1 && defn->rest_args)
692759995Selan 	  rest_args = 1;
692859995Selan 	parse_error = macarg (&args[i], rest_args);
692959995Selan       }
693059995Selan       else
693159995Selan 	parse_error = macarg (NULL_PTR, 0);
693259995Selan       if (parse_error) {
693359995Selan 	error_with_line (line_for_error (start_line), parse_error);
693459995Selan 	break;
693559995Selan       }
693659995Selan       i++;
693759995Selan     } while (*instack[indepth].bufp != ')');
693859995Selan 
693959995Selan     /* If we got one arg but it was just whitespace, call that 0 args.  */
694059995Selan     if (i == 1) {
694159995Selan       register U_CHAR *bp = args[0].raw;
694259995Selan       register U_CHAR *lim = bp + args[0].raw_length;
694359995Selan       while (bp != lim && is_space[*bp]) bp++;
694459995Selan       if (bp == lim)
694559995Selan 	i = 0;
694659995Selan     }
694759995Selan 
694859995Selan     /* Don't output an error message if we have already output one for
694959995Selan        a parse error above.  */
695059995Selan     rest_zero = 0;
695159995Selan     if (nargs == 0 && i > 0) {
695259995Selan       if (! parse_error)
695359995Selan 	error ("arguments given to macro `%s'", hp->name);
695459995Selan     } else if (i < nargs) {
695559995Selan       /* traditional C allows foo() if foo wants one argument.  */
695659995Selan       if (nargs == 1 && i == 0 && traditional)
695759995Selan 	;
695859995Selan       /* the rest args token is allowed to absorb 0 tokens */
695959995Selan       else if (i == nargs - 1 && defn->rest_args)
696059995Selan 	rest_zero = 1;
696159995Selan       else if (parse_error)
696259995Selan 	;
696359995Selan       else if (i == 0)
696459995Selan 	error ("macro `%s' used without args", hp->name);
696559995Selan       else if (i == 1)
696659995Selan 	error ("macro `%s' used with just one arg", hp->name);
696759995Selan       else
696859995Selan 	error ("macro `%s' used with only %d args", hp->name, i);
696959995Selan     } else if (i > nargs) {
697059995Selan       if (! parse_error)
697159995Selan 	error ("macro `%s' used with too many (%d) args", hp->name, i);
697259995Selan     }
697359995Selan 
697459995Selan     /* Swallow the closeparen.  */
697559995Selan     ++instack[indepth].bufp;
697659995Selan 
697759995Selan     /* If macro wants zero args, we parsed the arglist for checking only.
697859995Selan        Read directly from the macro definition.  */
697959995Selan     if (nargs == 0) {
698059995Selan       xbuf = defn->expansion;
698159995Selan       xbuf_len = defn->length;
698259995Selan     } else {
698359995Selan       register U_CHAR *exp = defn->expansion;
698459995Selan       register int offset;	/* offset in expansion,
698559995Selan 				   copied a piece at a time */
698659995Selan       register int totlen;	/* total amount of exp buffer filled so far */
698759995Selan 
698859995Selan       register struct reflist *ap, *last_ap;
698959995Selan 
699059995Selan       /* Macro really takes args.  Compute the expansion of this call.  */
699159995Selan 
699259995Selan       /* Compute length in characters of the macro's expansion.
699359995Selan 	 Also count number of times each arg is used.  */
699459995Selan       xbuf_len = defn->length;
699559995Selan       for (ap = defn->pattern; ap != NULL; ap = ap->next) {
699659995Selan 	if (ap->stringify)
699759995Selan 	  xbuf_len += args[ap->argno].stringified_length;
699859995Selan 	else if (ap->raw_before || ap->raw_after || traditional)
699959995Selan 	  xbuf_len += args[ap->argno].raw_length;
700059995Selan 	else
700159995Selan 	  xbuf_len += args[ap->argno].expand_length;
700259995Selan 
700359995Selan 	if (args[ap->argno].use_count < 10)
700459995Selan 	  args[ap->argno].use_count++;
700559995Selan       }
700659995Selan 
700759995Selan       xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
700859995Selan 
700959995Selan       /* Generate in XBUF the complete expansion
701059995Selan 	 with arguments substituted in.
701159995Selan 	 TOTLEN is the total size generated so far.
701259995Selan 	 OFFSET is the index in the definition
701359995Selan 	 of where we are copying from.  */
701459995Selan       offset = totlen = 0;
701559995Selan       for (last_ap = NULL, ap = defn->pattern; ap != NULL;
701659995Selan 	   last_ap = ap, ap = ap->next) {
701759995Selan 	register struct argdata *arg = &args[ap->argno];
701859995Selan 
701959995Selan 	/* add chars to XBUF unless rest_args was zero with concatenation */
702059995Selan 	for (i = 0; i < ap->nchars; i++, offset++)
702159995Selan 	  if (! (rest_zero && ((ap->rest_args && ap->raw_before)
702259995Selan 			       || (last_ap != NULL && last_ap->rest_args
702359995Selan 				   && last_ap->raw_after))))
702459995Selan 	    xbuf[totlen++] = exp[offset];
702559995Selan 
702659995Selan 	if (ap->stringify != 0) {
702759995Selan 	  int arglen = arg->raw_length;
702859995Selan 	  int escaped = 0;
702959995Selan 	  int in_string = 0;
703059995Selan 	  int c;
703159995Selan 	  i = 0;
703259995Selan 	  while (i < arglen
703359995Selan 		 && (c = arg->raw[i], is_space[c]))
703459995Selan 	    i++;
703559995Selan 	  while (i < arglen
703659995Selan 		 && (c = arg->raw[arglen - 1], is_space[c]))
703759995Selan 	    arglen--;
703859995Selan 	  if (!traditional)
703959995Selan 	    xbuf[totlen++] = '\"'; /* insert beginning quote */
704059995Selan 	  for (; i < arglen; i++) {
704159995Selan 	    c = arg->raw[i];
704259995Selan 
704359995Selan 	    /* Special markers Newline Space
704459995Selan 	       generate nothing for a stringified argument.  */
704559995Selan 	    if (c == '\n' && arg->raw[i+1] != '\n') {
704659995Selan 	      i++;
704759995Selan 	      continue;
704859995Selan 	    }
704959995Selan 
705059995Selan 	    /* Internal sequences of whitespace are replaced by one space
705159995Selan 	       except within an string or char token.  */
705259995Selan 	    if (! in_string
705359995Selan 		&& (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c])) {
705459995Selan 	      while (1) {
705559995Selan 		/* Note that Newline Space does occur within whitespace
705659995Selan 		   sequences; consider it part of the sequence.  */
705759995Selan 		if (c == '\n' && is_space[arg->raw[i+1]])
705859995Selan 		  i += 2;
705959995Selan 		else if (c != '\n' && is_space[c])
706059995Selan 		  i++;
706159995Selan 		else break;
706259995Selan 		c = arg->raw[i];
706359995Selan 	      }
706459995Selan 	      i--;
706559995Selan 	      c = ' ';
706659995Selan 	    }
706759995Selan 
706859995Selan 	    if (escaped)
706959995Selan 	      escaped = 0;
707059995Selan 	    else {
707159995Selan 	      if (c == '\\')
707259995Selan 		escaped = 1;
707359995Selan 	      if (in_string) {
707459995Selan 		if (c == in_string)
707559995Selan 		  in_string = 0;
707659995Selan 	      } else if (c == '\"' || c == '\'')
707759995Selan 		in_string = c;
707859995Selan 	    }
707959995Selan 
708059995Selan 	    /* Escape these chars */
708159995Selan 	    if (c == '\"' || (in_string && c == '\\'))
708259995Selan 	      xbuf[totlen++] = '\\';
708359995Selan 	    if (isprint (c))
708459995Selan 	      xbuf[totlen++] = c;
708559995Selan 	    else {
708659995Selan 	      sprintf ((char *) &xbuf[totlen], "\\%03o", (unsigned int) c);
708759995Selan 	      totlen += 4;
708859995Selan 	    }
708959995Selan 	  }
709059995Selan 	  if (!traditional)
709159995Selan 	    xbuf[totlen++] = '\"'; /* insert ending quote */
709259995Selan 	} else if (ap->raw_before || ap->raw_after || traditional) {
709359995Selan 	  U_CHAR *p1 = arg->raw;
709459995Selan 	  U_CHAR *l1 = p1 + arg->raw_length;
709559995Selan 	  if (ap->raw_before) {
709659995Selan 	    while (p1 != l1 && is_space[*p1]) p1++;
709759995Selan 	    while (p1 != l1 && is_idchar[*p1])
709859995Selan 	      xbuf[totlen++] = *p1++;
709959995Selan 	    /* Delete any no-reexpansion marker that follows
710059995Selan 	       an identifier at the beginning of the argument
710159995Selan 	       if the argument is concatenated with what precedes it.  */
710259995Selan 	    if (p1[0] == '\n' && p1[1] == '-')
710359995Selan 	      p1 += 2;
710459995Selan 	  }
710559995Selan 	  if (ap->raw_after) {
710659995Selan 	    /* Arg is concatenated after: delete trailing whitespace,
710759995Selan 	       whitespace markers, and no-reexpansion markers.  */
710859995Selan 	    while (p1 != l1) {
710959995Selan 	      if (is_space[l1[-1]]) l1--;
711059995Selan 	      else if (l1[-1] == '-') {
711159995Selan 		U_CHAR *p2 = l1 - 1;
711259995Selan 		/* If a `-' is preceded by an odd number of newlines then it
711359995Selan 		   and the last newline are a no-reexpansion marker.  */
711459995Selan 		while (p2 != p1 && p2[-1] == '\n') p2--;
711559995Selan 		if ((l1 - 1 - p2) & 1) {
711659995Selan 		  l1 -= 2;
711759995Selan 		}
711859995Selan 		else break;
711959995Selan 	      }
712059995Selan 	      else break;
712159995Selan 	    }
712259995Selan 	  }
712359995Selan 	  bcopy (p1, xbuf + totlen, l1 - p1);
712459995Selan 	  totlen += l1 - p1;
712559995Selan 	} else {
712659995Selan 	  bcopy (arg->expanded, xbuf + totlen, arg->expand_length);
712759995Selan 	  totlen += arg->expand_length;
712859995Selan 	  /* If a macro argument with newlines is used multiple times,
712959995Selan 	     then only expand the newlines once.  This avoids creating output
713059995Selan 	     lines which don't correspond to any input line, which confuses
713159995Selan 	     gdb and gcov.  */
713259995Selan 	  if (arg->use_count > 1 && arg->newlines > 0) {
713359995Selan 	    /* Don't bother doing delete_newlines for subsequent
713459995Selan 	       uses of arg.  */
713559995Selan 	    arg->use_count = 1;
713659995Selan 	    arg->expand_length
713759995Selan 	      = delete_newlines (arg->expanded, arg->expand_length);
713859995Selan 	  }
713959995Selan 	}
714059995Selan 
714159995Selan 	if (totlen > xbuf_len)
714259995Selan 	  abort ();
714359995Selan       }
714459995Selan 
714559995Selan       /* if there is anything left of the definition
714659995Selan 	 after handling the arg list, copy that in too. */
714759995Selan 
714859995Selan       for (i = offset; i < defn->length; i++) {
714959995Selan 	/* if we've reached the end of the macro */
715059995Selan 	if (exp[i] == ')')
715159995Selan 	  rest_zero = 0;
715259995Selan 	if (! (rest_zero && last_ap != NULL && last_ap->rest_args
715359995Selan 	       && last_ap->raw_after))
715459995Selan 	  xbuf[totlen++] = exp[i];
715559995Selan       }
715659995Selan 
715759995Selan       xbuf[totlen] = 0;
715859995Selan       xbuf_len = totlen;
715959995Selan 
716059995Selan       for (i = 0; i < nargs; i++) {
716159995Selan 	if (args[i].free1 != 0)
716259995Selan 	  free (args[i].free1);
716359995Selan 	if (args[i].free2 != 0)
716459995Selan 	  free (args[i].free2);
716559995Selan       }
716659995Selan     }
716759995Selan   } else {
716859995Selan     xbuf = defn->expansion;
716959995Selan     xbuf_len = defn->length;
717059995Selan   }
717159995Selan 
717259995Selan   /* Now put the expansion on the input stack
717359995Selan      so our caller will commence reading from it.  */
717459995Selan   {
717559995Selan     register FILE_BUF *ip2;
717659995Selan 
717759995Selan     ip2 = &instack[++indepth];
717859995Selan 
717959995Selan     ip2->fname = 0;
718059995Selan     ip2->nominal_fname = 0;
718159995Selan     ip2->lineno = 0;
718259995Selan     ip2->buf = xbuf;
718359995Selan     ip2->length = xbuf_len;
718459995Selan     ip2->bufp = xbuf;
718559995Selan     ip2->free_ptr = (nargs > 0) ? xbuf : 0;
718659995Selan     ip2->macro = hp;
718759995Selan     ip2->if_stack = if_stack;
718859995Selan     ip2->system_header_p = 0;
718959995Selan 
719059995Selan     /* Recursive macro use sometimes works traditionally.
719159995Selan        #define foo(x,y) bar(x(y,0), y)
719259995Selan        foo(foo, baz)  */
719359995Selan 
719459995Selan     if (!traditional)
719559995Selan       hp->type = T_DISABLED;
719659995Selan   }
719759995Selan }
719859995Selan 
719959995Selan /*
720059995Selan  * Parse a macro argument and store the info on it into *ARGPTR.
720159995Selan  * REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
720259995Selan  * Return nonzero to indicate a syntax error.
720359995Selan  */
720459995Selan 
720559995Selan static char *
macarg(argptr,rest_args)720659995Selan macarg (argptr, rest_args)
720759995Selan      register struct argdata *argptr;
720859995Selan      int rest_args;
720959995Selan {
721059995Selan   FILE_BUF *ip = &instack[indepth];
721159995Selan   int paren = 0;
721259995Selan   int newlines = 0;
721359995Selan   int comments = 0;
721459995Selan 
721559995Selan   /* Try to parse as much of the argument as exists at this
721659995Selan      input stack level.  */
721759995Selan   U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
721859995Selan 			&paren, &newlines, &comments, rest_args);
721959995Selan 
722059995Selan   /* If we find the end of the argument at this level,
722159995Selan      set up *ARGPTR to point at it in the input stack.  */
722259995Selan   if (!(ip->fname != 0 && (newlines != 0 || comments != 0))
722359995Selan       && bp != ip->buf + ip->length) {
722459995Selan     if (argptr != 0) {
722559995Selan       argptr->raw = ip->bufp;
722659995Selan       argptr->raw_length = bp - ip->bufp;
722759995Selan       argptr->newlines = newlines;
722859995Selan     }
722959995Selan     ip->bufp = bp;
723059995Selan   } else {
723159995Selan     /* This input stack level ends before the macro argument does.
723259995Selan        We must pop levels and keep parsing.
723359995Selan        Therefore, we must allocate a temporary buffer and copy
723459995Selan        the macro argument into it.  */
723559995Selan     int bufsize = bp - ip->bufp;
723659995Selan     int extra = newlines;
723759995Selan     U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1);
723859995Selan     int final_start = 0;
723959995Selan 
724059995Selan     bcopy (ip->bufp, buffer, bufsize);
724159995Selan     ip->bufp = bp;
724259995Selan     ip->lineno += newlines;
724359995Selan 
724459995Selan     while (bp == ip->buf + ip->length) {
724559995Selan       if (instack[indepth].macro == 0) {
724659995Selan 	free (buffer);
724759995Selan 	return "unterminated macro call";
724859995Selan       }
724959995Selan       ip->macro->type = T_MACRO;
725059995Selan       if (ip->free_ptr)
725159995Selan 	free (ip->free_ptr);
725259995Selan       ip = &instack[--indepth];
725359995Selan       newlines = 0;
725459995Selan       comments = 0;
725559995Selan       bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
725659995Selan 		    &newlines, &comments, rest_args);
725759995Selan       final_start = bufsize;
725859995Selan       bufsize += bp - ip->bufp;
725959995Selan       extra += newlines;
726059995Selan       buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1);
726159995Selan       bcopy (ip->bufp, buffer + bufsize - (bp - ip->bufp), bp - ip->bufp);
726259995Selan       ip->bufp = bp;
726359995Selan       ip->lineno += newlines;
726459995Selan     }
726559995Selan 
726659995Selan     /* Now, if arg is actually wanted, record its raw form,
726759995Selan        discarding comments and duplicating newlines in whatever
726859995Selan        part of it did not come from a macro expansion.
726959995Selan        EXTRA space has been preallocated for duplicating the newlines.
727059995Selan        FINAL_START is the index of the start of that part.  */
727159995Selan     if (argptr != 0) {
727259995Selan       argptr->raw = buffer;
727359995Selan       argptr->raw_length = bufsize;
727459995Selan       argptr->free1 = buffer;
727559995Selan       argptr->newlines = newlines;
727659995Selan       argptr->comments = comments;
727759995Selan       if ((newlines || comments) && ip->fname != 0)
727859995Selan 	argptr->raw_length
727959995Selan 	  = final_start +
728059995Selan 	    discard_comments (argptr->raw + final_start,
728159995Selan 			      argptr->raw_length - final_start,
728259995Selan 			      newlines);
728359995Selan       argptr->raw[argptr->raw_length] = 0;
728459995Selan       if (argptr->raw_length > bufsize + extra)
728559995Selan 	abort ();
728659995Selan     }
728759995Selan   }
728859995Selan 
728959995Selan   /* If we are not discarding this argument,
729059995Selan      macroexpand it and compute its length as stringified.
729159995Selan      All this info goes into *ARGPTR.  */
729259995Selan 
729359995Selan   if (argptr != 0) {
729459995Selan     FILE_BUF obuf;
729559995Selan     register U_CHAR *buf, *lim;
729659995Selan     register int totlen;
729759995Selan 
729859995Selan     obuf = expand_to_temp_buffer (argptr->raw,
729959995Selan 				  argptr->raw + argptr->raw_length,
730059995Selan 				  1, 0);
730159995Selan 
730259995Selan     argptr->expanded = obuf.buf;
730359995Selan     argptr->expand_length = obuf.length;
730459995Selan     argptr->free2 = obuf.buf;
730559995Selan 
730659995Selan     buf = argptr->raw;
730759995Selan     lim = buf + argptr->raw_length;
730859995Selan 
730959995Selan     while (buf != lim && is_space[*buf])
731059995Selan       buf++;
731159995Selan     while (buf != lim && is_space[lim[-1]])
731259995Selan       lim--;
731359995Selan     totlen = traditional ? 0 : 2;	/* Count opening and closing quote.  */
731459995Selan     while (buf != lim) {
731559995Selan       register U_CHAR c = *buf++;
731659995Selan       totlen++;
731759995Selan       /* Internal sequences of whitespace are replaced by one space
731859995Selan 	 in most cases, but not always.  So count all the whitespace
731959995Selan 	 in case we need to keep it all.  */
732059995Selan #if 0
732159995Selan       if (is_space[c])
732259995Selan 	SKIP_ALL_WHITE_SPACE (buf);
732359995Selan       else
732459995Selan #endif
732559995Selan       if (c == '\"' || c == '\\') /* escape these chars */
732659995Selan 	totlen++;
732759995Selan       else if (!isprint (c))
732859995Selan 	totlen += 3;
732959995Selan     }
733059995Selan     argptr->stringified_length = totlen;
733159995Selan   }
733259995Selan   return 0;
733359995Selan }
733459995Selan 
733559995Selan /* Scan text from START (inclusive) up to LIMIT (exclusive),
733659995Selan    counting parens in *DEPTHPTR,
733759995Selan    and return if reach LIMIT
733859995Selan    or before a `)' that would make *DEPTHPTR negative
733959995Selan    or before a comma when *DEPTHPTR is zero.
734059995Selan    Single and double quotes are matched and termination
734159995Selan    is inhibited within them.  Comments also inhibit it.
734259995Selan    Value returned is pointer to stopping place.
734359995Selan 
734459995Selan    Increment *NEWLINES each time a newline is passed.
734559995Selan    REST_ARGS notifies macarg1 that it should absorb the rest of the args.
734659995Selan    Set *COMMENTS to 1 if a comment is seen.  */
734759995Selan 
734859995Selan static U_CHAR *
macarg1(start,limit,depthptr,newlines,comments,rest_args)734959995Selan macarg1 (start, limit, depthptr, newlines, comments, rest_args)
735059995Selan      U_CHAR *start;
735159995Selan      register U_CHAR *limit;
735259995Selan      int *depthptr, *newlines, *comments;
735359995Selan      int rest_args;
735459995Selan {
735559995Selan   register U_CHAR *bp = start;
735659995Selan 
735759995Selan   while (bp < limit) {
735859995Selan     switch (*bp) {
735959995Selan     case '(':
736059995Selan       (*depthptr)++;
736159995Selan       break;
736259995Selan     case ')':
736359995Selan       if (--(*depthptr) < 0)
736459995Selan 	return bp;
736559995Selan       break;
736659995Selan     case '\\':
736759995Selan       /* Traditionally, backslash makes following char not special.  */
736859995Selan       if (bp + 1 < limit && traditional)
736959995Selan 	{
737059995Selan 	  bp++;
737159995Selan 	  /* But count source lines anyway.  */
737259995Selan 	  if (*bp == '\n')
737359995Selan 	    ++*newlines;
737459995Selan 	}
737559995Selan       break;
737659995Selan     case '\n':
737759995Selan       ++*newlines;
737859995Selan       break;
737959995Selan     case '/':
738059995Selan       if (bp[1] == '\\' && bp[2] == '\n')
738159995Selan 	newline_fix (bp + 1);
738259995Selan       if (cplusplus_comments && bp[1] == '/') {
738359995Selan 	*comments = 1;
738459995Selan 	bp += 2;
738559995Selan 	while (bp < limit && *bp++ != '\n') ;
738659995Selan 	++*newlines;
738759995Selan 	break;
738859995Selan       }
738959995Selan       if (bp[1] != '*' || bp + 1 >= limit)
739059995Selan 	break;
739159995Selan       *comments = 1;
739259995Selan       bp += 2;
739359995Selan       while (bp + 1 < limit) {
739459995Selan 	if (bp[0] == '*'
739559995Selan 	    && bp[1] == '\\' && bp[2] == '\n')
739659995Selan 	  newline_fix (bp + 1);
739759995Selan 	if (bp[0] == '*' && bp[1] == '/')
739859995Selan 	  break;
739959995Selan 	if (*bp == '\n') ++*newlines;
740059995Selan 	bp++;
740159995Selan       }
740259995Selan       break;
740359995Selan     case '\'':
740459995Selan     case '\"':
740559995Selan       {
740659995Selan 	int quotec;
740759995Selan 	for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) {
740859995Selan 	  if (*bp == '\\') {
740959995Selan 	    bp++;
741059995Selan 	    if (*bp == '\n')
741159995Selan 	      ++*newlines;
741259995Selan 	    while (*bp == '\\' && bp[1] == '\n') {
741359995Selan 	      bp += 2;
741459995Selan 	    }
741559995Selan 	  } else if (*bp == '\n') {
741659995Selan 	    ++*newlines;
741759995Selan 	    if (quotec == '\'')
741859995Selan 	      break;
741959995Selan 	  }
742059995Selan 	}
742159995Selan       }
742259995Selan       break;
742359995Selan     case ',':
742459995Selan       /* if we've returned to lowest level and we aren't absorbing all args */
742559995Selan       if ((*depthptr) == 0 && rest_args == 0)
742659995Selan 	return bp;
742759995Selan       break;
742859995Selan     }
742959995Selan     bp++;
743059995Selan   }
743159995Selan 
743259995Selan   return bp;
743359995Selan }
743459995Selan 
743559995Selan /* Discard comments and duplicate newlines
743659995Selan    in the string of length LENGTH at START,
743759995Selan    except inside of string constants.
743859995Selan    The string is copied into itself with its beginning staying fixed.
743959995Selan 
744059995Selan    NEWLINES is the number of newlines that must be duplicated.
744159995Selan    We assume that that much extra space is available past the end
744259995Selan    of the string.  */
744359995Selan 
744459995Selan static int
discard_comments(start,length,newlines)744559995Selan discard_comments (start, length, newlines)
744659995Selan      U_CHAR *start;
744759995Selan      int length;
744859995Selan      int newlines;
744959995Selan {
745059995Selan   register U_CHAR *ibp;
745159995Selan   register U_CHAR *obp;
745259995Selan   register U_CHAR *limit;
745359995Selan   register int c;
745459995Selan 
745559995Selan   /* If we have newlines to duplicate, copy everything
745659995Selan      that many characters up.  Then, in the second part,
745759995Selan      we will have room to insert the newlines
745859995Selan      while copying down.
745959995Selan      NEWLINES may actually be too large, because it counts
746059995Selan      newlines in string constants, and we don't duplicate those.
746159995Selan      But that does no harm.  */
746259995Selan   if (newlines > 0) {
746359995Selan     ibp = start + length;
746459995Selan     obp = ibp + newlines;
746559995Selan     limit = start;
746659995Selan     while (limit != ibp)
746759995Selan       *--obp = *--ibp;
746859995Selan   }
746959995Selan 
747059995Selan   ibp = start + newlines;
747159995Selan   limit = start + length + newlines;
747259995Selan   obp = start;
747359995Selan 
747459995Selan   while (ibp < limit) {
747559995Selan     *obp++ = c = *ibp++;
747659995Selan     switch (c) {
747759995Selan     case '\n':
747859995Selan       /* Duplicate the newline.  */
747959995Selan       *obp++ = '\n';
748059995Selan       break;
748159995Selan 
748259995Selan     case '\\':
748359995Selan       if (*ibp == '\n') {
748459995Selan 	obp--;
748559995Selan 	ibp++;
748659995Selan       }
748759995Selan       break;
748859995Selan 
748959995Selan     case '/':
749059995Selan       if (*ibp == '\\' && ibp[1] == '\n')
749159995Selan 	newline_fix (ibp);
749259995Selan       /* Delete any comment.  */
749359995Selan       if (cplusplus_comments && ibp[0] == '/') {
749459995Selan 	obp--;
749559995Selan 	ibp++;
749659995Selan 	while (ibp < limit && *ibp++ != '\n') ;
749759995Selan 	break;
749859995Selan       }
749959995Selan       if (ibp[0] != '*' || ibp + 1 >= limit)
750059995Selan 	break;
750159995Selan       obp--;
750259995Selan       ibp++;
750359995Selan       while (ibp + 1 < limit) {
750459995Selan 	if (ibp[0] == '*'
750559995Selan 	    && ibp[1] == '\\' && ibp[2] == '\n')
750659995Selan 	  newline_fix (ibp + 1);
750759995Selan 	if (ibp[0] == '*' && ibp[1] == '/')
750859995Selan 	  break;
750959995Selan 	ibp++;
751059995Selan       }
751159995Selan       ibp += 2;
751259995Selan       break;
751359995Selan 
751459995Selan     case '\'':
751559995Selan     case '\"':
751659995Selan       /* Notice and skip strings, so that we don't
751759995Selan 	 think that comments start inside them,
751859995Selan 	 and so we don't duplicate newlines in them.  */
751959995Selan       {
752059995Selan 	int quotec = c;
752159995Selan 	while (ibp < limit) {
752259995Selan 	  *obp++ = c = *ibp++;
752359995Selan 	  if (c == quotec)
752459995Selan 	    break;
752559995Selan 	  if (c == '\n' && quotec == '\'')
752659995Selan 	    break;
752759995Selan 	  if (c == '\\' && ibp < limit) {
752859995Selan 	    while (*ibp == '\\' && ibp[1] == '\n')
752959995Selan 	      ibp += 2;
753059995Selan 	    *obp++ = *ibp++;
753159995Selan 	  }
753259995Selan 	}
753359995Selan       }
753459995Selan       break;
753559995Selan     }
753659995Selan   }
753759995Selan 
753859995Selan   return obp - start;
753959995Selan }
754059995Selan 
754159995Selan /* Delete newlines in the string of length LENGTH at START, except inside
754259995Selan    of string constants.  The string is copied into itself with its beginning
754359995Selan    staying fixed.  */
754459995Selan 
754559995Selan static int
delete_newlines(start,length)754659995Selan delete_newlines (start, length)
754759995Selan      U_CHAR *start;
754859995Selan      int length;
754959995Selan {
755059995Selan   register U_CHAR *ibp;
755159995Selan   register U_CHAR *obp;
755259995Selan   register U_CHAR *limit;
755359995Selan   register int c;
755459995Selan 
755559995Selan   ibp = start;
755659995Selan   limit = start + length;
755759995Selan   obp = start;
755859995Selan 
755959995Selan   while (ibp < limit) {
756059995Selan     *obp++ = c = *ibp++;
756159995Selan     switch (c) {
756259995Selan     case '\n':
756359995Selan       /* If this is a NEWLINE NEWLINE, then this is a real newline in the
756459995Selan 	 output.  Skip past the newline and its duplicate.  */
756559995Selan       if (*ibp == '\n')
756659995Selan 	{
756759995Selan 	  ibp++;
756859995Selan 	  obp--;
756959995Selan 	}
757059995Selan       break;
757159995Selan 
757259995Selan     case '\'':
757359995Selan     case '\"':
757459995Selan       /* Notice and skip strings, so that we don't delete newlines in them.  */
757559995Selan       {
757659995Selan 	int quotec = c;
757759995Selan 	while (ibp < limit) {
757859995Selan 	  *obp++ = c = *ibp++;
757959995Selan 	  if (c == quotec)
758059995Selan 	    break;
758159995Selan 	  if (c == '\n' && quotec == '\'')
758259995Selan 	    break;
758359995Selan 	}
758459995Selan       }
758559995Selan       break;
758659995Selan     }
758759995Selan   }
758859995Selan 
758959995Selan   return obp - start;
759059995Selan }
759159995Selan 
759259995Selan /*
759359995Selan  * error - print error message and increment count of errors.
759459995Selan  */
759559995Selan 
759659995Selan void
error(msg,arg1,arg2,arg3)759759995Selan error (msg, arg1, arg2, arg3)
759859995Selan      char *msg;
759959995Selan      char *arg1, *arg2, *arg3;
760059995Selan {
760159995Selan   int i;
760259995Selan   FILE_BUF *ip = NULL;
760359995Selan 
760459995Selan   print_containing_files ();
760559995Selan 
760659995Selan   for (i = indepth; i >= 0; i--)
760759995Selan     if (instack[i].fname != NULL) {
760859995Selan       ip = &instack[i];
760959995Selan       break;
761059995Selan     }
761159995Selan 
761259995Selan   if (ip != NULL)
761359995Selan     fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
761459995Selan   fprintf (stderr, msg, arg1, arg2, arg3);
761559995Selan   fprintf (stderr, "\n");
761659995Selan   errors++;
761759995Selan }
761859995Selan 
761959995Selan /* Error including a message from `errno'.  */
762059995Selan 
762159995Selan static void
error_from_errno(name)762259995Selan error_from_errno (name)
762359995Selan      char *name;
762459995Selan {
762559995Selan   int i;
762659995Selan   FILE_BUF *ip = NULL;
762759995Selan 
762859995Selan   print_containing_files ();
762959995Selan 
763059995Selan   for (i = indepth; i >= 0; i--)
763159995Selan     if (instack[i].fname != NULL) {
763259995Selan       ip = &instack[i];
763359995Selan       break;
763459995Selan     }
763559995Selan 
763659995Selan   if (ip != NULL)
763759995Selan     fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
763859995Selan 
763959995Selan   if (errno < sys_nerr)
764059995Selan     fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
764159995Selan   else
764259995Selan     fprintf (stderr, "%s: undocumented I/O error\n", name);
764359995Selan 
764459995Selan   errors++;
764559995Selan }
764659995Selan 
764759995Selan /* Print error message but don't count it.  */
764859995Selan 
764959995Selan void
warning(msg,arg1,arg2,arg3)765059995Selan warning (msg, arg1, arg2, arg3)
765159995Selan      char *msg;
765259995Selan      char *arg1, *arg2, *arg3;
765359995Selan {
765459995Selan   int i;
765559995Selan   FILE_BUF *ip = NULL;
765659995Selan 
765759995Selan   if (inhibit_warnings)
765859995Selan     return;
765959995Selan 
766059995Selan   if (warnings_are_errors)
766159995Selan     errors++;
766259995Selan 
766359995Selan   print_containing_files ();
766459995Selan 
766559995Selan   for (i = indepth; i >= 0; i--)
766659995Selan     if (instack[i].fname != NULL) {
766759995Selan       ip = &instack[i];
766859995Selan       break;
766959995Selan     }
767059995Selan 
767159995Selan   if (ip != NULL)
767259995Selan     fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
767359995Selan   fprintf (stderr, "warning: ");
767459995Selan   fprintf (stderr, msg, arg1, arg2, arg3);
767559995Selan   fprintf (stderr, "\n");
767659995Selan }
767759995Selan 
767859995Selan static void
error_with_line(line,msg,arg1,arg2,arg3)767959995Selan error_with_line (line, msg, arg1, arg2, arg3)
768059995Selan      int line;
768159995Selan      char *msg;
768259995Selan      char *arg1, *arg2, *arg3;
768359995Selan {
768459995Selan   int i;
768559995Selan   FILE_BUF *ip = NULL;
768659995Selan 
768759995Selan   print_containing_files ();
768859995Selan 
768959995Selan   for (i = indepth; i >= 0; i--)
769059995Selan     if (instack[i].fname != NULL) {
769159995Selan       ip = &instack[i];
769259995Selan       break;
769359995Selan     }
769459995Selan 
769559995Selan   if (ip != NULL)
769659995Selan     fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
769759995Selan   fprintf (stderr, msg, arg1, arg2, arg3);
769859995Selan   fprintf (stderr, "\n");
769959995Selan   errors++;
770059995Selan }
770159995Selan 
770259995Selan /* print an error message and maybe count it.  */
770359995Selan 
770459995Selan void
pedwarn(msg,arg1,arg2,arg3)770559995Selan pedwarn (msg, arg1, arg2, arg3)
770659995Selan      char *msg;
770759995Selan      char *arg1, *arg2, *arg3;
770859995Selan {
770959995Selan   if (pedantic_errors)
771059995Selan     error (msg, arg1, arg2, arg3);
771159995Selan   else
771259995Selan     warning (msg, arg1, arg2, arg3);
771359995Selan }
771459995Selan 
771559995Selan /* Report a warning (or an error if pedantic_errors)
771659995Selan    giving specified file name and line number, not current.  */
771759995Selan 
771859995Selan static void
pedwarn_with_file_and_line(file,line,msg,arg1,arg2,arg3)771959995Selan pedwarn_with_file_and_line (file, line, msg, arg1, arg2, arg3)
772059995Selan      char *file;
772159995Selan      int line;
772259995Selan      char *msg;
772359995Selan      char *arg1, *arg2, *arg3;
772459995Selan {
772559995Selan   int i;
772659995Selan   if (!pedantic_errors && inhibit_warnings)
772759995Selan     return;
772859995Selan   if (file != NULL)
772959995Selan     fprintf (stderr, "%s:%d: ", file, line);
773059995Selan   if (pedantic_errors || warnings_are_errors)
773159995Selan     errors++;
773259995Selan   if (!pedantic_errors)
773359995Selan     fprintf (stderr, "warning: ");
773459995Selan   fprintf (stderr, msg, arg1, arg2, arg3);
773559995Selan   fprintf (stderr, "\n");
773659995Selan }
773759995Selan 
773859995Selan /* Print the file names and line numbers of the #include
773959995Selan    commands which led to the current file.  */
774059995Selan 
774159995Selan static void
print_containing_files()774259995Selan print_containing_files ()
774359995Selan {
774459995Selan   FILE_BUF *ip = NULL;
774559995Selan   int i;
774659995Selan   int first = 1;
774759995Selan 
774859995Selan   /* If stack of files hasn't changed since we last printed
774959995Selan      this info, don't repeat it.  */
775059995Selan   if (last_error_tick == input_file_stack_tick)
775159995Selan     return;
775259995Selan 
775359995Selan   for (i = indepth; i >= 0; i--)
775459995Selan     if (instack[i].fname != NULL) {
775559995Selan       ip = &instack[i];
775659995Selan       break;
775759995Selan     }
775859995Selan 
775959995Selan   /* Give up if we don't find a source file.  */
776059995Selan   if (ip == NULL)
776159995Selan     return;
776259995Selan 
776359995Selan   /* Find the other, outer source files.  */
776459995Selan   for (i--; i >= 0; i--)
776559995Selan     if (instack[i].fname != NULL) {
776659995Selan       ip = &instack[i];
776759995Selan       if (first) {
776859995Selan 	first = 0;
776959995Selan 	fprintf (stderr, "In file included");
777059995Selan       } else {
777159995Selan 	fprintf (stderr, ",");
777259995Selan       }
777359995Selan 
777459995Selan       fprintf (stderr, " from %s:%d", ip->nominal_fname, ip->lineno);
777559995Selan     }
777659995Selan   if (! first)
777759995Selan     fprintf (stderr, ":\n");
777859995Selan 
777959995Selan   /* Record we have printed the status as of this time.  */
778059995Selan   last_error_tick = input_file_stack_tick;
778159995Selan }
778259995Selan 
778359995Selan /* Return the line at which an error occurred.
778459995Selan    The error is not necessarily associated with the current spot
778559995Selan    in the input stack, so LINE says where.  LINE will have been
778659995Selan    copied from ip->lineno for the current input level.
778759995Selan    If the current level is for a file, we return LINE.
778859995Selan    But if the current level is not for a file, LINE is meaningless.
778959995Selan    In that case, we return the lineno of the innermost file.  */
779059995Selan 
779159995Selan static int
line_for_error(line)779259995Selan line_for_error (line)
779359995Selan      int line;
779459995Selan {
779559995Selan   int i;
779659995Selan   int line1 = line;
779759995Selan 
779859995Selan   for (i = indepth; i >= 0; ) {
779959995Selan     if (instack[i].fname != 0)
780059995Selan       return line1;
780159995Selan     i--;
780259995Selan     if (i < 0)
780359995Selan       return 0;
780459995Selan     line1 = instack[i].lineno;
780559995Selan   }
780659995Selan   abort ();
780759995Selan   /*NOTREACHED*/
780859995Selan   return 0;
780959995Selan }
781059995Selan 
781159995Selan /*
781259995Selan  * If OBUF doesn't have NEEDED bytes after OPTR, make it bigger.
781359995Selan  *
781459995Selan  * As things stand, nothing is ever placed in the output buffer to be
781559995Selan  * removed again except when it's KNOWN to be part of an identifier,
781659995Selan  * so flushing and moving down everything left, instead of expanding,
781759995Selan  * should work ok.
781859995Selan  */
781959995Selan 
782059995Selan /* You might think void was cleaner for the return type,
782159995Selan    but that would get type mismatch in check_expand in strict ANSI.  */
782259995Selan static int
grow_outbuf(obuf,needed)782359995Selan grow_outbuf (obuf, needed)
782459995Selan      register FILE_BUF *obuf;
782559995Selan      register int needed;
782659995Selan {
782759995Selan   register U_CHAR *p;
782859995Selan   int minsize;
782959995Selan 
783059995Selan   if (obuf->length - (obuf->bufp - obuf->buf) > needed)
783159995Selan     return 0;
783259995Selan 
783359995Selan   /* Make it at least twice as big as it is now.  */
783459995Selan   obuf->length *= 2;
783559995Selan   /* Make it have at least 150% of the free space we will need.  */
783659995Selan   minsize = (3 * needed) / 2 + (obuf->bufp - obuf->buf);
783759995Selan   if (minsize > obuf->length)
783859995Selan     obuf->length = minsize;
783959995Selan 
784059995Selan   if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL)
784159995Selan     memory_full ();
784259995Selan 
784359995Selan   obuf->bufp = p + (obuf->bufp - obuf->buf);
784459995Selan   obuf->buf = p;
784559995Selan 
784659995Selan   return 0;
784759995Selan }
784859995Selan 
784959995Selan /* Symbol table for macro names and special symbols */
785059995Selan 
785159995Selan /*
785259995Selan  * install a name in the main hash table, even if it is already there.
785359995Selan  *   name stops with first non alphanumeric, except leading '#'.
785459995Selan  * caller must check against redefinition if that is desired.
785559995Selan  * delete_macro () removes things installed by install () in fifo order.
785659995Selan  * this is important because of the `defined' special symbol used
785759995Selan  * in #if, and also if pushdef/popdef directives are ever implemented.
785859995Selan  *
785959995Selan  * If LEN is >= 0, it is the length of the name.
786059995Selan  * Otherwise, compute the length by scanning the entire name.
786159995Selan  *
786259995Selan  * If HASH is >= 0, it is the precomputed hash code.
786359995Selan  * Otherwise, compute the hash code.
786459995Selan  */
786559995Selan static HASHNODE *
install(name,len,type,ivalue,value,hash)786659995Selan install (name, len, type, ivalue, value, hash)
786759995Selan      U_CHAR *name;
786859995Selan      int len;
786959995Selan      enum node_type type;
787059995Selan      int ivalue;
787159995Selan      char *value;
787259995Selan      int hash;
787359995Selan {
787459995Selan   register HASHNODE *hp;
787559995Selan   register int i, bucket;
787659995Selan   register U_CHAR *p, *q;
787759995Selan 
787859995Selan   if (len < 0) {
787959995Selan     p = name;
788059995Selan     while (is_idchar[*p])
788159995Selan       p++;
788259995Selan     len = p - name;
788359995Selan   }
788459995Selan 
788559995Selan   if (hash < 0)
788659995Selan     hash = hashf (name, len, HASHSIZE);
788759995Selan 
788859995Selan   i = sizeof (HASHNODE) + len + 1;
788959995Selan   hp = (HASHNODE *) xmalloc (i);
789059995Selan   bucket = hash;
789159995Selan   hp->bucket_hdr = &hashtab[bucket];
789259995Selan   hp->next = hashtab[bucket];
789359995Selan   hashtab[bucket] = hp;
789459995Selan   hp->prev = NULL;
789559995Selan   if (hp->next != NULL)
789659995Selan     hp->next->prev = hp;
789759995Selan   hp->type = type;
789859995Selan   hp->length = len;
789959995Selan   if (hp->type == T_CONST)
790059995Selan     hp->value.ival = ivalue;
790159995Selan   else
790259995Selan     hp->value.cpval = value;
790359995Selan   hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
790459995Selan   p = hp->name;
790559995Selan   q = name;
790659995Selan   for (i = 0; i < len; i++)
790759995Selan     *p++ = *q++;
790859995Selan   hp->name[len] = 0;
790959995Selan   return hp;
791059995Selan }
791159995Selan 
791259995Selan /*
791359995Selan  * find the most recent hash node for name name (ending with first
791459995Selan  * non-identifier char) installed by install
791559995Selan  *
791659995Selan  * If LEN is >= 0, it is the length of the name.
791759995Selan  * Otherwise, compute the length by scanning the entire name.
791859995Selan  *
791959995Selan  * If HASH is >= 0, it is the precomputed hash code.
792059995Selan  * Otherwise, compute the hash code.
792159995Selan  */
792259995Selan HASHNODE *
lookup(name,len,hash)792359995Selan lookup (name, len, hash)
792459995Selan      U_CHAR *name;
792559995Selan      int len;
792659995Selan      int hash;
792759995Selan {
792859995Selan   register U_CHAR *bp;
792959995Selan   register HASHNODE *bucket;
793059995Selan 
793159995Selan   if (len < 0) {
793259995Selan     for (bp = name; is_idchar[*bp]; bp++) ;
793359995Selan     len = bp - name;
793459995Selan   }
793559995Selan 
793659995Selan   if (hash < 0)
793759995Selan     hash = hashf (name, len, HASHSIZE);
793859995Selan 
793959995Selan   bucket = hashtab[hash];
794059995Selan   while (bucket) {
794159995Selan     if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
794259995Selan       return bucket;
794359995Selan     bucket = bucket->next;
794459995Selan   }
794559995Selan   return NULL;
794659995Selan }
794759995Selan 
794859995Selan /*
794959995Selan  * Delete a hash node.  Some weirdness to free junk from macros.
795059995Selan  * More such weirdness will have to be added if you define more hash
795159995Selan  * types that need it.
795259995Selan  */
795359995Selan 
795459995Selan /* Note that the DEFINITION of a macro is removed from the hash table
795559995Selan    but its storage is not freed.  This would be a storage leak
795659995Selan    except that it is not reasonable to keep undefining and redefining
795759995Selan    large numbers of macros many times.
795859995Selan    In any case, this is necessary, because a macro can be #undef'd
795959995Selan    in the middle of reading the arguments to a call to it.
796059995Selan    If #undef freed the DEFINITION, that would crash.  */
796159995Selan 
796259995Selan static void
delete_macro(hp)796359995Selan delete_macro (hp)
796459995Selan      HASHNODE *hp;
796559995Selan {
796659995Selan 
796759995Selan   if (hp->prev != NULL)
796859995Selan     hp->prev->next = hp->next;
796959995Selan   if (hp->next != NULL)
797059995Selan     hp->next->prev = hp->prev;
797159995Selan 
797259995Selan   /* make sure that the bucket chain header that
797359995Selan      the deleted guy was on points to the right thing afterwards. */
797459995Selan   if (hp == *hp->bucket_hdr)
797559995Selan     *hp->bucket_hdr = hp->next;
797659995Selan 
797759995Selan #if 0
797859995Selan   if (hp->type == T_MACRO) {
797959995Selan     DEFINITION *d = hp->value.defn;
798059995Selan     struct reflist *ap, *nextap;
798159995Selan 
798259995Selan     for (ap = d->pattern; ap != NULL; ap = nextap) {
798359995Selan       nextap = ap->next;
798459995Selan       free (ap);
798559995Selan     }
798659995Selan     free (d);
798759995Selan   }
798859995Selan #endif
798959995Selan   free (hp);
799059995Selan }
799159995Selan 
799259995Selan /*
799359995Selan  * return hash function on name.  must be compatible with the one
799459995Selan  * computed a step at a time, elsewhere
799559995Selan  */
799659995Selan static int
hashf(name,len,hashsize)799759995Selan hashf (name, len, hashsize)
799859995Selan      register U_CHAR *name;
799959995Selan      register int len;
800059995Selan      int hashsize;
800159995Selan {
800259995Selan   register int r = 0;
800359995Selan 
800459995Selan   while (len--)
800559995Selan     r = HASHSTEP (r, *name++);
800659995Selan 
800759995Selan   return MAKE_POS (r) % hashsize;
800859995Selan }
800959995Selan 
801059995Selan 
801159995Selan /* Dump the definition of a single macro HP to OF.  */
801259995Selan static void
dump_single_macro(hp,of)801359995Selan dump_single_macro (hp, of)
801459995Selan      register HASHNODE *hp;
801559995Selan      FILE *of;
801659995Selan {
801759995Selan   register DEFINITION *defn = hp->value.defn;
801859995Selan   struct reflist *ap;
801959995Selan   int offset;
802059995Selan   int concat;
802159995Selan 
802259995Selan 
802359995Selan   /* Print the definition of the macro HP.  */
802459995Selan 
802559995Selan   fprintf (of, "#define %s", hp->name);
802659995Selan 
802759995Selan   if (defn->nargs >= 0) {
802859995Selan     int i;
802959995Selan 
803059995Selan     fprintf (of, "(");
803159995Selan     for (i = 0; i < defn->nargs; i++) {
803259995Selan       dump_arg_n (defn, i, of);
803359995Selan       if (i + 1 < defn->nargs)
803459995Selan 	fprintf (of, ", ");
803559995Selan     }
803659995Selan     fprintf (of, ")");
803759995Selan   }
803859995Selan 
803959995Selan   fprintf (of, " ");
804059995Selan 
804159995Selan   offset = 0;
804259995Selan   concat = 0;
804359995Selan   for (ap = defn->pattern; ap != NULL; ap = ap->next) {
804459995Selan     dump_defn_1 (defn->expansion, offset, ap->nchars, of);
804559995Selan     if (ap->nchars != 0)
804659995Selan       concat = 0;
804759995Selan     offset += ap->nchars;
804859995Selan     if (ap->stringify)
804959995Selan       fprintf (of, " #");
805059995Selan     if (ap->raw_before && !concat)
805159995Selan       fprintf (of, " ## ");
805259995Selan     concat = 0;
805359995Selan     dump_arg_n (defn, ap->argno, of);
805459995Selan     if (ap->raw_after) {
805559995Selan       fprintf (of, " ## ");
805659995Selan       concat = 1;
805759995Selan     }
805859995Selan   }
805959995Selan   dump_defn_1 (defn->expansion, offset, defn->length - offset, of);
806059995Selan   fprintf (of, "\n");
806159995Selan }
806259995Selan 
806359995Selan /* Dump all macro definitions as #defines to stdout.  */
806459995Selan 
806559995Selan static void
dump_all_macros()806659995Selan dump_all_macros ()
806759995Selan {
806859995Selan   int bucket;
806959995Selan 
807059995Selan   for (bucket = 0; bucket < HASHSIZE; bucket++) {
807159995Selan     register HASHNODE *hp;
807259995Selan 
807359995Selan     for (hp = hashtab[bucket]; hp; hp= hp->next) {
807459995Selan       if (hp->type == T_MACRO)
807559995Selan 	dump_single_macro (hp, stdout);
807659995Selan     }
807759995Selan   }
807859995Selan }
807959995Selan 
808059995Selan /* Output to OF a substring of a macro definition.
808159995Selan    BASE is the beginning of the definition.
808259995Selan    Output characters START thru LENGTH.
808359995Selan    Discard newlines outside of strings, thus
808459995Selan    converting funny-space markers to ordinary spaces.  */
808559995Selan 
808659995Selan static void
dump_defn_1(base,start,length,of)808759995Selan dump_defn_1 (base, start, length, of)
808859995Selan      U_CHAR *base;
808959995Selan      int start;
809059995Selan      int length;
809159995Selan      FILE *of;
809259995Selan {
809359995Selan   U_CHAR *p = base + start;
809459995Selan   U_CHAR *limit = base + start + length;
809559995Selan 
809659995Selan   while (p < limit) {
809759995Selan     if (*p != '\n')
809859995Selan       putc (*p, of);
809959995Selan     else if (*p == '\"' || *p =='\'') {
810059995Selan       U_CHAR *p1 = skip_quoted_string (p, limit, 0, NULL_PTR,
810159995Selan 				       NULL_PTR, NULL_PTR);
810259995Selan       fwrite (p, p1 - p, 1, of);
810359995Selan       p = p1 - 1;
810459995Selan     }
810559995Selan     p++;
810659995Selan   }
810759995Selan }
810859995Selan 
810959995Selan /* Print the name of argument number ARGNUM of macro definition DEFN
811059995Selan    to OF.
811159995Selan    Recall that DEFN->args.argnames contains all the arg names
811259995Selan    concatenated in reverse order with comma-space in between.  */
811359995Selan 
811459995Selan static void
dump_arg_n(defn,argnum,of)811559995Selan dump_arg_n (defn, argnum, of)
811659995Selan      DEFINITION *defn;
811759995Selan      int argnum;
811859995Selan      FILE *of;
811959995Selan {
812059995Selan   register U_CHAR *p = defn->args.argnames;
812159995Selan   while (argnum + 1 < defn->nargs) {
812259995Selan     p = (U_CHAR *) index (p, ' ') + 1;
812359995Selan     argnum++;
812459995Selan   }
812559995Selan 
812659995Selan   while (*p && *p != ',') {
812759995Selan     putc (*p, of);
812859995Selan     p++;
812959995Selan   }
813059995Selan }
813159995Selan 
813259995Selan /* Initialize syntactic classifications of characters.  */
813359995Selan 
813459995Selan static void
initialize_char_syntax()813559995Selan initialize_char_syntax ()
813659995Selan {
813759995Selan   register int i;
813859995Selan 
813959995Selan   /*
814059995Selan    * Set up is_idchar and is_idstart tables.  These should be
814159995Selan    * faster than saying (is_alpha (c) || c == '_'), etc.
814259995Selan    * Set up these things before calling any routines tthat
814359995Selan    * refer to them.
814459995Selan    */
814559995Selan   for (i = 'a'; i <= 'z'; i++) {
814659995Selan     is_idchar[i - 'a' + 'A'] = 1;
814759995Selan     is_idchar[i] = 1;
814859995Selan     is_idstart[i - 'a' + 'A'] = 1;
814959995Selan     is_idstart[i] = 1;
815059995Selan   }
815159995Selan   for (i = '0'; i <= '9'; i++)
815259995Selan     is_idchar[i] = 1;
815359995Selan   is_idchar['_'] = 1;
815459995Selan   is_idstart['_'] = 1;
815559995Selan   is_idchar['$'] = dollars_in_ident;
815659995Selan   is_idstart['$'] = dollars_in_ident;
815759995Selan 
815859995Selan   /* horizontal space table */
815959995Selan   is_hor_space[' '] = 1;
816059995Selan   is_hor_space['\t'] = 1;
816159995Selan   is_hor_space['\v'] = 1;
816259995Selan   is_hor_space['\f'] = 1;
816359995Selan   is_hor_space['\r'] = 1;
816459995Selan 
816559995Selan   is_space[' '] = 1;
816659995Selan   is_space['\t'] = 1;
816759995Selan   is_space['\v'] = 1;
816859995Selan   is_space['\f'] = 1;
816959995Selan   is_space['\n'] = 1;
817059995Selan   is_space['\r'] = 1;
817159995Selan }
817259995Selan 
817359995Selan /* Initialize the built-in macros.  */
817459995Selan 
817559995Selan static void
initialize_builtins(inp,outp)817659995Selan initialize_builtins (inp, outp)
817759995Selan      FILE_BUF *inp;
817859995Selan      FILE_BUF *outp;
817959995Selan {
818059995Selan   install ("__LINE__", -1, T_SPECLINE, 0, 0, -1);
818159995Selan   install ("__DATE__", -1, T_DATE, 0, 0, -1);
818259995Selan   install ("__FILE__", -1, T_FILE, 0, 0, -1);
818359995Selan   install ("__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1);
818459995Selan   install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1);
818559995Selan   install ("__VERSION__", -1, T_VERSION, 0, 0, -1);
818659995Selan   install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1);
818759995Selan   install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1);
818859995Selan   install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1);
818959995Selan   install ("__TIME__", -1, T_TIME, 0, 0, -1);
819059995Selan   if (!traditional)
819159995Selan     install ("__STDC__", -1, T_CONST, STDC_VALUE, 0, -1);
819259995Selan   if (objc)
819359995Selan     install ("__OBJC__", -1, T_CONST, 1, 0, -1);
819459995Selan /*  This is supplied using a -D by the compiler driver
819559995Selan     so that it is present only when truly compiling with GNU C.  */
819659995Selan /*  install ("__GNUC__", -1, T_CONST, 2, 0, -1);  */
819759995Selan 
819859995Selan   if (debug_output)
819959995Selan     {
820059995Selan       char directive[2048];
820159995Selan       register struct directive *dp = &directive_table[0];
820259995Selan       struct tm *timebuf = timestamp ();
820359995Selan 
820459995Selan       sprintf (directive, " __BASE_FILE__ \"%s\"\n",
820559995Selan 	       instack[0].nominal_fname);
820659995Selan       output_line_command (inp, outp, 0, same_file);
820759995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
820859995Selan 
820959995Selan       sprintf (directive, " __VERSION__ \"%s\"\n", version_string);
821059995Selan       output_line_command (inp, outp, 0, same_file);
821159995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
821259995Selan 
821359995Selan       sprintf (directive, " __SIZE_TYPE__ %s\n", SIZE_TYPE);
821459995Selan       output_line_command (inp, outp, 0, same_file);
821559995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
821659995Selan 
821759995Selan       sprintf (directive, " __PTRDIFF_TYPE__ %s\n", PTRDIFF_TYPE);
821859995Selan       output_line_command (inp, outp, 0, same_file);
821959995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
822059995Selan 
822159995Selan       sprintf (directive, " __WCHAR_TYPE__ %s\n", WCHAR_TYPE);
822259995Selan       output_line_command (inp, outp, 0, same_file);
822359995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
822459995Selan 
822559995Selan       sprintf (directive, " __DATE__ \"%s %2d %4d\"\n",
822659995Selan 	       monthnames[timebuf->tm_mon],
822759995Selan 	       timebuf->tm_mday, timebuf->tm_year + 1900);
822859995Selan       output_line_command (inp, outp, 0, same_file);
822959995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
823059995Selan 
823159995Selan       sprintf (directive, " __TIME__ \"%02d:%02d:%02d\"\n",
823259995Selan 	       timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
823359995Selan       output_line_command (inp, outp, 0, same_file);
823459995Selan       pass_thru_directive (directive, &directive[strlen (directive)], outp, dp);
823559995Selan 
823659995Selan       if (!traditional)
823759995Selan 	{
823859995Selan           sprintf (directive, " __STDC__ 1");
823959995Selan           output_line_command (inp, outp, 0, same_file);
824059995Selan           pass_thru_directive (directive, &directive[strlen (directive)],
824159995Selan 			       outp, dp);
824259995Selan 	}
824359995Selan       if (objc)
824459995Selan 	{
824559995Selan           sprintf (directive, " __OBJC__ 1");
824659995Selan           output_line_command (inp, outp, 0, same_file);
824759995Selan           pass_thru_directive (directive, &directive[strlen (directive)],
824859995Selan 			       outp, dp);
824959995Selan 	}
825059995Selan     }
825159995Selan }
825259995Selan 
825359995Selan /*
825459995Selan  * process a given definition string, for initialization
825559995Selan  * If STR is just an identifier, define it with value 1.
825659995Selan  * If STR has anything after the identifier, then it should
825759995Selan  * be identifier=definition.
825859995Selan  */
825959995Selan 
826059995Selan static void
make_definition(str,op)826159995Selan make_definition (str, op)
826259995Selan      U_CHAR *str;
826359995Selan      FILE_BUF *op;
826459995Selan {
826559995Selan   FILE_BUF *ip;
826659995Selan   struct directive *kt;
826759995Selan   U_CHAR *buf, *p;
826859995Selan 
826959995Selan   buf = str;
827059995Selan   p = str;
827159995Selan   if (!is_idstart[*p]) {
827259995Selan     error ("malformed option `-D %s'", str);
827359995Selan     return;
827459995Selan   }
827559995Selan   while (is_idchar[*++p])
827659995Selan     ;
827759995Selan   if (*p == 0) {
827859995Selan     buf = (U_CHAR *) alloca (p - buf + 4);
827959995Selan     strcpy ((char *)buf, str);
828059995Selan     strcat ((char *)buf, " 1");
828159995Selan   } else if (*p != '=') {
828259995Selan     error ("malformed option `-D %s'", str);
828359995Selan     return;
828459995Selan   } else {
828559995Selan     U_CHAR *q;
828659995Selan     /* Copy the entire option so we can modify it.  */
828759995Selan     buf = (U_CHAR *) alloca (2 * strlen (str) + 1);
828859995Selan     strncpy (buf, str, p - str);
828959995Selan     /* Change the = to a space.  */
829059995Selan     buf[p - str] = ' ';
829159995Selan     /* Scan for any backslash-newline and remove it.  */
829259995Selan     p++;
829359995Selan     q = &buf[p - str];
829459995Selan     while (*p) {
829559995Selan       if (*p == '\\' && p[1] == '\n')
829659995Selan 	p += 2;
829759995Selan       /* Change newline chars into newline-markers.  */
829859995Selan       else if (*p == '\n')
829959995Selan 	{
830059995Selan 	  *q++ = '\n';
830159995Selan 	  *q++ = '\n';
830259995Selan 	  p++;
830359995Selan 	}
830459995Selan       else
830559995Selan 	*q++ = *p++;
830659995Selan     }
830759995Selan     *q = 0;
830859995Selan   }
830959995Selan 
831059995Selan   ip = &instack[++indepth];
831159995Selan   ip->nominal_fname = ip->fname = "*Initialization*";
831259995Selan 
831359995Selan   ip->buf = ip->bufp = buf;
831459995Selan   ip->length = strlen (buf);
831559995Selan   ip->lineno = 1;
831659995Selan   ip->macro = 0;
831759995Selan   ip->free_ptr = 0;
831859995Selan   ip->if_stack = if_stack;
831959995Selan   ip->system_header_p = 0;
832059995Selan 
832159995Selan   for (kt = directive_table; kt->type != T_DEFINE; kt++)
832259995Selan     ;
832359995Selan 
832459995Selan   do_define (buf, buf + strlen (buf) , op, kt);
832559995Selan   --indepth;
832659995Selan }
832759995Selan 
832859995Selan /* JF, this does the work for the -U option */
832959995Selan 
833059995Selan static void
make_undef(str,op)833159995Selan make_undef (str, op)
833259995Selan      U_CHAR *str;
833359995Selan      FILE_BUF *op;
833459995Selan {
833559995Selan   FILE_BUF *ip;
833659995Selan   struct directive *kt;
833759995Selan 
833859995Selan   ip = &instack[++indepth];
833959995Selan   ip->nominal_fname = ip->fname = "*undef*";
834059995Selan 
834159995Selan   ip->buf = ip->bufp = str;
834259995Selan   ip->length = strlen (str);
834359995Selan   ip->lineno = 1;
834459995Selan   ip->macro = 0;
834559995Selan   ip->free_ptr = 0;
834659995Selan   ip->if_stack = if_stack;
834759995Selan   ip->system_header_p = 0;
834859995Selan 
834959995Selan   for (kt = directive_table; kt->type != T_UNDEF; kt++)
835059995Selan     ;
835159995Selan 
835259995Selan   do_undef (str, str + strlen (str), op, kt);
835359995Selan   --indepth;
835459995Selan }
835559995Selan 
835659995Selan /* Process the string STR as if it appeared as the body of a #assert.
835759995Selan    OPTION is the option name for which STR was the argument.  */
835859995Selan 
835959995Selan static void
make_assertion(option,str)836059995Selan make_assertion (option, str)
836159995Selan      char *option;
836259995Selan      U_CHAR *str;
836359995Selan {
836459995Selan   FILE_BUF *ip;
836559995Selan   struct directive *kt;
836659995Selan   U_CHAR *buf, *p, *q;
836759995Selan 
836859995Selan   /* Copy the entire option so we can modify it.  */
836959995Selan   buf = (U_CHAR *) alloca (strlen (str) + 1);
837059995Selan   strcpy ((char *) buf, str);
837159995Selan   /* Scan for any backslash-newline and remove it.  */
837259995Selan   p = q = buf;
837359995Selan   while (*p) {
837459995Selan     if (*p == '\\' && p[1] == '\n')
837559995Selan       p += 2;
837659995Selan     else
837759995Selan       *q++ = *p++;
837859995Selan   }
837959995Selan   *q = 0;
838059995Selan 
838159995Selan   p = buf;
838259995Selan   if (!is_idstart[*p]) {
838359995Selan     error ("malformed option `%s %s'", option, str);
838459995Selan     return;
838559995Selan   }
838659995Selan   while (is_idchar[*++p])
838759995Selan     ;
838859995Selan   while (*p == ' ' || *p == '\t') p++;
838959995Selan   if (! (*p == 0 || *p == '(')) {
839059995Selan     error ("malformed option `%s %s'", option, str);
839159995Selan     return;
839259995Selan   }
839359995Selan 
839459995Selan   ip = &instack[++indepth];
839559995Selan   ip->nominal_fname = ip->fname = "*Initialization*";
839659995Selan 
839759995Selan   ip->buf = ip->bufp = buf;
839859995Selan   ip->length = strlen (buf);
839959995Selan   ip->lineno = 1;
840059995Selan   ip->macro = 0;
840159995Selan   ip->free_ptr = 0;
840259995Selan   ip->if_stack = if_stack;
840359995Selan   ip->system_header_p = 0;
840459995Selan 
840559995Selan   for (kt = directive_table; kt->type != T_ASSERT; kt++)
840659995Selan     ;
840759995Selan 
840859995Selan   /* pass NULL as output ptr to do_define since we KNOW it never
840959995Selan      does any output.... */
841059995Selan   do_assert (buf, buf + strlen (buf) , NULL_PTR, kt);
841159995Selan   --indepth;
841259995Selan }
841359995Selan 
841459995Selan /* Append a chain of `struct file_name_list's
841559995Selan    to the end of the main include chain.
841659995Selan    FIRST is the beginning of the chain to append, and LAST is the end.  */
841759995Selan 
841859995Selan static void
append_include_chain(first,last)841959995Selan append_include_chain (first, last)
842059995Selan      struct file_name_list *first, *last;
842159995Selan {
842259995Selan   struct file_name_list *dir;
842359995Selan 
842459995Selan   if (!first || !last)
842559995Selan     return;
842659995Selan 
842759995Selan   if (include == 0)
842859995Selan     include = first;
842959995Selan   else
843059995Selan     last_include->next = first;
843159995Selan 
843259995Selan   if (first_bracket_include == 0)
843359995Selan     first_bracket_include = first;
843459995Selan 
843559995Selan   for (dir = first; ; dir = dir->next) {
843659995Selan     int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
843759995Selan     if (len > max_include_len)
843859995Selan       max_include_len = len;
843959995Selan     if (dir == last)
844059995Selan       break;
844159995Selan   }
844259995Selan 
844359995Selan   last->next = NULL;
844459995Selan   last_include = last;
844559995Selan }
844659995Selan 
844759995Selan /* Add output to `deps_buffer' for the -M switch.
844859995Selan    STRING points to the text to be output.
844959995Selan    SIZE is the number of bytes, or 0 meaning output until a null.
845059995Selan    Outputting the empty string breaks the line if it is long enough.  */
845159995Selan 
845259995Selan static void
deps_output(string,size)845359995Selan deps_output (string, size)
845459995Selan      char *string;
845559995Selan      unsigned size;
845659995Selan {
845759995Selan   if (size == 0)
845859995Selan     size = strlen (string);
845959995Selan 
846059995Selan #ifndef MAX_OUTPUT_COLUMNS
846159995Selan #define MAX_OUTPUT_COLUMNS 75
846259995Selan #endif
846359995Selan   if (size == 0 && deps_column != 0
846459995Selan       && size + deps_column > MAX_OUTPUT_COLUMNS) {
846559995Selan     deps_output ("\\\n  ", 0);
846659995Selan     deps_column = 0;
846759995Selan   }
846859995Selan 
846959995Selan   if (deps_size + size + 1 > deps_allocated_size) {
847059995Selan     deps_allocated_size = deps_size + size + 50;
847159995Selan     deps_allocated_size *= 2;
847259995Selan     deps_buffer = (char *) xrealloc (deps_buffer, deps_allocated_size);
847359995Selan   }
847459995Selan   bcopy (string, &deps_buffer[deps_size], size);
847559995Selan   deps_size += size;
847659995Selan   deps_column += size;
847759995Selan   deps_buffer[deps_size] = 0;
847859995Selan }
847959995Selan 
848059995Selan #if defined(USG) || defined(VMS)
848159995Selan #ifndef BSTRING
848259995Selan 
848359995Selan void
bzero(b,length)848459995Selan bzero (b, length)
848559995Selan      register char *b;
848659995Selan      register unsigned length;
848759995Selan {
848859995Selan   while (length-- > 0)
848959995Selan     *b++ = 0;
849059995Selan }
849159995Selan 
849259995Selan void
bcopy(b1,b2,length)849359995Selan bcopy (b1, b2, length)
849459995Selan      register char *b1;
849559995Selan      register char *b2;
849659995Selan      register unsigned length;
849759995Selan {
849859995Selan   while (length-- > 0)
849959995Selan     *b2++ = *b1++;
850059995Selan }
850159995Selan 
850259995Selan int
bcmp(b1,b2,length)850359995Selan bcmp (b1, b2, length)	/* This could be a macro! */
850459995Selan      register char *b1;
850559995Selan      register char *b2;
850659995Selan      register unsigned length;
850759995Selan {
850859995Selan    while (length-- > 0)
850959995Selan      if (*b1++ != *b2++)
851059995Selan        return 1;
851159995Selan 
851259995Selan    return 0;
851359995Selan }
851459995Selan #endif /* not BSTRING */
851559995Selan #endif /* USG or VMS */
851659995Selan 
851759995Selan 
851859995Selan static void
fatal(str,arg)851959995Selan fatal (str, arg)
852059995Selan      char *str, *arg;
852159995Selan {
852259995Selan   fprintf (stderr, "%s: ", progname);
852359995Selan   fprintf (stderr, str, arg);
852459995Selan   fprintf (stderr, "\n");
852559995Selan   exit (FAILURE_EXIT_CODE);
852659995Selan }
852759995Selan 
852859995Selan /* More 'friendly' abort that prints the line and file.
852959995Selan    config.h can #define abort fancy_abort if you like that sort of thing.  */
853059995Selan 
853159995Selan void
fancy_abort()853259995Selan fancy_abort ()
853359995Selan {
853459995Selan   fatal ("Internal gcc abort.");
853559995Selan }
853659995Selan 
853759995Selan static void
perror_with_name(name)853859995Selan perror_with_name (name)
853959995Selan      char *name;
854059995Selan {
854159995Selan   fprintf (stderr, "%s: ", progname);
854259995Selan   if (errno < sys_nerr)
854359995Selan     fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
854459995Selan   else
854559995Selan     fprintf (stderr, "%s: undocumented I/O error\n", name);
854659995Selan   errors++;
854759995Selan }
854859995Selan 
854959995Selan static void
pfatal_with_name(name)855059995Selan pfatal_with_name (name)
855159995Selan      char *name;
855259995Selan {
855359995Selan   perror_with_name (name);
855459995Selan #ifdef VMS
855559995Selan   exit (vaxc$errno);
855659995Selan #else
855759995Selan   exit (FAILURE_EXIT_CODE);
855859995Selan #endif
855959995Selan }
856059995Selan 
856159995Selan 
856259995Selan static void
memory_full()856359995Selan memory_full ()
856459995Selan {
856559995Selan   fatal ("Memory exhausted.");
856659995Selan }
856759995Selan 
856859995Selan 
856959995Selan char *
xmalloc(size)857059995Selan xmalloc (size)
857159995Selan      unsigned size;
857259995Selan {
857359995Selan   register char *ptr = (char *) malloc (size);
857459995Selan   if (ptr != 0) return (ptr);
857559995Selan   memory_full ();
857659995Selan   /*NOTREACHED*/
857759995Selan   return 0;
857859995Selan }
857959995Selan 
858059995Selan static char *
xrealloc(old,size)858159995Selan xrealloc (old, size)
858259995Selan      char *old;
858359995Selan      unsigned size;
858459995Selan {
858559995Selan   register char *ptr = (char *) realloc (old, size);
858659995Selan   if (ptr != 0) return (ptr);
858759995Selan   memory_full ();
858859995Selan   /*NOTREACHED*/
858959995Selan   return 0;
859059995Selan }
859159995Selan 
859259995Selan static char *
xcalloc(number,size)859359995Selan xcalloc (number, size)
859459995Selan      unsigned number, size;
859559995Selan {
859659995Selan   register unsigned total = number * size;
859759995Selan   register char *ptr = (char *) malloc (total);
859859995Selan   if (ptr != 0) {
859959995Selan     if (total > 100)
860059995Selan       bzero (ptr, total);
860159995Selan     else {
860259995Selan       /* It's not too long, so loop, zeroing by longs.
860359995Selan 	 It must be safe because malloc values are always well aligned.  */
860459995Selan       register long *zp = (long *) ptr;
860559995Selan       register long *zl = (long *) (ptr + total - 4);
860659995Selan       register int i = total - 4;
860759995Selan       while (zp < zl)
860859995Selan 	*zp++ = 0;
860959995Selan       if (i < 0)
861059995Selan 	i = 0;
861159995Selan       while (i < total)
861259995Selan 	ptr[i++] = 0;
861359995Selan     }
861459995Selan     return ptr;
861559995Selan   }
861659995Selan   memory_full ();
861759995Selan   /*NOTREACHED*/
861859995Selan   return 0;
861959995Selan }
862059995Selan 
862159995Selan static char *
savestring(input)862259995Selan savestring (input)
862359995Selan      char *input;
862459995Selan {
862559995Selan   unsigned size = strlen (input);
862659995Selan   char *output = xmalloc (size + 1);
862759995Selan   strcpy (output, input);
862859995Selan   return output;
862959995Selan }
863059995Selan 
863159995Selan /* Get the file-mode and data size of the file open on FD
863259995Selan    and store them in *MODE_POINTER and *SIZE_POINTER.  */
863359995Selan 
863459995Selan static int
file_size_and_mode(fd,mode_pointer,size_pointer)863559995Selan file_size_and_mode (fd, mode_pointer, size_pointer)
863659995Selan      int fd;
863759995Selan      int *mode_pointer;
863859995Selan      long int *size_pointer;
863959995Selan {
864059995Selan   struct stat sbuf;
864159995Selan 
864259995Selan   if (fstat (fd, &sbuf) < 0) return (-1);
864359995Selan   if (mode_pointer) *mode_pointer = sbuf.st_mode;
864459995Selan   if (size_pointer) *size_pointer = sbuf.st_size;
864559995Selan   return 0;
864659995Selan }
864759995Selan 
864859995Selan #ifdef VMS
864959995Selan 
865059995Selan /* Under VMS we need to fix up the "include" specification
865159995Selan    filename so that everything following the 1st slash is
865259995Selan    changed into its correct VMS file specification. */
865359995Selan 
865459995Selan static void
hack_vms_include_specification(fname)865559995Selan hack_vms_include_specification (fname)
865659995Selan      char *fname;
865759995Selan {
865859995Selan   register char *cp, *cp1, *cp2;
865959995Selan   int f, check_filename_before_returning, no_prefix_seen;
866059995Selan   char Local[512];
866159995Selan 
866259995Selan   check_filename_before_returning = 0;
866359995Selan   no_prefix_seen = 0;
866459995Selan 
866559995Selan   /* Ignore leading "./"s */
866659995Selan   while (fname[0] == '.' && fname[1] == '/') {
866759995Selan     strcpy (fname, fname+2);
866859995Selan     no_prefix_seen = 1;		/* mark this for later */
866959995Selan   }
867059995Selan   /* Look for the boundary between the VMS and UNIX filespecs */
867159995Selan   cp = rindex (fname, ']');	/* Look for end of dirspec. */
867259995Selan   if (cp == 0) cp = rindex (fname, '>'); /* ... Ditto		    */
867359995Selan   if (cp == 0) cp = rindex (fname, ':'); /* Look for end of devspec. */
867459995Selan   if (cp) {
867559995Selan     cp++;
867659995Selan   } else {
867759995Selan     cp = index (fname, '/');	/* Look for the "/" */
867859995Selan   }
867959995Selan 
868059995Selan   cp2 = Local;			/* initialize */
868159995Selan 
868259995Selan   /* We are trying to do a number of things here.  First of all, we are
868359995Selan      trying to hammer the filenames into a standard format, such that later
868459995Selan      processing can handle them.
868559995Selan 
868659995Selan      If the file name contains something like [dir.], then it recognizes this
868759995Selan      as a root, and strips the ".]".  Later processing will add whatever is
868859995Selan      needed to get things working properly.
868959995Selan 
869059995Selan      If no device is specified, then the first directory name is taken to be
869159995Selan      a device name (or a rooted logical). */
869259995Selan 
869359995Selan   /* See if we found that 1st slash */
869459995Selan   if (cp == 0) return;		/* Nothing to do!!! */
869559995Selan   if (*cp != '/') return;	/* Nothing to do!!! */
869659995Selan   /* Point to the UNIX filename part (which needs to be fixed!) */
869759995Selan   cp1 = cp+1;
869859995Selan   /* If the directory spec is not rooted, we can just copy
869959995Selan      the UNIX filename part and we are done */
870059995Selan   if (((cp - fname) > 1) && ((cp[-1] == ']') || (cp[-1] == '>'))) {
870159995Selan     if (cp[-2] != '.') {
870259995Selan       /*
870359995Selan        * The VMS part ends in a `]', and the preceding character is not a `.'.
870459995Selan        * We strip the `]', and then splice the two parts of the name in the
870559995Selan        * usual way.  Given the default locations for include files in cccp.c,
870659995Selan        * we will only use this code if the user specifies alternate locations
870759995Selan        * with the /include (-I) switch on the command line.  */
870859995Selan       cp -= 1;			/* Strip "]" */
870959995Selan       cp1--;			/* backspace */
871059995Selan     } else {
871159995Selan       /*
871259995Selan        * The VMS part has a ".]" at the end, and this will not do.  Later
871359995Selan        * processing will add a second directory spec, and this would be a syntax
871459995Selan        * error.  Thus we strip the ".]", and thus merge the directory specs.
871559995Selan        * We also backspace cp1, so that it points to a '/'.  This inhibits the
871659995Selan        * generation of the 000000 root directory spec (which does not belong here
871759995Selan        * in this case).
871859995Selan        */
871959995Selan       cp -= 2;			/* Strip ".]" */
872059995Selan       cp1--; };			/* backspace */
872159995Selan   } else {
872259995Selan 
872359995Selan     /* We drop in here if there is no VMS style directory specification yet.
872459995Selan      * If there is no device specification either, we make the first dir a
872559995Selan      * device and try that.  If we do not do this, then we will be essentially
872659995Selan      * searching the users default directory (as if they did a #include "asdf.h").
872759995Selan      *
872859995Selan      * Then all we need to do is to push a '[' into the output string. Later
872959995Selan      * processing will fill this in, and close the bracket.
873059995Selan      */
873159995Selan     if(cp[-1] != ':') *cp2++ = ':'; /* dev not in spec.  take first dir */
873259995Selan     *cp2++ = '[';		/* Open the directory specification */
873359995Selan   }
873459995Selan 
873559995Selan   /* at this point we assume that we have the device spec, and (at least
873659995Selan      the opening "[" for a directory specification.  We may have directories
873759995Selan      specified already */
873859995Selan 
873959995Selan   /* If there are no other slashes then the filename will be
874059995Selan      in the "root" directory.  Otherwise, we need to add
874159995Selan      directory specifications. */
874259995Selan   if (index (cp1, '/') == 0) {
874359995Selan     /* Just add "000000]" as the directory string */
874459995Selan     strcpy (cp2, "000000]");
874559995Selan     cp2 += strlen (cp2);
874659995Selan     check_filename_before_returning = 1; /* we might need to fool with this later */
874759995Selan   } else {
874859995Selan     /* As long as there are still subdirectories to add, do them. */
874959995Selan     while (index (cp1, '/') != 0) {
875059995Selan       /* If this token is "." we can ignore it */
875159995Selan       if ((cp1[0] == '.') && (cp1[1] == '/')) {
875259995Selan 	cp1 += 2;
875359995Selan 	continue;
875459995Selan       }
875559995Selan       /* Add a subdirectory spec. Do not duplicate "." */
875659995Selan       if (cp2[-1] != '.' && cp2[-1] != '[' && cp2[-1] != '<')
875759995Selan 	*cp2++ = '.';
875859995Selan       /* If this is ".." then the spec becomes "-" */
875959995Selan       if ((cp1[0] == '.') && (cp1[1] == '.') && (cp[2] == '/')) {
876059995Selan 	/* Add "-" and skip the ".." */
876159995Selan 	*cp2++ = '-';
876259995Selan 	cp1 += 3;
876359995Selan 	continue;
876459995Selan       }
876559995Selan       /* Copy the subdirectory */
876659995Selan       while (*cp1 != '/') *cp2++= *cp1++;
876759995Selan       cp1++;			/* Skip the "/" */
876859995Selan     }
876959995Selan     /* Close the directory specification */
877059995Selan     if(cp2[-1] == '.')		/* no trailing periods */
877159995Selan       cp2--;
877259995Selan     *cp2++ = ']';
877359995Selan   }
877459995Selan   /* Now add the filename */
877559995Selan   while (*cp1) *cp2++ = *cp1++;
877659995Selan   *cp2 = 0;
877759995Selan   /* Now append it to the original VMS spec. */
877859995Selan   strcpy (cp, Local);
877959995Selan 
878059995Selan   /* If we put a [000000] in the filename, try to open it first. If this fails,
878159995Selan      remove the [000000], and return that name.  This provides flexibility
878259995Selan      to the user in that they can use both rooted and non-rooted logical names
878359995Selan      to point to the location of the file.  */
878459995Selan 
878559995Selan   if (check_filename_before_returning && no_prefix_seen) {
878659995Selan     f = open (fname, O_RDONLY, 0666);
878759995Selan     if (f >= 0) {
878859995Selan       /* The file name is OK as it is, so return it as is.  */
878959995Selan       close (f);
879059995Selan       return;
879159995Selan     }
879259995Selan     /* The filename did not work.  Try to remove the [000000] from the name,
879359995Selan        and return it.  */
879459995Selan     cp = index (fname, '[');
879559995Selan     cp2 = index (fname, ']') + 1;
879659995Selan     strcpy (cp, cp2);		/* this gets rid of it */
879759995Selan   }
879859995Selan   return;
879959995Selan }
880059995Selan #endif	/* VMS */
880159995Selan 
880259995Selan #ifdef	VMS
880359995Selan 
880459995Selan /* These are the read/write replacement routines for
880559995Selan    VAX-11 "C".  They make read/write behave enough
880659995Selan    like their UNIX counterparts that CCCP will work */
880759995Selan 
880859995Selan static int
read(fd,buf,size)880959995Selan read (fd, buf, size)
881059995Selan      int fd;
881159995Selan      char *buf;
881259995Selan      int size;
881359995Selan {
881459995Selan #undef	read	/* Get back the REAL read routine */
881559995Selan   register int i;
881659995Selan   register int total = 0;
881759995Selan 
881859995Selan   /* Read until the buffer is exhausted */
881959995Selan   while (size > 0) {
882059995Selan     /* Limit each read to 32KB */
882159995Selan     i = (size > (32*1024)) ? (32*1024) : size;
882259995Selan     i = read (fd, buf, i);
882359995Selan     if (i <= 0) {
882459995Selan       if (i == 0) return (total);
882559995Selan       return(i);
882659995Selan     }
882759995Selan     /* Account for this read */
882859995Selan     total += i;
882959995Selan     buf += i;
883059995Selan     size -= i;
883159995Selan   }
883259995Selan   return (total);
883359995Selan }
883459995Selan 
883559995Selan static int
write(fd,buf,size)883659995Selan write (fd, buf, size)
883759995Selan      int fd;
883859995Selan      char *buf;
883959995Selan      int size;
884059995Selan {
884159995Selan #undef	write	/* Get back the REAL write routine */
884259995Selan   int i;
884359995Selan   int j;
884459995Selan 
884559995Selan   /* Limit individual writes to 32Kb */
884659995Selan   i = size;
884759995Selan   while (i > 0) {
884859995Selan     j = (i > (32*1024)) ? (32*1024) : i;
884959995Selan     if (write (fd, buf, j) < 0) return (-1);
885059995Selan     /* Account for the data written */
885159995Selan     buf += j;
885259995Selan     i -= j;
885359995Selan   }
885459995Selan   return (size);
885559995Selan }
885659995Selan 
885759995Selan /* The following wrapper functions supply additional arguments to the VMS
885859995Selan    I/O routines to optimize performance with file handling.  The arguments
885959995Selan    are:
886059995Selan      "mbc=16" - Set multi-block count to 16 (use a 8192 byte buffer).
886159995Selan      "deq=64" - When extending the file, extend it in chunks of 32Kbytes.
886259995Selan      "fop=tef"- Truncate unused portions of file when closing file.
886359995Selan      "shr=nil"- Disallow file sharing while file is open.
886459995Selan  */
886559995Selan 
886659995Selan static FILE *
freopen(fname,type,oldfile)886759995Selan freopen (fname, type, oldfile)
886859995Selan      char *fname;
886959995Selan      char *type;
887059995Selan      FILE *oldfile;
887159995Selan {
887259995Selan #undef	freopen	/* Get back the REAL fopen routine */
887359995Selan   if (strcmp (type, "w") == 0)
887459995Selan     return freopen (fname, type, oldfile, "mbc=16", "deq=64", "fop=tef", "shr=nil");
887559995Selan   return freopen (fname, type, oldfile, "mbc=16");
887659995Selan }
887759995Selan 
887859995Selan static FILE *
fopen(fname,type)887959995Selan fopen (fname, type)
888059995Selan      char *fname;
888159995Selan      char *type;
888259995Selan {
888359995Selan #undef fopen	/* Get back the REAL fopen routine */
888459995Selan   if (strcmp (type, "w") == 0)
888559995Selan     return fopen (fname, type, "mbc=16", "deq=64", "fop=tef", "shr=nil");
888659995Selan   return fopen (fname, type, "mbc=16");
888759995Selan }
888859995Selan 
888959995Selan static int
open(fname,flags,prot)889059995Selan open (fname, flags, prot)
889159995Selan      char *fname;
889259995Selan      int flags;
889359995Selan      int prot;
889459995Selan {
889559995Selan #undef open	/* Get back the REAL open routine */
889659995Selan   return open (fname, flags, prot, "mbc=16", "deq=64", "fop=tef");
889759995Selan }
889859995Selan 
889959995Selan /* Avoid run-time library bug, where copying M out of N+M characters with
890059995Selan    N >= 65535 results in VAXCRTL's strncat falling into an infinite loop.
890159995Selan    gcc-cpp exercises this particular bug.  */
890259995Selan 
890359995Selan static char *
strncat(dst,src,cnt)890459995Selan strncat (dst, src, cnt)
890559995Selan      char *dst;
890659995Selan      const char *src;
890759995Selan      unsigned cnt;
890859995Selan {
890959995Selan   register char *d = dst, *s = (char *) src;
891059995Selan   register int n = cnt;	/* convert to _signed_ type */
891159995Selan 
891259995Selan   while (*d) d++;	/* advance to end */
891359995Selan   while (--n >= 0)
891459995Selan     if (!(*d++ = *s++)) break;
891559995Selan   if (n < 0) *d = '\0';
891659995Selan   return dst;
891759995Selan }
891859995Selan #endif /* VMS */
8919