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, ©_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