diff options
Diffstat (limited to 'contrib/gcc/cppinit.c')
-rw-r--r-- | contrib/gcc/cppinit.c | 2965 |
1 files changed, 1581 insertions, 1384 deletions
diff --git a/contrib/gcc/cppinit.c b/contrib/gcc/cppinit.c index 453cc58..ab3dad7 100644 --- a/contrib/gcc/cppinit.c +++ b/contrib/gcc/cppinit.c @@ -1,6 +1,6 @@ /* CPP Library. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Per Bothner, 1994-95. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 @@ -21,164 +21,63 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" - -#define FAKE_CONST #include "cpplib.h" #include "cpphash.h" -#include "output.h" #include "prefix.h" #include "intl.h" +#include "version.h" +#include "mkdeps.h" +#include "cppdefault.h" +#include "except.h" /* for USING_SJLJ_EXCEPTIONS */ -/* XXX Should be in a header file. */ -extern char *version_string; - -/* Predefined symbols, built-in macros, and the default include path. */ +/* Predefined symbols, built-in macros, and the default include path. */ #ifndef GET_ENV_PATH_LIST #define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0) #endif -/* By default, colon separates directories in a path. */ -#ifndef PATH_SEPARATOR -#define PATH_SEPARATOR ':' -#endif - -#ifndef STANDARD_INCLUDE_DIR -#define STANDARD_INCLUDE_DIR "/usr/include" -#endif - -/* We let tm.h override the types used here, to handle trivial differences - such as the choice of unsigned int or long unsigned int for size_t. - When machines start needing nontrivial differences in the size type, - it would be best to do something here to figure out automatically - from other information what type to use. */ - -/* The string value for __SIZE_TYPE__. */ - -#ifndef SIZE_TYPE -#define SIZE_TYPE "long unsigned int" -#endif - -/* The string value for __PTRDIFF_TYPE__. */ - -#ifndef PTRDIFF_TYPE -#define PTRDIFF_TYPE "long int" -#endif - -/* The string value for __WCHAR_TYPE__. */ - -#ifndef WCHAR_TYPE -#define WCHAR_TYPE "int" -#endif -#define CPP_WCHAR_TYPE(PFILE) \ - (CPP_OPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE) - -/* The string value for __USER_LABEL_PREFIX__ */ - -#ifndef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "" -#endif - -/* The string value for __REGISTER_PREFIX__ */ - -#ifndef REGISTER_PREFIX -#define REGISTER_PREFIX "" -#endif - -/* Suffix for object files, and known input-file extensions. */ -static char *known_suffixes[] = -{ - ".c", ".C", ".s", ".S", ".m", - ".cc", ".cxx", ".cpp", ".cp", ".c++", - NULL -}; - -#ifndef OBJECT_SUFFIX -# ifdef VMS -# define OBJECT_SUFFIX ".obj" +/* Windows does not natively support inodes, and neither does MSDOS. + Cygwin's emulation can generate non-unique inodes, so don't use it. + VMS has non-numeric inodes. */ +#ifdef VMS +# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A))) +# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC)) +#else +# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__ +# define INO_T_EQ(A, B) 0 # else -# define OBJECT_SUFFIX ".o" +# define INO_T_EQ(A, B) ((A) == (B)) # endif +# define INO_T_COPY(DEST, SRC) (DEST) = (SRC) #endif +/* Internal structures and prototypes. */ -/* This is the default list of directories to search for include files. - It may be overridden by the various -I and -ixxx options. - - #include "file" looks in the same directory as the current file, - then this list. - #include <file> just looks in this list. - - All these directories are treated as `system' include directories - (they are not subject to pedantic warnings in some cases). */ - -static struct default_include -{ - char *fname; /* The name of the directory. */ - char *component; /* The component containing the directory - (see update_path in prefix.c) */ - int cplusplus; /* Only look here if we're compiling C++. */ - int cxx_aware; /* Includes in this directory don't need to - be wrapped in extern "C" when compiling - C++. This is not used anymore. */ -} -include_defaults_array[] -#ifdef INCLUDE_DEFAULTS -= INCLUDE_DEFAULTS; -#else -= { - /* Pick up GNU C++ specific include files. */ - { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, -#ifdef CROSS_COMPILE - /* This is the dir for fixincludes. Put it just before - the files that we fix. */ - { GCC_INCLUDE_DIR, "GCC", 0, 0 }, - /* For cross-compilation, this dir name is generated - automatically in Makefile.in. */ - { CROSS_INCLUDE_DIR, "GCC", 0, 0 }, -#ifdef TOOL_INCLUDE_DIR - /* This is another place that the target system's headers might be. */ - { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, -#endif -#else /* not CROSS_COMPILE */ -#ifdef LOCAL_INCLUDE_DIR - /* This should be /usr/local/include and should come before - the fixincludes-fixed header files. */ - { LOCAL_INCLUDE_DIR, 0, 0, 1 }, -#endif -#ifdef TOOL_INCLUDE_DIR - /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here. - Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */ - { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, -#endif - /* This is the dir for fixincludes. Put it just before - the files that we fix. */ - { GCC_INCLUDE_DIR, "GCC", 0, 0 }, - /* Some systems have an extra dir of include files. */ -#ifdef SYSTEM_INCLUDE_DIR - { SYSTEM_INCLUDE_DIR, 0, 0, 0 }, -#endif -#ifndef STANDARD_INCLUDE_COMPONENT -#define STANDARD_INCLUDE_COMPONENT 0 -#endif - { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 }, -#endif /* not CROSS_COMPILE */ - { 0, 0, 0, 0 } - }; -#endif /* no INCLUDE_DEFAULTS */ - -/* Internal structures and prototypes. */ - -/* A `struct pending_option' remembers one -D, -A, -U, -include, or -imacros - switch. There are four lists: one for -D and -U, one for -A, one - for -include, one for -imacros. `undef' is set for -U, clear for - -D, ignored for the others. - (Future: add an equivalent of -U for -A) */ +/* A `struct pending_option' remembers one -D, -A, -U, -include, or + -imacros switch. */ +typedef void (* cl_directive_handler) PARAMS ((cpp_reader *, const char *)); struct pending_option { struct pending_option *next; - char *arg; - int undef; + const char *arg; + cl_directive_handler handler; +}; + +/* The `pending' structure accumulates all the options that are not + actually processed until we hit cpp_read_main_file. It consists of + several lists, one for each type of option. We keep both head and + tail pointers for quick insertion. */ +struct cpp_pending +{ + struct pending_option *directive_head, *directive_tail; + + struct search_path *quote_head, *quote_tail; + struct search_path *brack_head, *brack_tail; + struct search_path *systm_head, *systm_tail; + struct search_path *after_head, *after_tail; + + struct pending_option *imacros_head, *imacros_tail; + struct pending_option *include_head, *include_tail; }; #ifdef __STDC__ @@ -195,196 +94,73 @@ struct pending_option } while (0) #endif -static void initialize_char_syntax PARAMS ((int)); static void print_help PARAMS ((void)); static void path_include PARAMS ((cpp_reader *, - struct cpp_pending *, char *, int)); -static void initialize_builtins PARAMS ((cpp_reader *)); +static void init_library PARAMS ((void)); +static void init_builtins PARAMS ((cpp_reader *)); static void append_include_chain PARAMS ((cpp_reader *, - struct cpp_pending *, - char *, int)); - -/* Last argument to append_include_chain: chain to use */ -enum { QUOTE = 0, BRACKET, SYSTEM, AFTER }; - -/* If gcc is in use (stage2/stage3) we can make these tables initialized - data. */ -#if defined __GNUC__ && (__GNUC__ > 2 \ - || (__GNUC__ == 2 && __GNUC_MINOR__ > 8)) -/* Table to tell if a character is legal as the second or later character - of a C identifier. */ -U_CHAR is_idchar[256] = -{ - ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, - ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, - ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, - ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, - ['y'] = 1, ['z'] = 1, - - ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, - ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, - ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, - ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, - ['Y'] = 1, ['Z'] = 1, - - ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, - ['7'] = 1, ['8'] = 1, ['9'] = 1, ['0'] = 1, - - ['_'] = 1, -}; + char *, int, int)); +static struct search_path * remove_dup_dir PARAMS ((cpp_reader *, + struct search_path *)); +static struct search_path * remove_dup_dirs PARAMS ((cpp_reader *, + struct search_path *)); +static void merge_include_chains PARAMS ((cpp_reader *)); +static bool push_include PARAMS ((cpp_reader *, + struct pending_option *)); +static void free_chain PARAMS ((struct pending_option *)); +static void set_lang PARAMS ((cpp_reader *, enum c_lang)); +static void init_dependency_output PARAMS ((cpp_reader *)); +static void init_standard_includes PARAMS ((cpp_reader *)); +static void read_original_filename PARAMS ((cpp_reader *)); +static void new_pending_directive PARAMS ((struct cpp_pending *, + const char *, + cl_directive_handler)); +static void output_deps PARAMS ((cpp_reader *)); +static int parse_option PARAMS ((const char *)); + +/* Fourth argument to append_include_chain: chain to use. + Note it's never asked to append to the quote chain. */ +enum { BRACKET = 0, SYSTEM, AFTER }; + +/* If we have designated initializers (GCC >2.7) these tables can be + initialized, constant data. Otherwise, they have to be filled in at + runtime. */ +#if HAVE_DESIGNATED_INITIALIZERS + +#define init_trigraph_map() /* Nothing. */ +#define TRIGRAPH_MAP \ +__extension__ const U_CHAR _cpp_trigraph_map[UCHAR_MAX + 1] = { + +#define END }; +#define s(p, v) [p] = v, -/* Table to tell if a character is legal as the first character of - a C identifier. */ -U_CHAR is_idstart[256] = -{ - ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, - ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, - ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, - ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, - ['y'] = 1, ['z'] = 1, - - ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, - ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, - ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, - ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, - ['Y'] = 1, ['Z'] = 1, - - ['_'] = 1, -}; - -/* Table to tell if a character is horizontal space. - \r is magical, so it is not in here. */ -U_CHAR is_hor_space[256] = -{ - [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1, -}; -/* table to tell if a character is horizontal or vertical space. */ -U_CHAR is_space[256] = -{ - [' '] = 1, ['\t'] = 1, ['\v'] = 1, ['\f'] = 1, ['\n'] = 1, -}; -/* Table to handle trigraph conversion, which occurs before all other - processing, everywhere in the file. (This is necessary since one - of the trigraphs encodes backslash.) Note it's off by default. - - from to from to from to - ?? = # ?? ) ] ?? ! | - ?? ( [ ?? ' ^ ?? > } - ?? / \ ?? < { ?? - ~ - - There is not a space between the ?? and the third char. I put spaces - there to avoid warnings when compiling this file. */ -U_CHAR trigraph_table[256] = -{ - ['='] = '#', [')'] = ']', ['!'] = '|', - ['('] = '[', ['\''] = '^', ['>'] = '}', - ['/'] = '\\', ['<'] = '{', ['-'] = '~', -}; +#else -/* This function will be entirely removed soon. */ -static inline void -initialize_char_syntax (dollar_in_ident) - int dollar_in_ident; -{ - is_idchar['$'] = dollar_in_ident; - is_idstart['$'] = dollar_in_ident; -} +#define TRIGRAPH_MAP U_CHAR _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \ + static void init_trigraph_map PARAMS ((void)) { \ + unsigned char *x = _cpp_trigraph_map; -#else /* Not GCC. */ +#define END } +#define s(p, v) x[p] = v; -U_CHAR is_idchar[256] = { 0 }; -U_CHAR is_idstart[256] = { 0 }; -U_CHAR is_hor_space[256] = { 0 }; -U_CHAR is_space[256] = { 0 }; -U_CHAR trigraph_table[256] = { 0 }; +#endif -/* Initialize syntactic classifications of characters. */ -static void -initialize_char_syntax (dollar_in_ident) - int dollar_in_ident; -{ - is_idstart['a'] = 1; is_idstart['b'] = 1; is_idstart['c'] = 1; - is_idstart['d'] = 1; is_idstart['e'] = 1; is_idstart['f'] = 1; - is_idstart['g'] = 1; is_idstart['h'] = 1; is_idstart['i'] = 1; - is_idstart['j'] = 1; is_idstart['k'] = 1; is_idstart['l'] = 1; - is_idstart['m'] = 1; is_idstart['n'] = 1; is_idstart['o'] = 1; - is_idstart['p'] = 1; is_idstart['q'] = 1; is_idstart['r'] = 1; - is_idstart['s'] = 1; is_idstart['t'] = 1; is_idstart['u'] = 1; - is_idstart['v'] = 1; is_idstart['w'] = 1; is_idstart['x'] = 1; - is_idstart['y'] = 1; is_idstart['z'] = 1; - - is_idstart['A'] = 1; is_idstart['B'] = 1; is_idstart['C'] = 1; - is_idstart['D'] = 1; is_idstart['E'] = 1; is_idstart['F'] = 1; - is_idstart['G'] = 1; is_idstart['H'] = 1; is_idstart['I'] = 1; - is_idstart['J'] = 1; is_idstart['K'] = 1; is_idstart['L'] = 1; - is_idstart['M'] = 1; is_idstart['N'] = 1; is_idstart['O'] = 1; - is_idstart['P'] = 1; is_idstart['Q'] = 1; is_idstart['R'] = 1; - is_idstart['S'] = 1; is_idstart['T'] = 1; is_idstart['U'] = 1; - is_idstart['V'] = 1; is_idstart['W'] = 1; is_idstart['X'] = 1; - is_idstart['Y'] = 1; is_idstart['Z'] = 1; - - is_idstart['_'] = 1; - - is_idchar['a'] = 1; is_idchar['b'] = 1; is_idchar['c'] = 1; - is_idchar['d'] = 1; is_idchar['e'] = 1; is_idchar['f'] = 1; - is_idchar['g'] = 1; is_idchar['h'] = 1; is_idchar['i'] = 1; - is_idchar['j'] = 1; is_idchar['k'] = 1; is_idchar['l'] = 1; - is_idchar['m'] = 1; is_idchar['n'] = 1; is_idchar['o'] = 1; - is_idchar['p'] = 1; is_idchar['q'] = 1; is_idchar['r'] = 1; - is_idchar['s'] = 1; is_idchar['t'] = 1; is_idchar['u'] = 1; - is_idchar['v'] = 1; is_idchar['w'] = 1; is_idchar['x'] = 1; - is_idchar['y'] = 1; is_idchar['z'] = 1; - - is_idchar['A'] = 1; is_idchar['B'] = 1; is_idchar['C'] = 1; - is_idchar['D'] = 1; is_idchar['E'] = 1; is_idchar['F'] = 1; - is_idchar['G'] = 1; is_idchar['H'] = 1; is_idchar['I'] = 1; - is_idchar['J'] = 1; is_idchar['K'] = 1; is_idchar['L'] = 1; - is_idchar['M'] = 1; is_idchar['N'] = 1; is_idchar['O'] = 1; - is_idchar['P'] = 1; is_idchar['Q'] = 1; is_idchar['R'] = 1; - is_idchar['S'] = 1; is_idchar['T'] = 1; is_idchar['U'] = 1; - is_idchar['V'] = 1; is_idchar['W'] = 1; is_idchar['X'] = 1; - is_idchar['Y'] = 1; is_idchar['Z'] = 1; - - is_idchar['1'] = 1; is_idchar['2'] = 1; is_idchar['3'] = 1; - is_idchar['4'] = 1; is_idchar['5'] = 1; is_idchar['6'] = 1; - is_idchar['7'] = 1; is_idchar['8'] = 1; is_idchar['9'] = 1; - is_idchar['0'] = 1; - - is_idchar['_'] = 1; - - is_idchar['$'] = dollar_in_ident; - is_idstart['$'] = dollar_in_ident; - - /* white space tables */ - is_hor_space[' '] = 1; - is_hor_space['\t'] = 1; - is_hor_space['\v'] = 1; - is_hor_space['\f'] = 1; - - is_space[' '] = 1; - is_space['\t'] = 1; - is_space['\v'] = 1; - is_space['\f'] = 1; - is_space['\n'] = 1; - - /* trigraph conversion */ - trigraph_table['='] = '#'; trigraph_table[')'] = ']'; - trigraph_table['!'] = '|'; trigraph_table['('] = '['; - trigraph_table['\''] = '^'; trigraph_table['>'] = '}'; - trigraph_table['/'] = '\\'; trigraph_table['<'] = '{'; - trigraph_table['-'] = '~'; -} +TRIGRAPH_MAP + s('=', '#') s(')', ']') s('!', '|') + s('(', '[') s('\'', '^') s('>', '}') + s('/', '\\') s('<', '{') s('-', '~') +END -#endif /* Not GCC. */ +#undef s +#undef END +#undef TRIGRAPH_MAP /* Given a colon-separated list of file names PATH, add all the names to the search path for include files. */ - static void -path_include (pfile, pend, list, path) +path_include (pfile, list, path) cpp_reader *pfile; - struct cpp_pending *pend; char *list; int path; { @@ -412,7 +188,7 @@ path_include (pfile, pend, list, path) name[q - p] = 0; } - append_include_chain (pfile, pend, name, path); + append_include_chain (pfile, name, path, 0); /* Advance past this name. */ if (*q == 0) @@ -422,1274 +198,1555 @@ path_include (pfile, pend, list, path) while (1); } -/* Find the base name of a (partial) pathname FNAME. - Returns a pointer into the string passed in. - Accepts Unix (/-separated) paths on all systems, - DOS and VMS paths on those systems. */ -static char * -base_name (fname) - const char *fname; -{ - char *s = (char *)fname; - char *p; -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (ISALPHA (s[0]) && s[1] == ':') s += 2; - if ((p = rindex (s, '\\'))) s = p + 1; -#elif defined VMS - if ((p = rindex (s, ':'))) s = p + 1; /* Skip device. */ - if ((p = rindex (s, ']'))) s = p + 1; /* Skip directory. */ - if ((p = rindex (s, '>'))) s = p + 1; /* Skip alternate (int'n'l) dir. */ -#endif - if ((p = rindex (s, '/'))) s = p + 1; - return s; -} - - -/* Append DIR to include path PATH. DIR must be permanently allocated - and writable. */ +/* Append DIR to include path PATH. DIR must be allocated on the + heap; this routine takes responsibility for freeing it. CXX_AWARE + is non-zero if the header contains extern "C" guards for C++, + otherwise it is zero. */ static void -append_include_chain (pfile, pend, dir, path) +append_include_chain (pfile, dir, path, cxx_aware) cpp_reader *pfile; - struct cpp_pending *pend; char *dir; int path; + int cxx_aware ATTRIBUTE_UNUSED; { - struct file_name_list *new; + struct cpp_pending *pend = CPP_OPTION (pfile, pending); + struct search_path *new; struct stat st; unsigned int len; - simplify_pathname (dir); + if (*dir == '\0') + { + free (dir); + dir = xstrdup ("."); + } + _cpp_simplify_pathname (dir); + if (stat (dir, &st)) { - /* Dirs that don't exist are silently ignored. */ + /* Dirs that don't exist are silently ignored. */ if (errno != ENOENT) - cpp_perror_with_name (pfile, dir); - else if (CPP_OPTIONS (pfile)->verbose) - cpp_notice ("ignoring nonexistent directory `%s'\n", dir); + cpp_notice_from_errno (pfile, dir); + else if (CPP_OPTION (pfile, verbose)) + fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir); + free (dir); return; } if (!S_ISDIR (st.st_mode)) { - cpp_message (pfile, 1, "%s: %s: Not a directory", progname, dir); + cpp_notice (pfile, "%s: Not a directory", dir); + free (dir); return; } len = strlen (dir); if (len > pfile->max_include_len) pfile->max_include_len = len; - - new = (struct file_name_list *)xmalloc (sizeof (struct file_name_list)); + + new = (struct search_path *) xmalloc (sizeof (struct search_path)); new->name = dir; - new->nlen = len; - new->ino = st.st_ino; + new->len = len; + INO_T_COPY (new->ino, st.st_ino); new->dev = st.st_dev; - new->sysp = (path == SYSTEM); + /* Both systm and after include file lists should be treated as system + include files since these two lists are really just a concatenation + of one "system" list. */ + if (path == SYSTEM || path == AFTER) +#ifdef NO_IMPLICIT_EXTERN_C + new->sysp = 1; +#else + new->sysp = cxx_aware ? 1 : 2; +#endif + else + new->sysp = 0; new->name_map = NULL; + new->next = NULL; switch (path) { - case QUOTE: APPEND (pend, quote, new); break; case BRACKET: APPEND (pend, brack, new); break; case SYSTEM: APPEND (pend, systm, new); break; case AFTER: APPEND (pend, after, new); break; } } +/* Handle a duplicated include path. PREV is the link in the chain + before the duplicate. The duplicate is removed from the chain and + freed. Returns PREV. */ +static struct search_path * +remove_dup_dir (pfile, prev) + cpp_reader *pfile; + struct search_path *prev; +{ + struct search_path *cur = prev->next; -/* Write out a #define command for the special named MACRO_NAME - to PFILE's token_buffer. */ + if (CPP_OPTION (pfile, verbose)) + fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name); -static void -dump_special_to_buffer (pfile, macro_name) + prev->next = cur->next; + free ((PTR) cur->name); + free (cur); + + return prev; +} + +/* Remove duplicate directories from a chain. Returns the tail of the + chain, or NULL if the chain is empty. This algorithm is quadratic + in the number of -I switches, which is acceptable since there + aren't usually that many of them. */ +static struct search_path * +remove_dup_dirs (pfile, head) cpp_reader *pfile; - char *macro_name; + struct search_path *head; { - static char define_directive[] = "#define "; - int macro_name_length = strlen (macro_name); - output_line_command (pfile, same_file); - CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length); - CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1); - CPP_PUTS_Q (pfile, macro_name, macro_name_length); - CPP_PUTC_Q (pfile, ' '); - cpp_expand_to_buffer (pfile, macro_name, macro_name_length); - CPP_PUTC (pfile, '\n'); + struct search_path *prev = NULL, *cur, *other; + + for (cur = head; cur; cur = cur->next) + { + for (other = head; other != cur; other = other->next) + if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev) + { + if (cur->sysp && !other->sysp) + { + cpp_warning (pfile, + "changing search order for system directory \"%s\"", + cur->name); + if (strcmp (cur->name, other->name)) + cpp_warning (pfile, + " as it is the same as non-system directory \"%s\"", + other->name); + else + cpp_warning (pfile, + " as it has already been specified as a non-system directory"); + } + cur = remove_dup_dir (pfile, prev); + break; + } + prev = cur; + } + + return prev; } -/* Initialize a cpp_options structure. */ -void -cpp_options_init (opts) - cpp_options *opts; +/* Merge the four include chains together in the order quote, bracket, + system, after. Remove duplicate dirs (as determined by + INO_T_EQ()). The system_include and after_include chains are never + referred to again after this function; all access is through the + bracket_include path. */ +static void +merge_include_chains (pfile) + cpp_reader *pfile; { - bzero ((char *) opts, sizeof (struct cpp_options)); + struct search_path *quote, *brack, *systm, *qtail; + + struct cpp_pending *pend = CPP_OPTION (pfile, pending); + + quote = pend->quote_head; + brack = pend->brack_head; + systm = pend->systm_head; + qtail = pend->quote_tail; + + /* Paste together bracket, system, and after include chains. */ + if (systm) + pend->systm_tail->next = pend->after_head; + else + systm = pend->after_head; - opts->dollars_in_ident = 1; - opts->cplusplus_comments = 1; - opts->warn_import = 1; + if (brack) + pend->brack_tail->next = systm; + else + brack = systm; + + /* This is a bit tricky. First we drop dupes from the quote-include + list. Then we drop dupes from the bracket-include list. + Finally, if qtail and brack are the same directory, we cut out + brack and move brack up to point to qtail. + + We can't just merge the lists and then uniquify them because + then we may lose directories from the <> search path that should + be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux. It is however + safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written + -Ibar -I- -Ifoo -Iquux. */ + + remove_dup_dirs (pfile, brack); + qtail = remove_dup_dirs (pfile, quote); + + if (quote) + { + qtail->next = brack; - opts->pending = (struct cpp_pending *) xmalloc (sizeof (struct cpp_pending)); - bzero ((char *) opts->pending, sizeof (struct cpp_pending)); + /* If brack == qtail, remove brack as it's simpler. */ + if (INO_T_EQ (qtail->ino, brack->ino) && qtail->dev == brack->dev) + brack = remove_dup_dir (pfile, qtail); + } + else + quote = brack; + + CPP_OPTION (pfile, quote_include) = quote; + CPP_OPTION (pfile, bracket_include) = brack; } -/* Initialize a cpp_reader structure. */ -void -cpp_reader_init (pfile) +/* A set of booleans indicating what CPP features each source language + requires. */ +struct lang_flags +{ + char c99; + char objc; + char cplusplus; + char extended_numbers; + char trigraphs; + char dollars_in_ident; + char cplusplus_comments; + char digraphs; +}; + +/* ??? Enable $ in identifiers in assembly? */ +static const struct lang_flags lang_defaults[] = +{ /* c99 objc c++ xnum trig dollar c++comm digr */ + /* GNUC89 */ { 0, 0, 0, 1, 0, 1, 1, 1 }, + /* GNUC99 */ { 1, 0, 0, 1, 0, 1, 1, 1 }, + /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 1, 0, 0, 1 }, + /* STDC99 */ { 1, 0, 0, 1, 1, 0, 1, 1 }, + /* GNUCXX */ { 0, 0, 1, 1, 0, 1, 1, 1 }, + /* CXX98 */ { 0, 0, 1, 1, 1, 0, 1, 1 }, + /* OBJC */ { 0, 1, 0, 1, 0, 1, 1, 1 }, + /* OBJCXX */ { 0, 1, 1, 1, 0, 1, 1, 1 }, + /* ASM */ { 0, 0, 0, 1, 0, 0, 1, 0 } +}; + +/* Sets internal flags correctly for a given language. */ +static void +set_lang (pfile, lang) cpp_reader *pfile; + enum c_lang lang; { - bzero ((char *) pfile, sizeof (cpp_reader)); -#if 0 - pfile->get_token = cpp_get_token; -#endif + const struct lang_flags *l = &lang_defaults[(int) lang]; + + CPP_OPTION (pfile, lang) = lang; + + CPP_OPTION (pfile, c99) = l->c99; + CPP_OPTION (pfile, objc) = l->objc; + CPP_OPTION (pfile, cplusplus) = l->cplusplus; + CPP_OPTION (pfile, extended_numbers) = l->extended_numbers; + CPP_OPTION (pfile, trigraphs) = l->trigraphs; + CPP_OPTION (pfile, dollars_in_ident) = l->dollars_in_ident; + CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments; + CPP_OPTION (pfile, digraphs) = l->digraphs; +} - pfile->token_buffer_size = 200; - pfile->token_buffer = (U_CHAR *) xmalloc (pfile->token_buffer_size); - CPP_SET_WRITTEN (pfile, 0); +#ifdef HOST_EBCDIC +static int opt_comp PARAMS ((const void *, const void *)); - pfile->hashtab = (HASHNODE **) xcalloc (HASHSIZE, sizeof (HASHNODE *)); +/* Run-time sorting of options array. */ +static int +opt_comp (p1, p2) + const void *p1, *p2; +{ + return strcmp (((struct cl_option *) p1)->opt_text, + ((struct cl_option *) p2)->opt_text); } +#endif -/* Free resources used by PFILE. - This is the cpp_reader 'finalizer' or 'destructor' (in C++ terminology). */ -void -cpp_cleanup (pfile) - cpp_reader *pfile; +/* init initializes library global state. It might not need to + do anything depending on the platform and compiler. */ +static void +init_library () { - int i; - while (CPP_BUFFER (pfile) != CPP_NULL_BUFFER (pfile)) - cpp_pop_buffer (pfile); + static int initialized = 0; - if (pfile->token_buffer) + if (! initialized) { - free (pfile->token_buffer); - pfile->token_buffer = NULL; - } + initialized = 1; - if (pfile->deps_buffer) - { - free (pfile->deps_buffer); - pfile->deps_buffer = NULL; - pfile->deps_allocated_size = 0; +#ifdef HOST_EBCDIC + /* For non-ASCII hosts, the cl_options array needs to be sorted at + runtime. */ + qsort (cl_options, N_OPTS, sizeof (struct cl_option), opt_comp); +#endif + + /* Set up the trigraph map. This doesn't need to do anything if + we were compiled with a compiler that supports C99 designated + initializers. */ + init_trigraph_map (); } +} + +/* Initialize a cpp_reader structure. */ +cpp_reader * +cpp_create_reader (lang) + enum c_lang lang; +{ + cpp_reader *pfile; + + /* Initialise this instance of the library if it hasn't been already. */ + init_library (); + + pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader)); + + set_lang (pfile, lang); + CPP_OPTION (pfile, warn_import) = 1; + CPP_OPTION (pfile, discard_comments) = 1; + CPP_OPTION (pfile, show_column) = 1; + CPP_OPTION (pfile, tabstop) = 8; + CPP_OPTION (pfile, operator_names) = 1; + + CPP_OPTION (pfile, pending) = + (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending)); + + /* It's simplest to just create this struct whether or not it will + be needed. */ + pfile->deps = deps_init (); + + /* Initialise the line map. Start at logical line 1, so we can use + a line number of zero for special states. */ + init_line_maps (&pfile->line_maps); + pfile->line = 1; + + /* Initialize lexer state. */ + pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments); + + /* Set up static tokens. */ + pfile->date.type = CPP_EOF; + pfile->avoid_paste.type = CPP_PADDING; + pfile->avoid_paste.val.source = NULL; + pfile->eof.type = CPP_EOF; + pfile->eof.flags = 0; - if (pfile->input_buffer) + /* Create a token buffer for the lexer. */ + _cpp_init_tokenrun (&pfile->base_run, 250); + pfile->cur_run = &pfile->base_run; + pfile->cur_token = pfile->base_run.base; + + /* Initialise the base context. */ + pfile->context = &pfile->base_context; + pfile->base_context.macro = 0; + pfile->base_context.prev = pfile->base_context.next = 0; + + /* Aligned and unaligned storage. */ + pfile->a_buff = _cpp_get_buff (pfile, 0); + pfile->u_buff = _cpp_get_buff (pfile, 0); + + /* Initialise the buffer obstack. */ + gcc_obstack_init (&pfile->buffer_ob); + + _cpp_init_includes (pfile); + + return pfile; +} + +/* Free resources used by PFILE. Accessing PFILE after this function + returns leads to undefined behaviour. Returns the error count. */ +int +cpp_destroy (pfile) + cpp_reader *pfile; +{ + int result; + struct search_path *dir, *dirn; + cpp_context *context, *contextn; + tokenrun *run, *runn; + + while (CPP_BUFFER (pfile) != NULL) + _cpp_pop_buffer (pfile); + + if (pfile->macro_buffer) { - free (pfile->input_buffer); - free (pfile->input_speccase); - pfile->input_buffer = pfile->input_speccase = NULL; - pfile->input_buffer_len = 0; + free ((PTR) pfile->macro_buffer); + pfile->macro_buffer = NULL; + pfile->macro_buffer_len = 0; } - while (pfile->if_stack) + deps_free (pfile->deps); + obstack_free (&pfile->buffer_ob, 0); + + _cpp_destroy_hashtable (pfile); + _cpp_cleanup_includes (pfile); + + _cpp_free_buff (pfile->a_buff); + _cpp_free_buff (pfile->u_buff); + _cpp_free_buff (pfile->free_buffs); + + for (run = &pfile->base_run; run; run = runn) { - IF_STACK_FRAME *temp = pfile->if_stack; - pfile->if_stack = temp->next; - free (temp); + runn = run->next; + free (run->base); + if (run != &pfile->base_run) + free (run); } - for (i = ALL_INCLUDE_HASHSIZE; --i >= 0; ) + for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn) { - struct include_hash *imp = pfile->all_include_files[i]; - while (imp) - { - struct include_hash *next = imp->next; -#if 0 - /* This gets freed elsewhere - I think. */ - free (imp->name); -#endif - free (imp); - imp = next; - } - pfile->all_include_files[i] = 0; + dirn = dir->next; + free ((PTR) dir->name); + free (dir); } - for (i = HASHSIZE; --i >= 0;) + for (context = pfile->base_context.next; context; context = contextn) { - while (pfile->hashtab[i]) - delete_macro (pfile->hashtab[i]); + contextn = context->next; + free (context); } - free (pfile->hashtab); + + free_line_maps (&pfile->line_maps); + + result = pfile->errors; + free (pfile); + + return result; } -/* Initialize the built-in macros. */ -static void -initialize_builtins (pfile) - cpp_reader *pfile; +/* This structure defines one built-in identifier. A node will be + entered in the hash table under the name NAME, with value VALUE (if + any). If flags has OPERATOR, the node's operator field is used; if + flags has BUILTIN the node's builtin field is used. Macros that are + known at build time should not be flagged BUILTIN, as then they do + not appear in macro dumps with e.g. -dM or -dD. + + Two values are not compile time constants, so we tag + them in the FLAGS field instead: + VERS value is the global version_string, quoted + ULP value is the global user_label_prefix + + Also, macros with CPLUS set in the flags field are entered only for C++. */ +struct builtin { -#define NAME(str) (U_CHAR *)str, sizeof str - 1 - cpp_install (pfile, NAME("__TIME__"), T_TIME, 0, -1); - cpp_install (pfile, NAME("__DATE__"), T_DATE, 0, -1); - cpp_install (pfile, NAME("__FILE__"), T_FILE, 0, -1); - cpp_install (pfile, NAME("__BASE_FILE__"), T_BASE_FILE, 0, -1); - cpp_install (pfile, NAME("__LINE__"), T_SPECLINE, 0, -1); - cpp_install (pfile, NAME("__INCLUDE_LEVEL__"), T_INCLUDE_LEVEL, 0, -1); - cpp_install (pfile, NAME("__VERSION__"), T_VERSION, 0, -1); + const U_CHAR *name; + const char *value; + unsigned char builtin; + unsigned char operator; + unsigned short flags; + unsigned short len; +}; +#define VERS 0x01 +#define ULP 0x02 +#define CPLUS 0x04 +#define BUILTIN 0x08 +#define OPERATOR 0x10 + +#define B(n, t) { U n, 0, t, 0, BUILTIN, sizeof n - 1 } +#define C(n, v) { U n, v, 0, 0, 0, sizeof n - 1 } +#define X(n, f) { U n, 0, 0, 0, f, sizeof n - 1 } +#define O(n, c, f) { U n, 0, 0, c, OPERATOR | f, sizeof n - 1 } +static const struct builtin builtin_array[] = +{ + B("__TIME__", BT_TIME), + B("__DATE__", BT_DATE), + B("__FILE__", BT_FILE), + B("__BASE_FILE__", BT_BASE_FILE), + B("__LINE__", BT_SPECLINE), + B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL), + B("_Pragma", BT_PRAGMA), + + X("__VERSION__", VERS), + X("__USER_LABEL_PREFIX__", ULP), + C("__REGISTER_PREFIX__", REGISTER_PREFIX), + C("__HAVE_BUILTIN_SETJMP__", "1"), +#if USING_SJLJ_EXCEPTIONS + /* libgcc needs to know this. */ + C("__USING_SJLJ_EXCEPTIONS__","1"), +#endif #ifndef NO_BUILTIN_SIZE_TYPE - cpp_install (pfile, NAME("__SIZE_TYPE__"), T_CONST, SIZE_TYPE, -1); + C("__SIZE_TYPE__", SIZE_TYPE), #endif #ifndef NO_BUILTIN_PTRDIFF_TYPE - cpp_install (pfile, NAME("__PTRDIFF_TYPE__ "), T_CONST, PTRDIFF_TYPE, -1); + C("__PTRDIFF_TYPE__", PTRDIFF_TYPE), #endif - cpp_install (pfile, NAME("__WCHAR_TYPE__"), T_CONST, WCHAR_TYPE, -1); - cpp_install (pfile, NAME("__USER_LABEL_PREFIX__"), T_CONST, user_label_prefix, -1); - cpp_install (pfile, NAME("__REGISTER_PREFIX__"), T_CONST, REGISTER_PREFIX, -1); - cpp_install (pfile, NAME("__HAVE_BUILTIN_SETJMP__"), T_CONST, "1", -1); - if (!CPP_TRADITIONAL (pfile)) - { - cpp_install (pfile, NAME("__STDC__"), T_STDC, 0, -1); -#if 0 - if (CPP_OPTIONS (pfile)->c9x) - cpp_install (pfile, NAME("__STDC_VERSION__"),T_CONST, "199909L", -1); - else +#ifndef NO_BUILTIN_WCHAR_TYPE + C("__WCHAR_TYPE__", WCHAR_TYPE), #endif - cpp_install (pfile, NAME("__STDC_VERSION__"),T_CONST, "199409L", -1); - } -#undef NAME - - if (CPP_OPTIONS (pfile)->debug_output) - { - dump_special_to_buffer (pfile, "__BASE_FILE__"); - dump_special_to_buffer (pfile, "__VERSION__"); -#ifndef NO_BUILTIN_SIZE_TYPE - dump_special_to_buffer (pfile, "__SIZE_TYPE__"); +#ifndef NO_BUILTIN_WINT_TYPE + C("__WINT_TYPE__", WINT_TYPE), #endif -#ifndef NO_BUILTIN_PTRDIFF_TYPE - dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__"); +#ifdef STDC_0_IN_SYSTEM_HEADERS + B("__STDC__", BT_STDC), +#else + C("__STDC__", "1"), #endif - dump_special_to_buffer (pfile, "__WCHAR_TYPE__"); - dump_special_to_buffer (pfile, "__DATE__"); - dump_special_to_buffer (pfile, "__TIME__"); - if (!CPP_TRADITIONAL (pfile)) - dump_special_to_buffer (pfile, "__STDC__"); - } -} -/* Another subroutine of cpp_start_read. This one sets up to do - dependency-file output. */ + /* Named operators known to the preprocessor. These cannot be #defined + and always have their stated meaning. They are treated like normal + identifiers except for the type code and the meaning. Most of them + are only for C++ (but see iso646.h). */ + O("and", CPP_AND_AND, CPLUS), + O("and_eq", CPP_AND_EQ, CPLUS), + O("bitand", CPP_AND, CPLUS), + O("bitor", CPP_OR, CPLUS), + O("compl", CPP_COMPL, CPLUS), + O("not", CPP_NOT, CPLUS), + O("not_eq", CPP_NOT_EQ, CPLUS), + O("or", CPP_OR_OR, CPLUS), + O("or_eq", CPP_OR_EQ, CPLUS), + O("xor", CPP_XOR, CPLUS), + O("xor_eq", CPP_XOR_EQ, CPLUS) +}; +#undef B +#undef C +#undef X +#undef O +#define builtin_array_end \ + builtin_array + sizeof(builtin_array)/sizeof(struct builtin) + +/* Subroutine of cpp_read_main_file; reads the builtins table above and + enters them, and language-specific macros, into the hash table. */ static void -initialize_dependency_output (pfile) +init_builtins (pfile) cpp_reader *pfile; { - cpp_options *opts = CPP_OPTIONS (pfile); - char *spec, *s, *output_file; - - /* Either of two environment variables can specify output of deps. - Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET", - where OUTPUT_FILE is the file to write deps info to - and DEPS_TARGET is the target to mention in the deps. */ + const struct builtin *b; - if (opts->print_deps == 0) + for(b = builtin_array; b < builtin_array_end; b++) { - spec = getenv ("DEPENDENCIES_OUTPUT"); - if (spec) - opts->print_deps = 1; - else + if ((b->flags & CPLUS) && ! CPP_OPTION (pfile, cplusplus)) + continue; + + if ((b->flags & OPERATOR) && ! CPP_OPTION (pfile, operator_names)) + continue; + + if (b->flags & (OPERATOR | BUILTIN)) { - spec = getenv ("SUNPRO_DEPENDENCIES"); - if (spec) - opts->print_deps = 2; + cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); + if (b->flags & OPERATOR) + { + hp->flags |= NODE_OPERATOR; + hp->value.operator = b->operator; + } else - return; + { + hp->type = NT_MACRO; + hp->flags |= NODE_BUILTIN | NODE_WARN; + hp->value.builtin = b->builtin; + } } - - /* Find the space before the DEPS_TARGET, if there is one. */ - s = strchr (spec, ' '); - if (s) + else /* A standard macro of some kind. */ { - opts->deps_target = s + 1; - output_file = (char *) xmalloc (s - spec + 1); - memcpy (output_file, spec, s - spec); - output_file[s - spec] = 0; + const char *val; + char *str; + + if (b->flags & VERS) + { + /* Allocate enough space for 'name "value"\n\0'. */ + str = alloca (b->len + strlen (version_string) + 5); + sprintf (str, "%s \"%s\"\n", b->name, version_string); + } + else + { + if (b->flags & ULP) + val = CPP_OPTION (pfile, user_label_prefix); + else + val = b->value; + + /* Allocate enough space for "name value\n\0". */ + str = alloca (b->len + strlen (val) + 3); + sprintf(str, "%s %s\n", b->name, val); + } + + _cpp_define_builtin (pfile, str); } + } + + if (CPP_OPTION (pfile, cplusplus)) + { + _cpp_define_builtin (pfile, "__cplusplus 1"); + if (SUPPORTS_ONE_ONLY) + _cpp_define_builtin (pfile, "__GXX_WEAK__ 1"); else - { - opts->deps_target = 0; - output_file = spec; - } + _cpp_define_builtin (pfile, "__GXX_WEAK__ 0"); + } + if (CPP_OPTION (pfile, objc)) + _cpp_define_builtin (pfile, "__OBJC__ 1"); + + if (CPP_OPTION (pfile, lang) == CLK_STDC94) + _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L"); + else if (CPP_OPTION (pfile, c99)) + _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L"); + + if (CPP_OPTION (pfile, lang) == CLK_STDC89 + || CPP_OPTION (pfile, lang) == CLK_STDC94 + || CPP_OPTION (pfile, lang) == CLK_STDC99) + _cpp_define_builtin (pfile, "__STRICT_ANSI__ 1"); + else if (CPP_OPTION (pfile, lang) == CLK_ASM) + _cpp_define_builtin (pfile, "__ASSEMBLER__ 1"); +} +#undef BUILTIN +#undef OPERATOR +#undef VERS +#undef ULP +#undef CPLUS +#undef builtin_array_end + +/* And another subroutine. This one sets up the standard include path. */ +static void +init_standard_includes (pfile) + cpp_reader *pfile; +{ + char *path; + const struct default_include *p; + const char *specd_prefix = CPP_OPTION (pfile, include_prefix); + + /* Several environment variables may add to the include search path. + CPATH specifies an additional list of directories to be searched + as if specified with -I, while C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, + etc. specify an additional list of directories to be searched as + if specified with -isystem, for the language indicated. */ + + GET_ENV_PATH_LIST (path, "CPATH"); + if (path != 0 && *path != 0) + path_include (pfile, path, BRACKET); - opts->deps_file = output_file; - opts->print_deps_append = 1; + switch ((CPP_OPTION (pfile, objc) << 1) + CPP_OPTION (pfile, cplusplus)) + { + case 0: + GET_ENV_PATH_LIST (path, "C_INCLUDE_PATH"); + break; + case 1: + GET_ENV_PATH_LIST (path, "CPLUS_INCLUDE_PATH"); + break; + case 2: + GET_ENV_PATH_LIST (path, "OBJC_INCLUDE_PATH"); + break; + case 3: + GET_ENV_PATH_LIST (path, "OBJCPLUS_INCLUDE_PATH"); + break; } + if (path != 0 && *path != 0) + path_include (pfile, path, SYSTEM); - /* Print the expected object file name as the target of this Make-rule. */ - pfile->deps_allocated_size = 200; - pfile->deps_buffer = (char *) xmalloc (pfile->deps_allocated_size); - pfile->deps_buffer[0] = 0; - pfile->deps_size = 0; - pfile->deps_column = 0; - - if (opts->deps_target) - deps_output (pfile, opts->deps_target, ':'); - else if (*opts->in_fname == 0) - deps_output (pfile, "-", ':'); - else + /* Search "translated" versions of GNU directories. + These have /usr/local/lib/gcc... replaced by specd_prefix. */ + if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len) { - char *p, *q, *r; - int len, x; - - /* Discard all directory prefixes from filename. */ - q = base_name (opts->in_fname); - - /* Copy remainder to mungable area. */ - len = strlen (q); - p = (char *) alloca (len + 8); - strcpy (p, q); - - /* Output P, but remove known suffixes. */ - q = p + len; - /* Point to the filename suffix. */ - r = rindex (p, '.'); - /* Compare against the known suffixes. */ - for (x = 0; known_suffixes[x]; x++) + /* Remove the `include' from /usr/local/lib/gcc.../include. + GCC_INCLUDE_DIR will always end in /include. */ + int default_len = cpp_GCC_INCLUDE_DIR_len; + char *default_prefix = (char *) alloca (default_len + 1); + int specd_len = strlen (specd_prefix); + + memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len); + default_prefix[default_len] = '\0'; + + for (p = cpp_include_defaults; p->fname; p++) { - if (strncmp (known_suffixes[x], r, q - r) == 0) + /* Some standard dirs are only for C++. */ + if (!p->cplusplus + || (CPP_OPTION (pfile, cplusplus) + && !CPP_OPTION (pfile, no_standard_cplusplus_includes))) { - /* Make q point to the bit we're going to overwrite - with an object suffix. */ - q = r; - break; + /* Does this dir start with the prefix? */ + if (!memcmp (p->fname, default_prefix, default_len)) + { + /* Yes; change prefix and add to search list. */ + int flen = strlen (p->fname); + int this_len = specd_len + flen - default_len; + char *str = (char *) xmalloc (this_len + 1); + memcpy (str, specd_prefix, specd_len); + memcpy (str + specd_len, + p->fname + default_len, + flen - default_len + 1); + + append_include_chain (pfile, str, SYSTEM, p->cxx_aware); + } } } + } - /* Supply our own suffix. */ - strcpy (q, OBJECT_SUFFIX); - - deps_output (pfile, p, ':'); - deps_output (pfile, opts->in_fname, ' '); + /* Search ordinary names for GNU include directories. */ + for (p = cpp_include_defaults; p->fname; p++) + { + /* Some standard dirs are only for C++. */ + if (!p->cplusplus + || (CPP_OPTION (pfile, cplusplus) + && !CPP_OPTION (pfile, no_standard_cplusplus_includes))) + { + char *str = update_path (p->fname, p->component); + append_include_chain (pfile, str, SYSTEM, p->cxx_aware); + } } } -/* This is called after options have been processed. - * Check options for consistency, and setup for processing input - * from the file named FNAME. (Use standard input if FNAME==NULL.) - * Return 1 on success, 0 on failure. - */ - -int -cpp_start_read (pfile, fname) +/* Pushes a command line -imacro and -include file indicated by P onto + the buffer stack. Returns non-zero if successful. */ +static bool +push_include (pfile, p) cpp_reader *pfile; - char *fname; + struct pending_option *p; { - struct cpp_options *opts = CPP_OPTIONS (pfile); - struct pending_option *p, *q; - int f; - cpp_buffer *fp; - struct include_hash *ih_fake; - - /* -MG doesn't select the form of output and must be specified with one of - -M or -MM. -MG doesn't make sense with -MD or -MMD since they don't - inhibit compilation. */ - if (opts->print_deps_missing_files - && (opts->print_deps == 0 || !opts->no_output)) - { - cpp_fatal (pfile, "-MG must be specified with one of -M or -MM"); - return 0; - } + cpp_token header; + + /* Later: maybe update this to use the #include "" search path + if cpp_read_file fails. */ + header.type = CPP_STRING; + header.val.str.text = (const unsigned char *) p->arg; + header.val.str.len = strlen (p->arg); + /* Make the command line directive take up a line. */ + pfile->line++; + + return _cpp_execute_include (pfile, &header, IT_CMDLINE); +} + +/* Frees a pending_option chain. */ +static void +free_chain (head) + struct pending_option *head; +{ + struct pending_option *next; - /* Chill should not be used with -trigraphs. */ - if (opts->chill && opts->trigraphs) + while (head) { - cpp_warning (pfile, "-lang-chill and -trigraphs are mutually exclusive"); - opts->trigraphs = 0; + next = head->next; + free (head); + head = next; } +} - /* Set this if it hasn't been set already. */ - if (user_label_prefix == NULL) - user_label_prefix = USER_LABEL_PREFIX; - - /* Now that we know dollars_in_ident, we can initialize the syntax - tables. */ - initialize_char_syntax (opts->dollars_in_ident); - - /* Do partial setup of input buffer for the sake of generating - early #line directives (when -g is in effect). */ - fp = cpp_push_buffer (pfile, NULL, 0); - if (!fp) - return 0; - if (opts->in_fname == NULL || *opts->in_fname == 0) +/* This is called after options have been parsed, and partially + processed. Setup for processing input from the file named FNAME, + or stdin if it is the empty string. Return the original filename + on success (e.g. foo.i->foo.c), or NULL on failure. */ +const char * +cpp_read_main_file (pfile, fname, table) + cpp_reader *pfile; + const char *fname; + hash_table *table; +{ + /* The front ends don't set up the hash table until they have + finished processing the command line options, so initializing the + hashtable is deferred until now. */ + _cpp_init_hashtable (pfile, table); + + /* Set up the include search path now. */ + if (! CPP_OPTION (pfile, no_standard_includes)) + init_standard_includes (pfile); + + merge_include_chains (pfile); + + /* With -v, print the list of dirs to search. */ + if (CPP_OPTION (pfile, verbose)) { - opts->in_fname = fname; - if (opts->in_fname == NULL) - opts->in_fname = ""; + struct search_path *l; + fprintf (stderr, _("#include \"...\" search starts here:\n")); + for (l = CPP_OPTION (pfile, quote_include); l; l = l->next) + { + if (l == CPP_OPTION (pfile, bracket_include)) + fprintf (stderr, _("#include <...> search starts here:\n")); + fprintf (stderr, " %s\n", l->name); + } + fprintf (stderr, _("End of search list.\n")); } - fp->nominal_fname = fp->fname = opts->in_fname; - fp->lineno = 0; - /* Install __LINE__, etc. Must follow initialize_char_syntax - and option processing. */ - initialize_builtins (pfile); + if (CPP_OPTION (pfile, print_deps)) + /* Set the default target (if there is none already). */ + deps_add_default_target (pfile->deps, fname); - /* Do -U's, -D's and -A's in the order they were seen. */ - p = opts->pending->define_head; - while (p) - { - if (opts->debug_output) - output_line_command (pfile, same_file); - if (p->undef) - cpp_undef (pfile, p->arg); - else - cpp_define (pfile, p->arg); + /* Open the main input file. */ + if (!_cpp_read_file (pfile, fname)) + return NULL; - q = p->next; - free (p); - p = q; - } + /* Set this after cpp_post_options so the client can change the + option if it wishes, and after stacking the main file so we don't + trace the main file. */ + pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names); - p = opts->pending->assert_head; - while (p) - { - if (opts->debug_output) - output_line_command (pfile, same_file); - if (p->undef) - cpp_unassert (pfile, p->arg); - else - cpp_assert (pfile, p->arg); + /* For foo.i, read the original filename foo.c now, for the benefit + of the front ends. */ + if (CPP_OPTION (pfile, preprocessed)) + read_original_filename (pfile); - q = p->next; - free (p); - p = q; - } - - opts->done_initializing = 1; + return pfile->map->to_file; +} - /* Several environment variables may add to the include search path. - CPATH specifies an additional list of directories to be searched - as if specified with -I, while C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, - etc. specify an additional list of directories to be searched as - if specified with -isystem, for the language indicated. +/* For preprocessed files, if the first tokens are of the form # NUM. + handle the directive so we know the original file name. This will + generate file_change callbacks, which the front ends must handle + appropriately given their state of initialization. */ +static void +read_original_filename (pfile) + cpp_reader *pfile; +{ + const cpp_token *token, *token1; - These variables are ignored if -nostdinc is on. */ - if (! opts->no_standard_includes) + /* Lex ahead; if the first tokens are of the form # NUM, then + process the directive, otherwise back up. */ + token = _cpp_lex_direct (pfile); + if (token->type == CPP_HASH) { - char *path; - GET_ENV_PATH_LIST (path, "CPATH"); - if (path != 0 && *path != 0) - path_include (pfile, opts->pending, path, BRACKET); + token1 = _cpp_lex_direct (pfile); + _cpp_backup_tokens (pfile, 1); - switch ((opts->objc << 1) + opts->cplusplus) + /* If it's a #line directive, handle it. */ + if (token1->type == CPP_NUMBER) { - case 0: - GET_ENV_PATH_LIST (path, "C_INCLUDE_PATH"); - break; - case 1: - GET_ENV_PATH_LIST (path, "CPLUS_INCLUDE_PATH"); - break; - case 2: - GET_ENV_PATH_LIST (path, "OBJC_INCLUDE_PATH"); - break; - case 3: - GET_ENV_PATH_LIST (path, "OBJCPLUS_INCLUDE_PATH"); - break; + _cpp_handle_directive (pfile, token->flags & PREV_WHITE); + return; } - if (path != 0 && *path != 0) - path_include (pfile, opts->pending, path, SYSTEM); } - /* Unless -nostdinc, add the compiled-in include path to the list, - translating prefixes. */ - if (!opts->no_standard_includes) - { - struct default_include *p = include_defaults_array; - char *specd_prefix = opts->include_prefix; - - /* Search "translated" versions of GNU directories. - These have /usr/local/lib/gcc... replaced by specd_prefix. */ - if (specd_prefix != 0) - { - char *default_prefix = alloca (sizeof GCC_INCLUDE_DIR - 7); - /* Remove the `include' from /usr/local/lib/gcc.../include. - GCC_INCLUDE_DIR will always end in /include. */ - int default_len = sizeof GCC_INCLUDE_DIR - 8; - int specd_len = strlen (specd_prefix); + /* Backup as if nothing happened. */ + _cpp_backup_tokens (pfile, 1); +} - default_len = sizeof GCC_INCLUDE_DIR - 8; - memcpy (default_prefix, GCC_INCLUDE_DIR, default_len); - default_prefix[default_len] = '\0'; +/* Handle pending command line options: -D, -U, -A, -imacros and + -include. This should be called after debugging has been properly + set up in the front ends. */ +void +cpp_finish_options (pfile) + cpp_reader *pfile; +{ + /* Install builtins and process command line macros etc. in the order + they appeared, but only if not already preprocessed. */ + if (! CPP_OPTION (pfile, preprocessed)) + { + struct pending_option *p; - for (p = include_defaults_array; p->fname; p++) - { - /* Some standard dirs are only for C++. */ - if (!p->cplusplus - || (opts->cplusplus - && !opts->no_standard_cplusplus_includes)) - { - /* Does this dir start with the prefix? */ - if (!strncmp (p->fname, default_prefix, default_len)) - { - /* Yes; change prefix and add to search list. */ - int flen = strlen (p->fname); - int this_len = specd_len + flen - default_len; - char *str = (char *) xmalloc (this_len + 1); - memcpy (str, specd_prefix, specd_len); - memcpy (str + specd_len, - p->fname + default_len, - flen - default_len + 1); - - append_include_chain (pfile, opts->pending, - str, SYSTEM); - } - } - } - } + _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0); + init_builtins (pfile); + _cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0); + for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next) + (*p->handler) (pfile, p->arg); - /* Search ordinary names for GNU include directories. */ - for (p = include_defaults_array; p->fname; p++) + /* Scan -imacros files after command line defines, but before + files given with -include. */ + while ((p = CPP_OPTION (pfile, pending)->imacros_head) != NULL) { - /* Some standard dirs are only for C++. */ - if (!p->cplusplus - || (opts->cplusplus - && !opts->no_standard_cplusplus_includes)) + if (push_include (pfile, p)) { - char *str = (char *) update_path (p->fname, p->component); - str = xstrdup (str); /* XXX Potential memory leak! */ - append_include_chain (pfile, opts->pending, str, SYSTEM); + pfile->buffer->return_at_eof = true; + cpp_scan_nooutput (pfile); } + CPP_OPTION (pfile, pending)->imacros_head = p->next; + free (p); } } - merge_include_chains (opts); + free_chain (CPP_OPTION (pfile, pending)->directive_head); + _cpp_push_next_buffer (pfile); +} - /* With -v, print the list of dirs to search. */ - if (opts->verbose) +/* Called to push the next buffer on the stack given by -include. If + there are none, free the pending structure and restore the line map + for the main file. */ +bool +_cpp_push_next_buffer (pfile) + cpp_reader *pfile; +{ + bool pushed = false; + + /* This is't pretty; we'd rather not be relying on this as a boolean + for reverting the line map. Further, we only free the chains in + this conditional, so an early call to cpp_finish / cpp_destroy + will leak that memory. */ + if (CPP_OPTION (pfile, pending) + && CPP_OPTION (pfile, pending)->imacros_head == NULL) { - struct file_name_list *p; - cpp_message (pfile, -1, "#include \"...\" search starts here:\n"); - for (p = opts->quote_include; p; p = p->next) + while (!pushed) { - if (p == opts->bracket_include) - cpp_message (pfile, -1, "#include <...> search starts here:\n"); - fprintf (stderr, " %s\n", p->name); + struct pending_option *p = CPP_OPTION (pfile, pending)->include_head; + + if (p == NULL) + break; + if (! CPP_OPTION (pfile, preprocessed)) + pushed = push_include (pfile, p); + CPP_OPTION (pfile, pending)->include_head = p->next; + free (p); } - cpp_message (pfile, -1, "End of search list.\n"); - } - /* Open the main input file. - We do this in nonblocking mode so we don't get stuck here if - someone clever has asked cpp to process /dev/rmt0; - finclude() will check that we have a real file to work with. */ - if (fname == NULL || *fname == 0) - { - fname = ""; - f = 0; - } - else if ((f = open (fname, O_RDONLY|O_NONBLOCK|O_NOCTTY, 0666)) < 0) - cpp_pfatal_with_name (pfile, fname); - - initialize_dependency_output (pfile); - - /* Must call finclude() on the main input before processing - -include switches; otherwise the -included text winds up - after the main input. */ - ih_fake = (struct include_hash *) xmalloc (sizeof (struct include_hash)); - ih_fake->next = 0; - ih_fake->next_this_file = 0; - ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ - ih_fake->name = fname; - ih_fake->control_macro = 0; - ih_fake->buf = (char *)-1; - ih_fake->limit = 0; - if (!finclude (pfile, f, ih_fake)) - return 0; - output_line_command (pfile, same_file); - pfile->only_seen_white = 2; - - /* The -imacros files can be scanned now, but the -include files - have to be pushed onto the include stack and processed later, - in the main loop calling cpp_get_token. */ - - pfile->no_record_file++; - opts->no_output++; - p = opts->pending->imacros_head; - while (p) - { - int fd = open (p->arg, O_RDONLY|O_NONBLOCK|O_NOCTTY, 0666); - if (fd < 0) + if (!pushed) { - cpp_perror_with_name (pfile, p->arg); - return 0; + free (CPP_OPTION (pfile, pending)); + CPP_OPTION (pfile, pending) = NULL; + + /* Restore the line map for the main file. */ + if (! CPP_OPTION (pfile, preprocessed)) + _cpp_do_file_change (pfile, LC_RENAME, + pfile->line_maps.maps[0].to_file, 1, 0); } - if (!cpp_push_buffer (pfile, NULL, 0)) - return 0; - - ih_fake = (struct include_hash *) - xmalloc (sizeof (struct include_hash)); - ih_fake->next = 0; - ih_fake->next_this_file = 0; - ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ - ih_fake->name = p->arg; - ih_fake->control_macro = 0; - ih_fake->buf = (char *)-1; - ih_fake->limit = 0; - if (!finclude (pfile, fd, ih_fake)) - cpp_scan_buffer (pfile); - free (ih_fake); - - q = p->next; - free (p); - p = q; } - opts->no_output--; + return pushed; +} + +/* Use mkdeps.c to output dependency information. */ +static void +output_deps (pfile) + cpp_reader *pfile; +{ + /* Stream on which to print the dependency information. */ + FILE *deps_stream = 0; + const char *const deps_mode = + CPP_OPTION (pfile, print_deps_append) ? "a" : "w"; - p = opts->pending->include_head; - while (p) + if (CPP_OPTION (pfile, deps_file) == 0) + deps_stream = stdout; + else { - int fd = open (p->arg, O_RDONLY|O_NONBLOCK|O_NOCTTY, 0666); - if (fd < 0) + deps_stream = fopen (CPP_OPTION (pfile, deps_file), deps_mode); + if (deps_stream == 0) { - cpp_perror_with_name (pfile, p->arg); - return 0; + cpp_notice_from_errno (pfile, CPP_OPTION (pfile, deps_file)); + return; } - if (!cpp_push_buffer (pfile, NULL, 0)) - return 0; - - ih_fake = (struct include_hash *) - xmalloc (sizeof (struct include_hash)); - ih_fake->next = 0; - ih_fake->next_this_file = 0; - ih_fake->foundhere = ABSOLUTE_PATH; /* well sort of ... */ - ih_fake->name = p->arg; - ih_fake->control_macro = 0; - ih_fake->buf = (char *)-1; - ih_fake->limit = 0; - if (finclude (pfile, fd, ih_fake)) - output_line_command (pfile, enter_file); - - q = p->next; - free (p); - p = q; } - pfile->no_record_file--; - free (opts->pending); - opts->pending = NULL; + deps_write (pfile->deps, deps_stream, 72); + + if (CPP_OPTION (pfile, deps_phony_targets)) + deps_phony_targets (pfile->deps, deps_stream); - return 1; + /* Don't close stdout. */ + if (CPP_OPTION (pfile, deps_file)) + { + if (ferror (deps_stream) || fclose (deps_stream) != 0) + cpp_fatal (pfile, "I/O error on output"); + } } /* This is called at the end of preprocessing. It pops the last buffer and writes dependency output. It should also clear macro definitions, such that you could call cpp_start_read - with a new filename to restart processing. */ + with a new filename to restart processing. */ void cpp_finish (pfile) cpp_reader *pfile; { - struct cpp_options *opts = CPP_OPTIONS (pfile); + /* cpplex.c leaves the final buffer on the stack. This it so that + it returns an unending stream of CPP_EOFs to the client. If we + popped the buffer, we'd dereference a NULL buffer pointer and + segfault. It's nice to allow the client to do worry-free excess + cpp_get_token calls. */ + while (pfile->buffer) + _cpp_pop_buffer (pfile); + + /* Don't write the deps file if preprocessing has failed. */ + if (CPP_OPTION (pfile, print_deps) && pfile->errors == 0) + output_deps (pfile); + + /* Report on headers that could use multiple include guards. */ + if (CPP_OPTION (pfile, print_include_names)) + _cpp_report_missing_guards (pfile); +} - if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) != CPP_NULL_BUFFER (pfile)) - cpp_fatal (pfile, - "cpplib internal error: buffers still stacked in cpp_finish"); - cpp_pop_buffer (pfile); - - if (opts->print_deps) +/* Add a directive to be handled later in the initialization phase. */ +static void +new_pending_directive (pend, text, handler) + struct cpp_pending *pend; + const char *text; + cl_directive_handler handler; +{ + struct pending_option *o = (struct pending_option *) + xmalloc (sizeof (struct pending_option)); + + o->arg = text; + o->next = NULL; + o->handler = handler; + APPEND (pend, directive, o); +} + +/* Irix6 "cc -n32" and OSF4 cc have problems with char foo[] = ("string"); + I.e. a const string initializer with parens around it. That is + what N_("string") resolves to, so we make no_* be macros instead. */ +#define no_arg N_("argument missing after %s") +#define no_ass N_("assertion missing after %s") +#define no_dir N_("directory name missing after %s") +#define no_fil N_("file name missing after %s") +#define no_mac N_("macro name missing after %s") +#define no_pth N_("path name missing after %s") +#define no_num N_("number missing after %s") +#define no_tgt N_("target missing after %s") + +/* This is the list of all command line options, with the leading + "-" removed. It must be sorted in ASCII collating order. */ +#define COMMAND_LINE_OPTIONS \ + DEF_OPT("$", 0, OPT_dollar) \ + DEF_OPT("+", 0, OPT_plus) \ + DEF_OPT("-help", 0, OPT__help) \ + DEF_OPT("-target-help", 0, OPT_target__help) \ + DEF_OPT("-version", 0, OPT__version) \ + DEF_OPT("A", no_ass, OPT_A) \ + DEF_OPT("C", 0, OPT_C) \ + DEF_OPT("D", no_mac, OPT_D) \ + DEF_OPT("H", 0, OPT_H) \ + DEF_OPT("I", no_dir, OPT_I) \ + DEF_OPT("M", 0, OPT_M) \ + DEF_OPT("MD", no_fil, OPT_MD) \ + DEF_OPT("MF", no_fil, OPT_MF) \ + DEF_OPT("MG", 0, OPT_MG) \ + DEF_OPT("MM", 0, OPT_MM) \ + DEF_OPT("MMD", no_fil, OPT_MMD) \ + DEF_OPT("MP", 0, OPT_MP) \ + DEF_OPT("MQ", no_tgt, OPT_MQ) \ + DEF_OPT("MT", no_tgt, OPT_MT) \ + DEF_OPT("P", 0, OPT_P) \ + DEF_OPT("U", no_mac, OPT_U) \ + DEF_OPT("W", no_arg, OPT_W) /* arg optional */ \ + DEF_OPT("d", no_arg, OPT_d) \ + DEF_OPT("fleading-underscore", 0, OPT_fleading_underscore) \ + DEF_OPT("fno-leading-underscore", 0, OPT_fno_leading_underscore) \ + DEF_OPT("fno-operator-names", 0, OPT_fno_operator_names) \ + DEF_OPT("fno-preprocessed", 0, OPT_fno_preprocessed) \ + DEF_OPT("fno-show-column", 0, OPT_fno_show_column) \ + DEF_OPT("fpreprocessed", 0, OPT_fpreprocessed) \ + DEF_OPT("fshow-column", 0, OPT_fshow_column) \ + DEF_OPT("ftabstop=", no_num, OPT_ftabstop) \ + DEF_OPT("h", 0, OPT_h) \ + DEF_OPT("idirafter", no_dir, OPT_idirafter) \ + DEF_OPT("imacros", no_fil, OPT_imacros) \ + DEF_OPT("include", no_fil, OPT_include) \ + DEF_OPT("iprefix", no_pth, OPT_iprefix) \ + DEF_OPT("isystem", no_dir, OPT_isystem) \ + DEF_OPT("iwithprefix", no_dir, OPT_iwithprefix) \ + DEF_OPT("iwithprefixbefore", no_dir, OPT_iwithprefixbefore) \ + DEF_OPT("lang-asm", 0, OPT_lang_asm) \ + DEF_OPT("lang-c", 0, OPT_lang_c) \ + DEF_OPT("lang-c++", 0, OPT_lang_cplusplus) \ + DEF_OPT("lang-c89", 0, OPT_lang_c89) \ + DEF_OPT("lang-objc", 0, OPT_lang_objc) \ + DEF_OPT("lang-objc++", 0, OPT_lang_objcplusplus) \ + DEF_OPT("nostdinc", 0, OPT_nostdinc) \ + DEF_OPT("nostdinc++", 0, OPT_nostdincplusplus) \ + DEF_OPT("o", no_fil, OPT_o) \ + DEF_OPT("pedantic", 0, OPT_pedantic) \ + DEF_OPT("pedantic-errors", 0, OPT_pedantic_errors) \ + DEF_OPT("remap", 0, OPT_remap) \ + DEF_OPT("std=c++98", 0, OPT_std_cplusplus98) \ + DEF_OPT("std=c89", 0, OPT_std_c89) \ + DEF_OPT("std=c99", 0, OPT_std_c99) \ + DEF_OPT("std=c9x", 0, OPT_std_c9x) \ + DEF_OPT("std=gnu89", 0, OPT_std_gnu89) \ + DEF_OPT("std=gnu99", 0, OPT_std_gnu99) \ + DEF_OPT("std=gnu9x", 0, OPT_std_gnu9x) \ + DEF_OPT("std=iso9899:1990", 0, OPT_std_iso9899_1990) \ + DEF_OPT("std=iso9899:199409", 0, OPT_std_iso9899_199409) \ + DEF_OPT("std=iso9899:1999", 0, OPT_std_iso9899_1999) \ + DEF_OPT("std=iso9899:199x", 0, OPT_std_iso9899_199x) \ + DEF_OPT("trigraphs", 0, OPT_trigraphs) \ + DEF_OPT("v", 0, OPT_v) \ + DEF_OPT("version", 0, OPT_version) \ + DEF_OPT("w", 0, OPT_w) + +#define DEF_OPT(text, msg, code) code, +enum opt_code +{ + COMMAND_LINE_OPTIONS + N_OPTS +}; +#undef DEF_OPT + +struct cl_option +{ + const char *opt_text; + const char *msg; + size_t opt_len; + enum opt_code opt_code; +}; + +#define DEF_OPT(text, msg, code) { text, msg, sizeof(text) - 1, code }, +#ifdef HOST_EBCDIC +static struct cl_option cl_options[] = +#else +static const struct cl_option cl_options[] = +#endif +{ + COMMAND_LINE_OPTIONS +}; +#undef DEF_OPT +#undef COMMAND_LINE_OPTIONS + +/* Perform a binary search to find which, if any, option the given + command-line matches. Returns its index in the option array, + negative on failure. Complications arise since some options can be + suffixed with an argument, and multiple complete matches can occur, + e.g. -iwithprefix and -iwithprefixbefore. Moreover, we need to + accept options beginning with -W that we do not recognise, but not + to swallow any subsequent command line argument; this is handled as + special cases in cpp_handle_option. */ +static int +parse_option (input) + const char *input; +{ + unsigned int md, mn, mx; + size_t opt_len; + int comp; + + mn = 0; + mx = N_OPTS; + + while (mx > mn) { - /* Stream on which to print the dependency information. */ - FILE *deps_stream; + md = (mn + mx) / 2; + + opt_len = cl_options[md].opt_len; + comp = memcmp (input, cl_options[md].opt_text, opt_len); - /* Don't actually write the deps file if compilation has failed. */ - if (pfile->errors == 0) + if (comp > 0) + mn = md + 1; + else if (comp < 0) + mx = md; + else { - char *deps_mode = opts->print_deps_append ? "a" : "w"; - if (opts->deps_file == 0) - deps_stream = stdout; - else if ((deps_stream = fopen (opts->deps_file, deps_mode)) == 0) - cpp_pfatal_with_name (pfile, opts->deps_file); - fputs (pfile->deps_buffer, deps_stream); - putc ('\n', deps_stream); - if (opts->deps_file) + if (input[opt_len] == '\0') + return md; + /* We were passed more text. If the option takes an argument, + we may match a later option or we may have been passed the + argument. The longest possible option match succeeds. + If the option takes no arguments we have not matched and + continue the search (e.g. input="stdc++" match was "stdc"). */ + mn = md + 1; + if (cl_options[md].msg) { - if (ferror (deps_stream) || fclose (deps_stream) != 0) - cpp_fatal (pfile, "I/O error on output"); + /* Scan forwards. If we get an exact match, return it. + Otherwise, return the longest option-accepting match. + This loops no more than twice with current options. */ + mx = md; + for (; mn < (unsigned int) N_OPTS; mn++) + { + opt_len = cl_options[mn].opt_len; + if (memcmp (input, cl_options[mn].opt_text, opt_len)) + break; + if (input[opt_len] == '\0') + return mn; + if (cl_options[mn].msg) + mx = mn; + } + return mx; } } } - if (opts->dump_macros == dump_only) - { - int i; - HASHNODE *h; - MACRODEF m; - for (i = HASHSIZE; --i >= 0;) - { - for (h = pfile->hashtab[i]; h; h = h->next) - if (h->type == T_MACRO) - { - m.defn = h->value.defn; - m.symnam = h->name; - m.symlen = h->length; - dump_definition (pfile, m); - CPP_PUTC (pfile, '\n'); - } - } - } + return -1; } /* Handle one command-line option in (argc, argv). Can be called multiple times, to handle multiple sets of options. + If ignore is non-zero, this will ignore unrecognized -W* options. Returns number of strings consumed. */ int -cpp_handle_option (pfile, argc, argv) +cpp_handle_option (pfile, argc, argv, ignore) cpp_reader *pfile; int argc; char **argv; + int ignore; { - struct cpp_options *opts = CPP_OPTIONS (pfile); int i = 0; + struct cpp_pending *pend = CPP_OPTION (pfile, pending); - if (argv[i][0] != '-') + /* Interpret "-" or a non-option as a file name. */ + if (argv[i][0] != '-' || argv[i][1] == '\0') { - if (opts->out_fname != NULL) - { - print_help (); - cpp_fatal (pfile, "Too many arguments"); - } - else if (opts->in_fname != NULL) - opts->out_fname = argv[i]; + if (CPP_OPTION (pfile, in_fname) == NULL) + CPP_OPTION (pfile, in_fname) = argv[i]; + else if (CPP_OPTION (pfile, out_fname) == NULL) + CPP_OPTION (pfile, out_fname) = argv[i]; else - opts->in_fname = argv[i]; + cpp_fatal (pfile, "too many filenames. Type %s --help for usage info", + progname); } else - switch (argv[i][1]) - { - case 'f': - if (!strcmp (argv[i], "-fleading-underscore")) - user_label_prefix = "_"; - else if (!strcmp (argv[i], "-fno-leading-underscore")) - user_label_prefix = ""; - break; - - case 'I': /* Add directory to path for includes. */ - if (!strcmp (argv[i] + 2, "-")) - { - /* -I- means: - Use the preceding -I directories for #include "..." - but not #include <...>. - Don't search the directory of the present file - for #include "...". (Note that -I. -I- is not the same as - the default setup; -I. uses the compiler's working dir.) */ - if (! opts->ignore_srcdir) - { - opts->ignore_srcdir = 1; - opts->pending->quote_head = opts->pending->brack_head; - opts->pending->quote_tail = opts->pending->brack_tail; - opts->pending->brack_head = 0; - opts->pending->brack_tail = 0; - } - else - { - cpp_fatal (pfile, "-I- specified twice"); - return argc; - } - } - else - { - char *fname; - if (argv[i][2] != 0) - fname = argv[i] + 2; - else if (i + 1 == argc) - goto missing_dirname; - else - fname = argv[++i]; - append_include_chain (pfile, opts->pending, - xstrdup (fname), BRACKET); - } - break; - - case 'i': - /* Add directory to beginning of system include path, as a system - include directory. */ - if (!strcmp (argv[i], "-isystem")) - { - if (i + 1 == argc) - goto missing_filename; - append_include_chain (pfile, opts->pending, - xstrdup (argv[++i]), SYSTEM); - } - else if (!strcmp (argv[i], "-include")) - { - if (i + 1 == argc) - goto missing_filename; - else - { - struct pending_option *o = (struct pending_option *) - xmalloc (sizeof (struct pending_option)); - o->arg = argv[++i]; - - /* This list has to be built in reverse order so that - when cpp_start_read pushes all the -include files onto - the buffer stack, they will be scanned in forward order. */ - o->next = opts->pending->include_head; - opts->pending->include_head = o; - } - } - else if (!strcmp (argv[i], "-imacros")) - { - if (i + 1 == argc) - goto missing_filename; - else - { - struct pending_option *o = (struct pending_option *) - xmalloc (sizeof (struct pending_option)); - o->arg = argv[++i]; - o->next = NULL; - - APPEND (opts->pending, imacros, o); - } - } - /* Add directory to end of path for includes, - with the default prefix at the front of its name. */ - else if (!strcmp (argv[i], "-iwithprefix")) - { - char *fname; - int len; - if (i + 1 == argc) - goto missing_dirname; - ++i; - len = strlen (argv[i]); + { + enum opt_code opt_code; + int opt_index; + const char *arg = 0; - if (opts->include_prefix != 0) - { - fname = xmalloc (opts->include_prefix_len + len + 1); - memcpy (fname, opts->include_prefix, opts->include_prefix_len); - memcpy (fname + opts->include_prefix_len, argv[i], len + 1); - } - else - { - fname = xmalloc (sizeof GCC_INCLUDE_DIR - 8 + len); - memcpy (fname, GCC_INCLUDE_DIR, sizeof GCC_INCLUDE_DIR - 9); - memcpy (fname + sizeof GCC_INCLUDE_DIR - 9, argv[i], len + 1); - } - - append_include_chain (pfile, opts->pending, fname, SYSTEM); - } - /* Add directory to main path for includes, - with the default prefix at the front of its name. */ - else if (!strcmp (argv[i], "-iwithprefixbefore")) - { - char *fname; - int len; - if (i + 1 == argc) - goto missing_dirname; - ++i; - len = strlen (argv[i]); + /* Skip over '-'. */ + opt_index = parse_option (&argv[i][1]); + if (opt_index < 0) + return i; - if (opts->include_prefix != 0) - { - fname = xmalloc (opts->include_prefix_len + len + 1); - memcpy (fname, opts->include_prefix, opts->include_prefix_len); - memcpy (fname + opts->include_prefix_len, argv[i], len + 1); - } - else - { - fname = xmalloc (sizeof GCC_INCLUDE_DIR - 8 + len); - memcpy (fname, GCC_INCLUDE_DIR, sizeof GCC_INCLUDE_DIR - 9); - memcpy (fname + sizeof GCC_INCLUDE_DIR - 9, argv[i], len + 1); - } - - append_include_chain (pfile, opts->pending, fname, BRACKET); - } - /* Add directory to end of path for includes. */ - else if (!strcmp (argv[i], "-idirafter")) - { - if (i + 1 == argc) - goto missing_dirname; - append_include_chain (pfile, opts->pending, - xstrdup (argv[++i]), AFTER); - } - else if (!strcmp (argv[i], "-iprefix")) - { - if (i + 1 == argc) - goto missing_filename; - else - { - opts->include_prefix = argv[++i]; - opts->include_prefix_len = strlen (argv[i]); - } - } - else if (!strcmp (argv[i], "-ifoutput")) - opts->output_conditionals = 1; + opt_code = cl_options[opt_index].opt_code; + if (cl_options[opt_index].msg) + { + arg = &argv[i][cl_options[opt_index].opt_len + 1]; - break; - - case 'o': - if (opts->out_fname != NULL) - { - cpp_fatal (pfile, "Output filename specified twice"); - return argc; - } - if (i + 1 == argc) - goto missing_filename; - opts->out_fname = argv[++i]; - if (!strcmp (opts->out_fname, "-")) - opts->out_fname = ""; - break; - - case 'p': - if (!strcmp (argv[i], "-pedantic")) - CPP_PEDANTIC (pfile) = 1; - else if (!strcmp (argv[i], "-pedantic-errors")) - { - CPP_PEDANTIC (pfile) = 1; - opts->pedantic_errors = 1; - } -#if 0 - else if (!strcmp (argv[i], "-pcp")) { - char *pcp_fname = argv[++i]; - pcp_outfile = ((pcp_fname[0] != '-' || pcp_fname[1] != '\0') - ? fopen (pcp_fname, "w") - : fdopen (dup (fileno (stdout)), "w")); - if (pcp_outfile == 0) - cpp_pfatal_with_name (pfile, pcp_fname); - no_precomp = 1; + /* Yuk. Special case for -W as it must not swallow + up any following argument. If this becomes common, add + another field to the cl_options table. */ + if (arg[0] == '\0' && opt_code != OPT_W) + { + arg = argv[++i]; + if (!arg) + { + cpp_fatal (pfile, cl_options[opt_index].msg, argv[i - 1]); + return argc; + } + } } -#endif - break; - - case 't': - if (!strcmp (argv[i], "-traditional")) - { - opts->traditional = 1; - opts->cplusplus_comments = 0; - } - else if (!strcmp (argv[i], "-trigraphs")) - opts->trigraphs = 1; - break; - - case 'l': - if (! strcmp (argv[i], "-lang-c")) - opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0, - opts->c9x = 1, opts->objc = 0; - if (! strcmp (argv[i], "-lang-c89")) - opts->cplusplus = 0, opts->cplusplus_comments = 0, opts->c89 = 1, - opts->c9x = 0, opts->objc = 0; - if (! strcmp (argv[i], "-lang-c++")) - opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0, - opts->c9x = 0, opts->objc = 0; - if (! strcmp (argv[i], "-lang-objc")) - opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0, - opts->c9x = 0, opts->objc = 1; - if (! strcmp (argv[i], "-lang-objc++")) - opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0, - opts->c9x = 0, opts->objc = 1; - if (! strcmp (argv[i], "-lang-asm")) - opts->lang_asm = 1; - if (! strcmp (argv[i], "-lint")) - opts->for_lint = 1; - if (! strcmp (argv[i], "-lang-chill")) - opts->objc = 0, opts->cplusplus = 0, opts->chill = 1, - opts->traditional = 1; - break; - - case '+': - opts->cplusplus = 1, opts->cplusplus_comments = 1; - break; - - case 's': - if (!strcmp (argv[i], "-std=iso9899:1990") - || !strcmp (argv[i], "-std=iso9899:199409") - || !strcmp (argv[i], "-std=c89") - || !strcmp (argv[i], "-std=gnu89")) - opts->cplusplus = 0, opts->cplusplus_comments = 0, - opts->c89 = 1, opts->c9x = 0, opts->objc = 0; - else if (!strcmp (argv[i], "-std=iso9899:199x") - || !strcmp (argv[i], "-std=c9x") - || !strcmp (argv[i], "-std=gnu9x")) - opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0, - opts->c9x = 1, opts->objc = 0; - break; - case 'w': - opts->inhibit_warnings = 1; - break; - - case 'W': - if (!strcmp (argv[i], "-Wtrigraphs")) - opts->warn_trigraphs = 1; - else if (!strcmp (argv[i], "-Wno-trigraphs")) - opts->warn_trigraphs = 0; - else if (!strcmp (argv[i], "-Wcomment")) - opts->warn_comments = 1; - else if (!strcmp (argv[i], "-Wno-comment")) - opts->warn_comments = 0; - else if (!strcmp (argv[i], "-Wcomments")) - opts->warn_comments = 1; - else if (!strcmp (argv[i], "-Wno-comments")) - opts->warn_comments = 0; - else if (!strcmp (argv[i], "-Wtraditional")) - opts->warn_stringify = 1; - else if (!strcmp (argv[i], "-Wno-traditional")) - opts->warn_stringify = 0; - else if (!strcmp (argv[i], "-Wundef")) - opts->warn_undef = 1; - else if (!strcmp (argv[i], "-Wno-undef")) - opts->warn_undef = 0; - else if (!strcmp (argv[i], "-Wimport")) - opts->warn_import = 1; - else if (!strcmp (argv[i], "-Wno-import")) - opts->warn_import = 0; - else if (!strcmp (argv[i], "-Werror")) - opts->warnings_are_errors = 1; - else if (!strcmp (argv[i], "-Wno-error")) - opts->warnings_are_errors = 0; - else if (!strcmp (argv[i], "-Wall")) - { - opts->warn_trigraphs = 1; - opts->warn_comments = 1; - } - break; - - case 'M': - /* The style of the choices here is a bit mixed. - The chosen scheme is a hybrid of keeping all options in one string - and specifying each option in a separate argument: - -M|-MM|-MD file|-MMD file [-MG]. An alternative is: - -M|-MM|-MD file|-MMD file|-MG|-MMG; or more concisely: - -M[M][G][D file]. This is awkward to handle in specs, and is not - as extensible. */ - /* ??? -MG must be specified in addition to one of -M or -MM. - This can be relaxed in the future without breaking anything. - The converse isn't true. */ - - /* -MG isn't valid with -MD or -MMD. This is checked for later. */ - if (!strcmp (argv[i], "-MG")) - { - opts->print_deps_missing_files = 1; - break; - } - if (!strcmp (argv[i], "-M")) - opts->print_deps = 2; - else if (!strcmp (argv[i], "-MM")) - opts->print_deps = 1; - else if (!strcmp (argv[i], "-MD")) - opts->print_deps = 2; - else if (!strcmp (argv[i], "-MMD")) - opts->print_deps = 1; - /* For -MD and -MMD options, write deps on file named by next arg. */ - if (!strcmp (argv[i], "-MD") || !strcmp (argv[i], "-MMD")) - { - if (i+1 == argc) - goto missing_filename; - opts->deps_file = argv[++i]; - } - else - { - /* For -M and -MM, write deps on standard output - and suppress the usual output. */ - opts->no_output = 1; - } - break; - - case 'd': + switch (opt_code) { - char *p = argv[i] + 2; - char c; - while ((c = *p++) != 0) + case N_OPTS: /* Shut GCC up. */ + break; + case OPT_fleading_underscore: + CPP_OPTION (pfile, user_label_prefix) = "_"; + break; + case OPT_fno_leading_underscore: + CPP_OPTION (pfile, user_label_prefix) = ""; + break; + case OPT_fno_operator_names: + CPP_OPTION (pfile, operator_names) = 0; + break; + case OPT_fpreprocessed: + CPP_OPTION (pfile, preprocessed) = 1; + break; + case OPT_fno_preprocessed: + CPP_OPTION (pfile, preprocessed) = 0; + break; + case OPT_fshow_column: + CPP_OPTION (pfile, show_column) = 1; + break; + case OPT_fno_show_column: + CPP_OPTION (pfile, show_column) = 0; + break; + case OPT_ftabstop: + /* Silently ignore empty string, non-longs and silly values. */ + if (arg[0] != '\0') { - /* Arg to -d specifies what parts of macros to dump */ - switch (c) - { - case 'M': - opts->dump_macros = dump_only; - opts->no_output = 1; + char *endptr; + long tabstop = strtol (arg, &endptr, 10); + if (*endptr == '\0' && tabstop >= 1 && tabstop <= 100) + CPP_OPTION (pfile, tabstop) = tabstop; + } + break; + case OPT_w: + CPP_OPTION (pfile, inhibit_warnings) = 1; + break; + case OPT_h: + case OPT__help: + print_help (); + CPP_OPTION (pfile, help_only) = 1; + break; + case OPT_target__help: + /* Print if any target specific options. cpplib has none, but + make sure help_only gets set. */ + CPP_OPTION (pfile, help_only) = 1; + break; + + /* --version inhibits compilation, -version doesn't. -v means + verbose and -version. Historical reasons, don't ask. */ + case OPT__version: + CPP_OPTION (pfile, help_only) = 1; + pfile->print_version = 1; + break; + case OPT_v: + CPP_OPTION (pfile, verbose) = 1; + pfile->print_version = 1; + break; + case OPT_version: + pfile->print_version = 1; + break; + + case OPT_C: + CPP_OPTION (pfile, discard_comments) = 0; + break; + case OPT_P: + CPP_OPTION (pfile, no_line_commands) = 1; + break; + case OPT_dollar: /* Don't include $ in identifiers. */ + CPP_OPTION (pfile, dollars_in_ident) = 0; + break; + case OPT_H: + CPP_OPTION (pfile, print_include_names) = 1; + break; + case OPT_D: + new_pending_directive (pend, arg, cpp_define); + break; + case OPT_pedantic_errors: + CPP_OPTION (pfile, pedantic_errors) = 1; + /* fall through */ + case OPT_pedantic: + CPP_OPTION (pfile, pedantic) = 1; + break; + case OPT_trigraphs: + CPP_OPTION (pfile, trigraphs) = 1; + break; + case OPT_plus: + CPP_OPTION (pfile, cplusplus) = 1; + CPP_OPTION (pfile, cplusplus_comments) = 1; + break; + case OPT_remap: + CPP_OPTION (pfile, remap) = 1; + break; + case OPT_iprefix: + CPP_OPTION (pfile, include_prefix) = arg; + CPP_OPTION (pfile, include_prefix_len) = strlen (arg); + break; + case OPT_lang_c: + set_lang (pfile, CLK_GNUC89); + break; + case OPT_lang_cplusplus: + set_lang (pfile, CLK_GNUCXX); + break; + case OPT_lang_objc: + set_lang (pfile, CLK_OBJC); + break; + case OPT_lang_objcplusplus: + set_lang (pfile, CLK_OBJCXX); + break; + case OPT_lang_asm: + set_lang (pfile, CLK_ASM); + break; + case OPT_std_cplusplus98: + set_lang (pfile, CLK_CXX98); + break; + case OPT_std_gnu89: + set_lang (pfile, CLK_GNUC89); + break; + case OPT_std_gnu9x: + case OPT_std_gnu99: + set_lang (pfile, CLK_GNUC99); + break; + case OPT_std_iso9899_199409: + set_lang (pfile, CLK_STDC94); + break; + case OPT_std_iso9899_1990: + case OPT_std_c89: + case OPT_lang_c89: + set_lang (pfile, CLK_STDC89); + break; + case OPT_std_iso9899_199x: + case OPT_std_iso9899_1999: + case OPT_std_c9x: + case OPT_std_c99: + set_lang (pfile, CLK_STDC99); + break; + case OPT_nostdinc: + /* -nostdinc causes no default include directories. + You must specify all include-file directories with -I. */ + CPP_OPTION (pfile, no_standard_includes) = 1; + break; + case OPT_nostdincplusplus: + /* -nostdinc++ causes no default C++-specific include directories. */ + CPP_OPTION (pfile, no_standard_cplusplus_includes) = 1; + break; + case OPT_o: + if (CPP_OPTION (pfile, out_fname) == NULL) + CPP_OPTION (pfile, out_fname) = arg; + else + { + cpp_fatal (pfile, "output filename specified twice"); + return argc; + } + break; + case OPT_d: + /* Args to -d specify what parts of macros to dump. + Silently ignore unrecognised options; they may + be aimed at the compiler proper. */ + { + char c; + + while ((c = *arg++) != '\0') + switch (c) + { + case 'M': + CPP_OPTION (pfile, dump_macros) = dump_only; + CPP_OPTION (pfile, no_output) = 1; break; case 'N': - opts->dump_macros = dump_names; + CPP_OPTION (pfile, dump_macros) = dump_names; break; case 'D': - opts->dump_macros = dump_definitions; + CPP_OPTION (pfile, dump_macros) = dump_definitions; break; case 'I': - opts->dump_includes = 1; + CPP_OPTION (pfile, dump_includes) = 1; break; } - } - } - break; - - case 'g': - if (argv[i][2] == '3') - opts->debug_output = 1; - break; - - case '-': - if (!strcmp (argv[i], "--help")) - print_help (); - else if (!strcmp (argv[i], "--version")) - cpp_notice ("GNU CPP version %s\n", version_string); - exit (0); /* XXX */ - break; - - case 'v': - cpp_notice ("GNU CPP version %s", version_string); -#ifdef TARGET_VERSION - TARGET_VERSION; -#endif - fputc ('\n', stderr); - opts->verbose = 1; - break; - - case 'H': - opts->print_include_names = 1; - break; - - case 'D': - { - struct pending_option *o = (struct pending_option *) - xmalloc (sizeof (struct pending_option)); - if (argv[i][2] != 0) - o->arg = argv[i] + 2; - else if (i + 1 == argc) - { - cpp_fatal (pfile, "Macro name missing after -D option"); - return argc; - } - else - o->arg = argv[++i]; + } + break; - o->next = NULL; - o->undef = 0; - APPEND (opts->pending, define, o); - } - break; - - case 'A': - { - char *p; - - if (argv[i][2] != 0) - p = argv[i] + 2; - else if (i + 1 == argc) - { - cpp_fatal (pfile, "Assertion missing after -A option"); - return argc; - } - else - p = argv[++i]; - - if (strcmp (p, "-")) - { - struct pending_option *o = (struct pending_option *) - xmalloc (sizeof (struct pending_option)); + case OPT_MG: + CPP_OPTION (pfile, print_deps_missing_files) = 1; + break; + case OPT_M: + CPP_OPTION (pfile, print_deps) = 2; + break; + case OPT_MM: + CPP_OPTION (pfile, print_deps) = 1; + break; + case OPT_MF: + CPP_OPTION (pfile, deps_file) = arg; + break; + case OPT_MP: + CPP_OPTION (pfile, deps_phony_targets) = 1; + break; + case OPT_MQ: + case OPT_MT: + /* Add a target. -MQ quotes for Make. */ + deps_add_target (pfile->deps, arg, opt_code == OPT_MQ); + break; - o->arg = p; - o->next = NULL; - o->undef = 0; - APPEND (opts->pending, assert, o); + /* -MD and -MMD for cpp0 are deprecated and undocumented + (use -M or -MM with -MF instead), and probably should be + removed with the next major GCC version. For the moment + we allow these for the benefit of Automake 1.4, which + uses these when dependency tracking is enabled. Automake + 1.5 will fix this. */ + case OPT_MD: + CPP_OPTION (pfile, print_deps) = 2; + CPP_OPTION (pfile, deps_file) = arg; + break; + case OPT_MMD: + CPP_OPTION (pfile, print_deps) = 1; + CPP_OPTION (pfile, deps_file) = arg; + break; + + case OPT_A: + if (arg[0] == '-') + { + /* -A with an argument beginning with '-' acts as + #unassert on whatever immediately follows the '-'. + If "-" is the whole argument, we eliminate all + predefined macros and assertions, including those + that were specified earlier on the command line. + That way we can get rid of any that were passed + automatically in from GCC. */ + + if (arg[1] == '\0') + { + free_chain (pend->directive_head); + pend->directive_head = NULL; + pend->directive_tail = NULL; + } + else + new_pending_directive (pend, arg + 1, cpp_unassert); } else - { - /* -A- eliminates all predefined macros and assertions. - Let's include also any that were specified earlier - on the command line. That way we can get rid of any - that were passed automatically in from GCC. */ - struct pending_option *o1, *o2; - - o1 = opts->pending->define_head; - while (o1) + new_pending_directive (pend, arg, cpp_assert); + break; + case OPT_U: + new_pending_directive (pend, arg, cpp_undef); + break; + case OPT_I: /* Add directory to path for includes. */ + if (!strcmp (arg, "-")) + { + /* -I- means: + Use the preceding -I directories for #include "..." + but not #include <...>. + Don't search the directory of the present file + for #include "...". (Note that -I. -I- is not the same as + the default setup; -I. uses the compiler's working dir.) */ + if (! CPP_OPTION (pfile, ignore_srcdir)) { - o2 = o1->next; - free (o1); - o1 = o2; + pend->quote_head = pend->brack_head; + pend->quote_tail = pend->brack_tail; + pend->brack_head = 0; + pend->brack_tail = 0; + CPP_OPTION (pfile, ignore_srcdir) = 1; } - o1 = opts->pending->assert_head; - while (o1) + else { - o2 = o1->next; - free (o1); - o1 = o2; + cpp_fatal (pfile, "-I- specified twice"); + return argc; } - opts->pending->assert_head = NULL; - opts->pending->assert_tail = NULL; - opts->pending->define_head = NULL; - opts->pending->define_tail = NULL; - } - } - break; - - case 'U': - { - struct pending_option *o = (struct pending_option *) - xmalloc (sizeof (struct pending_option)); - - if (argv[i][2] != 0) - o->arg = argv[i] + 2; - else if (i + 1 == argc) - { - cpp_fatal (pfile, "Macro name missing after -U option"); - return argc; - } - else - o->arg = argv[++i]; + } + else + append_include_chain (pfile, xstrdup (arg), BRACKET, 0); + break; + case OPT_isystem: + /* Add directory to beginning of system include path, as a system + include directory. */ + append_include_chain (pfile, xstrdup (arg), SYSTEM, 0); + break; + case OPT_include: + case OPT_imacros: + { + struct pending_option *o = (struct pending_option *) + xmalloc (sizeof (struct pending_option)); + o->arg = arg; + o->next = NULL; - o->next = NULL; - o->undef = 1; - APPEND (opts->pending, define, o); - } - break; - - case 'C': - opts->put_out_comments = 1; - break; - - case 'E': /* -E comes from cc -E; ignore it. */ - break; - - case 'P': - opts->no_line_commands = 1; - break; - - case '$': /* Don't include $ in identifiers. */ - opts->dollars_in_ident = 0; - break; - - case 'n': - if (!strcmp (argv[i], "-nostdinc")) - /* -nostdinc causes no default include directories. - You must specify all include-file directories with -I. */ - opts->no_standard_includes = 1; - else if (!strcmp (argv[i], "-nostdinc++")) - /* -nostdinc++ causes no default C++-specific include directories. */ - opts->no_standard_cplusplus_includes = 1; -#if 0 - else if (!strcmp (argv[i], "-noprecomp")) - no_precomp = 1; -#endif - break; - - case 'r': - if (!strcmp (argv[i], "-remap")) - opts->remap = 1; - break; - - case '\0': /* JF handle '-' as file name meaning stdin or stdout */ - if (opts->in_fname == NULL) - opts->in_fname = ""; - else if (opts->out_fname == NULL) - opts->out_fname = ""; - else - return i; /* error */ - break; + if (opt_code == OPT_include) + APPEND (pend, include, o); + else + APPEND (pend, imacros, o); + } + break; + case OPT_iwithprefix: + /* Add directory to end of path for includes, + with the default prefix at the front of its name. */ + /* fall through */ + case OPT_iwithprefixbefore: + /* Add directory to main path for includes, + with the default prefix at the front of its name. */ + { + char *fname; + int len; - default: - return i; - } + len = strlen (arg); - return i + 1; + if (CPP_OPTION (pfile, include_prefix) != 0) + { + size_t ipl = CPP_OPTION (pfile, include_prefix_len); + fname = xmalloc (ipl + len + 1); + memcpy (fname, CPP_OPTION (pfile, include_prefix), ipl); + memcpy (fname + ipl, arg, len + 1); + } + else if (cpp_GCC_INCLUDE_DIR_len) + { + fname = xmalloc (cpp_GCC_INCLUDE_DIR_len + len + 1); + memcpy (fname, cpp_GCC_INCLUDE_DIR, cpp_GCC_INCLUDE_DIR_len); + memcpy (fname + cpp_GCC_INCLUDE_DIR_len, arg, len + 1); + } + else + fname = xstrdup (arg); - missing_filename: - cpp_fatal (pfile, "Filename missing after `%s' option", argv[i]); - return argc; - missing_dirname: - cpp_fatal (pfile, "Directory name missing after `%s' option", argv[i]); - return argc; + append_include_chain (pfile, fname, + opt_code == OPT_iwithprefix ? SYSTEM: BRACKET, 0); + } + break; + case OPT_idirafter: + /* Add directory to end of path for includes. */ + append_include_chain (pfile, xstrdup (arg), AFTER, 0); + break; + case OPT_W: + /* Silently ignore unrecognised options. */ + if (!strcmp (argv[i], "-Wall")) + { + CPP_OPTION (pfile, warn_trigraphs) = 1; + CPP_OPTION (pfile, warn_comments) = 1; + } + else if (!strcmp (argv[i], "-Wtraditional")) + CPP_OPTION (pfile, warn_traditional) = 1; + else if (!strcmp (argv[i], "-Wtrigraphs")) + CPP_OPTION (pfile, warn_trigraphs) = 1; + else if (!strcmp (argv[i], "-Wcomment")) + CPP_OPTION (pfile, warn_comments) = 1; + else if (!strcmp (argv[i], "-Wcomments")) + CPP_OPTION (pfile, warn_comments) = 1; + else if (!strcmp (argv[i], "-Wundef")) + CPP_OPTION (pfile, warn_undef) = 1; + else if (!strcmp (argv[i], "-Wimport")) + CPP_OPTION (pfile, warn_import) = 1; + else if (!strcmp (argv[i], "-Werror")) + CPP_OPTION (pfile, warnings_are_errors) = 1; + else if (!strcmp (argv[i], "-Wsystem-headers")) + CPP_OPTION (pfile, warn_system_headers) = 1; + else if (!strcmp (argv[i], "-Wno-traditional")) + CPP_OPTION (pfile, warn_traditional) = 0; + else if (!strcmp (argv[i], "-Wno-trigraphs")) + CPP_OPTION (pfile, warn_trigraphs) = 0; + else if (!strcmp (argv[i], "-Wno-comment")) + CPP_OPTION (pfile, warn_comments) = 0; + else if (!strcmp (argv[i], "-Wno-comments")) + CPP_OPTION (pfile, warn_comments) = 0; + else if (!strcmp (argv[i], "-Wno-undef")) + CPP_OPTION (pfile, warn_undef) = 0; + else if (!strcmp (argv[i], "-Wno-import")) + CPP_OPTION (pfile, warn_import) = 0; + else if (!strcmp (argv[i], "-Wno-error")) + CPP_OPTION (pfile, warnings_are_errors) = 0; + else if (!strcmp (argv[i], "-Wno-system-headers")) + CPP_OPTION (pfile, warn_system_headers) = 0; + else if (! ignore) + return i; + break; + } + } + return i + 1; } /* Handle command-line options in (argc, argv). Can be called multiple times, to handle multiple sets of options. Returns if an unrecognized option is seen. Returns number of strings consumed. */ - int cpp_handle_options (pfile, argc, argv) cpp_reader *pfile; @@ -1698,19 +1755,132 @@ cpp_handle_options (pfile, argc, argv) { int i; int strings_processed; + for (i = 0; i < argc; i += strings_processed) { - strings_processed = cpp_handle_option (pfile, argc - i, argv + i); + strings_processed = cpp_handle_option (pfile, argc - i, argv + i, 1); if (strings_processed == 0) break; } + return i; } +/* Extra processing when all options are parsed, after all calls to + cpp_handle_option[s]. Consistency checks etc. */ +void +cpp_post_options (pfile) + cpp_reader *pfile; +{ + if (pfile->print_version) + { + fprintf (stderr, _("GNU CPP version %s (cpplib)"), version_string); +#ifdef TARGET_VERSION + TARGET_VERSION; +#endif + fputc ('\n', stderr); + } + + /* Canonicalize in_fname and out_fname. We guarantee they are not + NULL, and that the empty string represents stdin / stdout. */ + if (CPP_OPTION (pfile, in_fname) == NULL + || !strcmp (CPP_OPTION (pfile, in_fname), "-")) + CPP_OPTION (pfile, in_fname) = ""; + + if (CPP_OPTION (pfile, out_fname) == NULL + || !strcmp (CPP_OPTION (pfile, out_fname), "-")) + CPP_OPTION (pfile, out_fname) = ""; + + /* -Wtraditional is not useful in C++ mode. */ + if (CPP_OPTION (pfile, cplusplus)) + CPP_OPTION (pfile, warn_traditional) = 0; + + /* Set this if it hasn't been set already. */ + if (CPP_OPTION (pfile, user_label_prefix) == NULL) + CPP_OPTION (pfile, user_label_prefix) = USER_LABEL_PREFIX; + + /* Permanently disable macro expansion if we are rescanning + preprocessed text. */ + if (CPP_OPTION (pfile, preprocessed)) + pfile->state.prevent_expansion = 1; + + /* We need to do this after option processing and before + cpp_start_read, as cppmain.c relies on the options->no_output to + set its callbacks correctly before calling cpp_start_read. */ + init_dependency_output (pfile); + + /* After checking the environment variables, check if -M or -MM has + not been specified, but other -M options have. */ + if (CPP_OPTION (pfile, print_deps) == 0 && + (CPP_OPTION (pfile, print_deps_missing_files) + || CPP_OPTION (pfile, deps_file) + || CPP_OPTION (pfile, deps_phony_targets))) + cpp_fatal (pfile, "you must additionally specify either -M or -MM"); +} + +/* Set up dependency-file output. */ +static void +init_dependency_output (pfile) + cpp_reader *pfile; +{ + char *spec, *s, *output_file; + + /* Either of two environment variables can specify output of deps. + Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET", + where OUTPUT_FILE is the file to write deps info to + and DEPS_TARGET is the target to mention in the deps. */ + + if (CPP_OPTION (pfile, print_deps) == 0) + { + spec = getenv ("DEPENDENCIES_OUTPUT"); + if (spec) + CPP_OPTION (pfile, print_deps) = 1; + else + { + spec = getenv ("SUNPRO_DEPENDENCIES"); + if (spec) + CPP_OPTION (pfile, print_deps) = 2; + else + return; + } + + /* Find the space before the DEPS_TARGET, if there is one. */ + s = strchr (spec, ' '); + if (s) + { + /* Let the caller perform MAKE quoting. */ + deps_add_target (pfile->deps, s + 1, 0); + output_file = (char *) xmalloc (s - spec + 1); + memcpy (output_file, spec, s - spec); + output_file[s - spec] = 0; + } + else + output_file = spec; + + /* Command line overrides environment variables. */ + if (CPP_OPTION (pfile, deps_file) == 0) + CPP_OPTION (pfile, deps_file) = output_file; + CPP_OPTION (pfile, print_deps_append) = 1; + } + + /* If dependencies go to standard output, or -MG is used, we should + suppress output, including -dM, -dI etc. */ + if (CPP_OPTION (pfile, deps_file) == 0 + || CPP_OPTION (pfile, print_deps_missing_files)) + { + CPP_OPTION (pfile, no_output) = 1; + CPP_OPTION (pfile, dump_macros) = 0; + CPP_OPTION (pfile, dump_includes) = 0; + } +} + +/* Handle --help output. */ static void print_help () { - cpp_notice ("Usage: %s [switches] input output\n", progname); + fprintf (stderr, _("Usage: %s [switches] input output\n"), progname); + /* To keep the lines from getting too long for some compilers, limit + to about 500 characters (6 lines) per chunk. */ fputs (_("\ Switches:\n\ -include <file> Include the contents of <file> before other files\n\ @@ -1719,62 +1889,89 @@ Switches:\n\ -iwithprefix <dir> Add <dir> to the end of the system include path\n\ -iwithprefixbefore <dir> Add <dir> to the end of the main include path\n\ -isystem <dir> Add <dir> to the start of the system include path\n\ +"), stdout); + fputs (_("\ -idirafter <dir> Add <dir> to the end of the system include path\n\ -I <dir> Add <dir> to the end of the main include path\n\ + -I- Fine-grained include path control; see info docs\n\ -nostdinc Do not search system include directories\n\ (dirs specified with -isystem will still be used)\n\ -nostdinc++ Do not search system include directories for C++\n\ -o <file> Put output into <file>\n\ - -pedantic Issue all warnings demanded by strict ANSI C\n\ - -traditional Follow K&R pre-processor behaviour\n\ - -trigraphs Support ANSI C trigraphs\n\ +"), stdout); + fputs (_("\ + -pedantic Issue all warnings demanded by strict ISO C\n\ + -pedantic-errors Issue -pedantic warnings as errors instead\n\ + -trigraphs Support ISO C trigraphs\n\ -lang-c Assume that the input sources are in C\n\ -lang-c89 Assume that the input sources are in C89\n\ +"), stdout); + fputs (_("\ -lang-c++ Assume that the input sources are in C++\n\ -lang-objc Assume that the input sources are in ObjectiveC\n\ -lang-objc++ Assume that the input sources are in ObjectiveC++\n\ -lang-asm Assume that the input sources are in assembler\n\ - -lang-chill Assume that the input sources are in Chill\n\ +"), stdout); + fputs (_("\ -std=<std name> Specify the conformance standard; one of:\n\ - gnu89, gnu9x, c89, c9x, iso9899:1990,\n\ - iso9899:199409, iso9899:199x\n\ + gnu89, gnu99, c89, c99, iso9899:1990,\n\ + iso9899:199409, iso9899:1999\n\ -+ Allow parsing of C++ style features\n\ -w Inhibit warning messages\n\ -Wtrigraphs Warn if trigraphs are encountered\n\ -Wno-trigraphs Do not warn about trigraphs\n\ -Wcomment{s} Warn if one comment starts inside another\n\ +"), stdout); + fputs (_("\ -Wno-comment{s} Do not warn about comments\n\ - -Wtraditional Warn if a macro argument is/would be turned into\n\ - a string if -traditional is specified\n\ - -Wno-traditional Do not warn about stringification\n\ + -Wtraditional Warn about features not present in traditional C\n\ + -Wno-traditional Do not warn about traditional C\n\ -Wundef Warn if an undefined macro is used by #if\n\ -Wno-undef Do not warn about testing undefined macros\n\ -Wimport Warn about the use of the #import directive\n\ +"), stdout); + fputs (_("\ -Wno-import Do not warn about the use of #import\n\ -Werror Treat all warnings as errors\n\ -Wno-error Do not treat warnings as errors\n\ + -Wsystem-headers Do not suppress warnings from system headers\n\ + -Wno-system-headers Suppress warnings from system headers\n\ -Wall Enable all preprocessor warnings\n\ +"), stdout); + fputs (_("\ -M Generate make dependencies\n\ -MM As -M, but ignore system header files\n\ - -MD As -M, but put output in a .d file\n\ - -MMD As -MD, but ignore system header files\n\ + -MF <file> Write dependency output to the given file\n\ -MG Treat missing header file as generated files\n\ - -g Include #define and #undef directives in the output\n\ +"), stdout); + fputs (_("\ + -MP Generate phony targets for all headers\n\ + -MQ <target> Add a MAKE-quoted target\n\ + -MT <target> Add an unquoted target\n\ +"), stdout); + fputs (_("\ -D<macro> Define a <macro> with string '1' as its value\n\ -D<macro>=<val> Define a <macro> with <val> as its value\n\ -A<question> (<answer>) Assert the <answer> to <question>\n\ + -A-<question> (<answer>) Disable the <answer> to <question>\n\ -U<macro> Undefine <macro> \n\ -v Display the version number\n\ +"), stdout); + fputs (_("\ -H Print the name of header files as they are used\n\ -C Do not discard comments\n\ -dM Display a list of macro definitions active at end\n\ -dD Preserve macro definitions in output\n\ -dN As -dD except that only the names are preserved\n\ -dI Include #include directives in the output\n\ - -ifoutput Describe skipped code blocks in output \n\ +"), stdout); + fputs (_("\ + -fpreprocessed Treat the input file as already preprocessed\n\ + -ftabstop=<number> Distance between tab stops for column reporting\n\ -P Do not generate #line directives\n\ -$ Do not allow '$' in identifiers\n\ -remap Remap file names when including files.\n\ + --version Display version information\n\ -h or --help Display this information\n\ "), stdout); } |