X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcppfiles.c;h=1ff34ff00846831f8ae736fcc266b44cfe3d4b60;hb=ed4ead76fec2cd562d2c0d7172aa5289bf3113ae;hp=197a8bcaa4118029d657957d68b3684740f65f61;hpb=d6cf07b1c4c306345032803460d76372fd6e9855;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 197a8bcaa41..1ff34ff0084 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -1,6 +1,6 @@ /* Part of CPP library. (include file handling) Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, - 1999, 2000, 2001 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Per Bothner, 1994. Based on CCCP program by Paul Rubin, June 1986 Adapted to ANSI C, Richard Stallman, Jan 1987 @@ -22,17 +22,50 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include +#include "coretypes.h" +#include "tm.h" #include "cpplib.h" #include "cpphash.h" #include "intl.h" #include "mkdeps.h" #include "splay-tree.h" +#ifdef ENABLE_VALGRIND_CHECKING +# ifdef HAVE_MEMCHECK_H +# include +# else +# include +# endif +#else +/* Avoid #ifdef:s when we can help it. */ +#define VALGRIND_DISCARD(x) +#endif #ifdef HAVE_MMAP_FILE # include # ifndef MMAP_THRESHOLD # define MMAP_THRESHOLD 3 /* Minimum page count to mmap the file. */ # endif +# if MMAP_THRESHOLD +# define TEST_THRESHOLD(size, pagesize) \ + (size / pagesize >= MMAP_THRESHOLD && (size % pagesize) != 0) + /* Use mmap if the file is big enough to be worth it (controlled + by MMAP_THRESHOLD) and if we can safely count on there being + at least one readable NUL byte after the end of the file's + contents. This is true for all tested operating systems when + the file size is not an exact multiple of the page size. */ +# ifndef __CYGWIN__ +# define SHOULD_MMAP(size, pagesize) TEST_THRESHOLD (size, pagesize) +# else +# define WIN32_LEAN_AND_MEAN +# include + /* Cygwin can't correctly emulate mmap under Windows 9x style systems so + disallow use of mmap on those systems. Windows 9x does not zero fill + memory at EOF and beyond, as required. */ +# define SHOULD_MMAP(size, pagesize) ((GetVersion() & 0x80000000) \ + ? 0 : TEST_THRESHOLD (size, pagesize)) +# endif +# endif #else /* No MMAP_FILE */ # undef MMAP_THRESHOLD @@ -57,51 +90,74 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #undef strcmp /* This structure is used for the table of all includes. */ -struct include_file -{ +struct include_file { const char *name; /* actual path name of file */ + const char *header_name; /* the original header found */ const cpp_hashnode *cmacro; /* macro, if any, preventing reinclusion. */ - const struct search_path *foundhere; + const struct cpp_path *foundhere; /* location in search path where file was found, for #include_next and sysp. */ const unsigned char *buffer; /* pointer to cached file contents */ struct stat st; /* copy of stat(2) data for file */ int fd; /* fd open on file (short term storage only) */ + int err_no; /* errno obtained if opening a file failed */ unsigned short include_count; /* number of times file has been read */ unsigned short refcnt; /* number of stacked buffers using this file */ unsigned char mapped; /* file buffer is mmapped */ - unsigned char defined; /* cmacro prevents inclusion in this state */ + unsigned char pch; /* 0: file not known to be a PCH. + 1: file is a PCH + (on return from find_include_file). + 2: file is not and never will be a valid + precompiled header. + 3: file is always a valid precompiled + header. */ }; +/* Variable length record files on VMS will have a stat size that includes + record control characters that won't be included in the read size. */ +#ifdef VMS +# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */ +# define STAT_SIZE_TOO_BIG(ST) ((ST).st_fab_rfm == FAB_C_VAR) +#else +# define STAT_SIZE_TOO_BIG(ST) 0 +#endif + /* The cmacro works like this: If it's NULL, the file is to be included again. If it's NEVER_REREAD, the file is never to be included again. Otherwise it is a macro hashnode, and the file is - to be included again if the macro is defined or not as specified by - DEFINED. */ -#define NEVER_REREAD ((const cpp_hashnode *)-1) + to be included again if the macro is defined. */ +#define NEVER_REREAD ((const cpp_hashnode *) -1) #define DO_NOT_REREAD(inc) \ ((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \ - || ((inc)->cmacro->type == NT_MACRO) == (inc)->defined)) + || (inc)->cmacro->type == NT_MACRO)) +#define NO_INCLUDE_PATH ((struct include_file *) -1) +#define INCLUDE_PCH_P(F) (((F)->pch & 1) != 0) static struct file_name_map *read_name_map PARAMS ((cpp_reader *, const char *)); static char *read_filename_string PARAMS ((int, FILE *)); static char *remap_filename PARAMS ((cpp_reader *, char *, - struct search_path *)); -static struct search_path *search_from PARAMS ((cpp_reader *, - struct include_file *)); -static struct include_file *find_include_file - PARAMS ((cpp_reader *, const char *, - struct search_path *)); + struct cpp_path *)); +static struct cpp_path *search_from PARAMS ((cpp_reader *, + enum include_type)); +static struct include_file * + find_include_file PARAMS ((cpp_reader *, const cpp_token *, + enum include_type)); static struct include_file *open_file PARAMS ((cpp_reader *, const char *)); -static void read_include_file PARAMS ((cpp_reader *, struct include_file *)); -static void stack_include_file PARAMS ((cpp_reader *, struct include_file *)); +static struct include_file *validate_pch PARAMS ((cpp_reader *, + const char *, + const char *)); +static struct include_file *open_file_pch PARAMS ((cpp_reader *, + const char *)); +static int read_include_file PARAMS ((cpp_reader *, struct include_file *)); +static bool stack_include_file PARAMS ((cpp_reader *, struct include_file *)); static void purge_cache PARAMS ((struct include_file *)); static void destroy_node PARAMS ((splay_tree_value)); static int report_missing_guard PARAMS ((splay_tree_node, void *)); static splay_tree_node find_or_create_entry PARAMS ((cpp_reader *, const char *)); static void handle_missing_header PARAMS ((cpp_reader *, const char *, int)); +static int remove_component_p PARAMS ((const char *)); /* Set up the splay tree we use to store information about all the file names seen in this compilation. We also have entries for each @@ -109,7 +165,7 @@ static void handle_missing_header PARAMS ((cpp_reader *, const char *, int)); don't try to open it again in future. The key of each node is the file name, after processing by - _cpp_simplify_pathname. The path name may or may not be absolute. + cpp_simplify_path. The path name may or may not be absolute. The path string has been malloced, as is automatically freed by registering free () as the splay tree key deletion function. @@ -138,7 +194,7 @@ static void destroy_node (v) splay_tree_value v; { - struct include_file *f = (struct include_file *)v; + struct include_file *f = (struct include_file *) v; if (f) { @@ -155,7 +211,8 @@ _cpp_never_reread (file) file->cmacro = NEVER_REREAD; } -/* Lookup a simplified filename, and create an entry if none exists. */ +/* Lookup a filename, which is simplified after making a copy, and + create an entry if none exists. */ static splay_tree_node find_or_create_entry (pfile, fname) cpp_reader *pfile; @@ -163,12 +220,18 @@ find_or_create_entry (pfile, fname) { splay_tree_node node; struct include_file *file; + char *name = xstrdup (fname); - node = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname); - if (! node) + cpp_simplify_path (name); + node = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name); + if (node) + free (name); + else { file = xcnew (struct include_file); - file->name = xstrdup (fname); + file->name = name; + file->header_name = name; + file->err_no = errno; node = splay_tree_insert (pfile->all_include_files, (splay_tree_key) file->name, (splay_tree_value) file); @@ -177,8 +240,7 @@ find_or_create_entry (pfile, fname) return node; } -/* Enter a simplified file name in the splay tree, for the sake of - cpp_included (). */ +/* Enter a file name in the splay tree, for the sake of cpp_included. */ void _cpp_fake_include (pfile, fname) cpp_reader *pfile; @@ -196,7 +258,6 @@ _cpp_fake_include (pfile, fname) Returns an include_file structure with an open file descriptor on success, or NULL on failure. */ - static struct include_file * open_file (pfile, filename) cpp_reader *pfile; @@ -205,15 +266,18 @@ open_file (pfile, filename) splay_tree_node nd = find_or_create_entry (pfile, filename); struct include_file *file = (struct include_file *) nd->value; - /* Don't retry opening if we failed previously. */ - if (file->fd == -2) - return 0; + if (file->err_no) + { + /* Ugh. handle_missing_header () needs errno to be set. */ + errno = file->err_no; + return 0; + } - /* Don't reopen an idempotent file. */ + /* Don't reopen an idempotent file. */ if (DO_NOT_REREAD (file)) return file; - - /* Don't reopen one which is already loaded. */ + + /* Don't reopen one which is already loaded. */ if (file->buffer != NULL) return file; @@ -232,82 +296,194 @@ open_file (pfile, filename) Special case: the empty string is translated to stdin. */ if (filename[0] == '\0') - file->fd = 0; + { + file->fd = 0; +#ifdef __DJGPP__ + /* For DJGPP redirected input is opened in text mode. Change it + to binary mode. */ + if (! isatty (file->fd)) + setmode (file->fd, O_BINARY); +#endif + } else - file->fd = open (filename, O_RDONLY | O_NOCTTY | O_BINARY, 0666); + file->fd = open (file->name, O_RDONLY | O_NOCTTY | O_BINARY, 0666); if (file->fd != -1 && fstat (file->fd, &file->st) == 0) { - /* Mark a regular, zero-length file never-reread now. */ - if (S_ISREG (file->st.st_mode) && file->st.st_size == 0) - { - _cpp_never_reread (file); - close (file->fd); - file->fd = -1; - } + if (!S_ISDIR (file->st.st_mode)) + return file; + + /* If it's a directory, we return null and continue the search + as the file we're looking for may appear elsewhere in the + search path. */ + errno = ENOENT; + close (file->fd); + file->fd = -1; + } + + file->err_no = errno; + return 0; +} +static struct include_file * +validate_pch (pfile, filename, pchname) + cpp_reader *pfile; + const char *filename; + const char *pchname; +{ + struct include_file * file; + + file = open_file (pfile, pchname); + if (file == NULL) + return NULL; + if ((file->pch & 2) == 0) + file->pch = pfile->cb.valid_pch (pfile, pchname, file->fd); + if (INCLUDE_PCH_P (file)) + { + char *f = xstrdup (filename); + cpp_simplify_path (f); + file->header_name = f; return file; } + close (file->fd); + file->fd = -1; + return NULL; +} - /* Don't issue an error message if the file doesn't exist. */ - if (errno != ENOENT && errno != ENOTDIR) - cpp_error_from_errno (pfile, filename); - /* Create a negative node for this path, and return null. */ - file->fd = -2; +/* Like open_file, but also look for a precompiled header if (a) one exists + and (b) it is valid. */ +static struct include_file * +open_file_pch (pfile, filename) + cpp_reader *pfile; + const char *filename; +{ + if (filename[0] != '\0' + && pfile->cb.valid_pch != NULL) + { + size_t namelen = strlen (filename); + char *pchname = alloca (namelen + 5); + struct include_file * file; + splay_tree_node nd; + + memcpy (pchname, filename, namelen); + memcpy (pchname + namelen, ".gch", 5); - return 0; -} + nd = find_or_create_entry (pfile, pchname); + file = (struct include_file *) nd->value; -/* Place the file referenced by INC into a new buffer on PFILE's - stack. If there are errors, or the file should not be re-included, - a null buffer is pushed. */ + if (file != NULL) + { + if (stat (file->name, &file->st) == 0 && S_ISDIR (file->st.st_mode)) + { + DIR * thedir; + struct dirent *d; + size_t subname_len = namelen + 64; + char *subname = xmalloc (subname_len); + + thedir = opendir (pchname); + if (thedir == NULL) + return NULL; + memcpy (subname, pchname, namelen + 4); + subname[namelen+4] = '/'; + while ((d = readdir (thedir)) != NULL) + { + if (strlen (d->d_name) + namelen + 7 > subname_len) + { + subname_len = strlen (d->d_name) + namelen + 64; + subname = xrealloc (subname, subname_len); + } + strcpy (subname + namelen + 5, d->d_name); + file = validate_pch (pfile, filename, subname); + if (file) + break; + } + closedir (thedir); + free (subname); + } + else + file = validate_pch (pfile, filename, pchname); + if (file) + return file; + } + } + return open_file (pfile, filename); +} -static void +/* Place the file referenced by INC into a new buffer on the buffer + stack, unless there are errors, or the file is not re-included + because of e.g. multiple-include guards. Returns true if a buffer + is stacked. */ +static bool stack_include_file (pfile, inc) cpp_reader *pfile; struct include_file *inc; { - size_t len = 0; cpp_buffer *fp; - int sysp, deps_sysp; + int sysp; + const char *filename; - /* We'll try removing deps_sysp after the release of 3.0. */ - deps_sysp = pfile->system_include_depth != 0; - sysp = ((pfile->buffer && pfile->buffer->sysp) - || (inc->foundhere && inc->foundhere->sysp)); + if (DO_NOT_REREAD (inc)) + return false; - /* For -M, add the file to the dependencies on its first inclusion. */ - if (CPP_OPTION (pfile, print_deps) > deps_sysp && !inc->include_count) - deps_add_dep (pfile->deps, inc->name); + sysp = MAX ((pfile->map ? pfile->map->sysp : 0), + (inc->foundhere ? inc->foundhere->sysp : 0)); - /* We don't want multiple include guard advice for the main file. */ - if (pfile->buffer) - inc->include_count++; + /* Add the file to the dependencies on its first inclusion. */ + if (CPP_OPTION (pfile, deps.style) > !!sysp && !inc->include_count) + { + if (pfile->buffer || CPP_OPTION (pfile, deps.ignore_main_file) == 0) + deps_add_dep (pfile->deps, inc->name); + } + + /* PCH files get dealt with immediately. */ + if (INCLUDE_PCH_P (inc)) + { + pfile->cb.read_pch (pfile, inc->name, inc->fd, inc->header_name); + close (inc->fd); + inc->fd = -1; + return false; + } /* Not in cache? */ if (! inc->buffer) - read_include_file (pfile, inc); + { + if (read_include_file (pfile, inc)) + { + /* If an error occurs, do not try to read this file again. */ + _cpp_never_reread (inc); + return false; + } + /* Mark a regular, zero-length file never-reread. We read it, + NUL-terminate it, and stack it once, so preprocessing a main + file of zero length does not raise an error. */ + if (S_ISREG (inc->st.st_mode) && inc->st.st_size == 0) + _cpp_never_reread (inc); + close (inc->fd); + inc->fd = -1; + } - if (! DO_NOT_REREAD (inc)) - len = inc->st.st_size; + if (pfile->buffer) + /* We don't want MI guard advice for the main file. */ + inc->include_count++; /* Push a buffer. */ - fp = cpp_push_buffer (pfile, inc->buffer, len, BUF_FILE, inc->name); + fp = cpp_push_buffer (pfile, inc->buffer, inc->st.st_size, + /* from_stage3 */ CPP_OPTION (pfile, preprocessed), 0); fp->inc = inc; fp->inc->refcnt++; - fp->sysp = sysp; - fp->search_from = search_from (pfile, inc); - /* Initialise controlling macro state. */ - pfile->mi_state = MI_OUTSIDE; + /* Initialize controlling macro state. */ + pfile->mi_valid = true; pfile->mi_cmacro = 0; - pfile->include_depth++; /* Generate the call back. */ - fp->lineno = 0; - _cpp_do_file_change (pfile, FC_ENTER, 0, 0); - fp->lineno = 1; + filename = inc->name; + if (*filename == '\0') + filename = ""; + _cpp_do_file_change (pfile, LC_ENTER, filename, 1, sysp); + + return true; } /* Read the file referenced by INC into the file cache. @@ -315,30 +491,26 @@ stack_include_file (pfile, inc) If fd points to a plain file, we might be able to mmap it; we can definitely allocate the buffer all at once. If fd is a pipe or terminal, we can't do either. If fd is something weird, like a - block device or a directory, we don't want to read it at all. + block device, we don't want to read it at all. Unfortunately, different systems use different st.st_mode values for pipes: some have S_ISFIFO, some S_ISSOCK, some are buggy and zero the entire struct stat except a couple fields. Hence we don't - even try to figure out what something is, except for plain files, - directories, and block devices. + even try to figure out what something is, except for plain files + and block devices. FIXME: Flush file cache and try again if we run out of memory. */ - -static void +static int read_include_file (pfile, inc) cpp_reader *pfile; struct include_file *inc; { ssize_t size, offset, count; - U_CHAR *buf; + uchar *buf; #if MMAP_THRESHOLD static int pagesize = -1; #endif - if (DO_NOT_REREAD (inc)) - return; - if (S_ISREG (inc->st.st_mode)) { /* off_t might have a wider range than ssize_t - in other words, @@ -351,7 +523,7 @@ read_include_file (pfile, inc) does not bite us. */ if (inc->st.st_size > INTTYPE_MAXIMUM (ssize_t)) { - cpp_error (pfile, "%s is too large", inc->name); + cpp_error (pfile, DL_ERROR, "%s is too large", inc->name); goto fail; } size = inc->st.st_size; @@ -361,17 +533,22 @@ read_include_file (pfile, inc) if (pagesize == -1) pagesize = getpagesize (); - if (size / pagesize >= MMAP_THRESHOLD) + if (SHOULD_MMAP (size, pagesize)) { - buf = (U_CHAR *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0); - if (buf == (U_CHAR *)-1) + buf = (uchar *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0); + if (buf == (uchar *) -1) goto perror_fail; + + /* We must tell Valgrind that the byte at buf[size] is actually + readable. Discard the handle to avoid handle leak. */ + VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (buf + size, 1)); + inc->mapped = 1; } else #endif { - buf = (U_CHAR *) xmalloc (size); + buf = (uchar *) xmalloc (size + 1); offset = 0; while (offset < size) { @@ -380,21 +557,23 @@ read_include_file (pfile, inc) goto perror_fail; if (count == 0) { - cpp_warning (pfile, "%s is shorter than expected", inc->name); + if (!STAT_SIZE_TOO_BIG (inc->st)) + cpp_error (pfile, DL_WARNING, + "%s is shorter than expected", inc->name); + size = offset; + buf = xrealloc (buf, size + 1); + inc->st.st_size = size; break; } offset += count; } + /* The lexer requires that the buffer be NUL-terminated. */ + buf[size] = '\0'; } } else if (S_ISBLK (inc->st.st_mode)) { - cpp_error (pfile, "%s is a block device", inc->name); - goto fail; - } - else if (S_ISDIR (inc->st.st_mode)) - { - cpp_error (pfile, "%s is a directory", inc->name); + cpp_error (pfile, DL_ERROR, "%s is a block device", inc->name); goto fail; } else @@ -404,37 +583,38 @@ read_include_file (pfile, inc) bigger than the majority of C source files. */ size = 8 * 1024; - buf = (U_CHAR *) xmalloc (size); + buf = (uchar *) xmalloc (size + 1); offset = 0; while ((count = read (inc->fd, buf + offset, size - offset)) > 0) { offset += count; if (offset == size) - buf = xrealloc (buf, (size *= 2)); + { + size *= 2; + buf = xrealloc (buf, size + 1); + } } if (count < 0) goto perror_fail; - if (offset < size) - buf = xrealloc (buf, offset); + if (offset + 1 < size) + buf = xrealloc (buf, offset + 1); + + /* The lexer requires that the buffer be NUL-terminated. */ + buf[offset] = '\0'; inc->st.st_size = offset; } - close (inc->fd); inc->buffer = buf; - inc->fd = -1; - return; + return 0; perror_fail: - cpp_error_from_errno (pfile, inc->name); + cpp_errno (pfile, DL_ERROR, inc->name); fail: - /* Do not try to read this file again. */ - close (inc->fd); - inc->fd = -1; - _cpp_never_reread (inc); - return; + return 1; } +/* Drop INC's buffer from memory, if we are unlikely to need it again. */ static void purge_cache (inc) struct include_file *inc; @@ -443,7 +623,14 @@ purge_cache (inc) { #if MMAP_THRESHOLD if (inc->mapped) - munmap ((PTR) inc->buffer, inc->st.st_size); + { + /* Undo the previous annotation for the + known-zero-byte-after-mmap. Discard the handle to avoid + handle leak. */ + VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (inc->buffer + + inc->st.st_size, 1)); + munmap ((PTR) inc->buffer, inc->st.st_size); + } else #endif free ((PTR) inc->buffer); @@ -458,8 +645,8 @@ cpp_included (pfile, fname) cpp_reader *pfile; const char *fname; { - struct search_path *path; - char *name; + struct cpp_path *path; + char *name, *n; splay_tree_node nd; if (IS_ABSOLUTE_PATHNAME (fname)) @@ -468,54 +655,80 @@ cpp_included (pfile, fname) nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname); return (nd && nd->value); } - + /* Search directory path for the file. */ name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2); - for (path = CPP_OPTION (pfile, quote_include); path; path = path->next) + for (path = pfile->quote_include; path; path = path->next) { memcpy (name, path->name, path->len); name[path->len] = '/'; strcpy (&name[path->len + 1], fname); - _cpp_simplify_pathname (name); if (CPP_OPTION (pfile, remap)) - name = remap_filename (pfile, name, path); + n = remap_filename (pfile, name, path); + else + n = name; - nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name); + nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) n); if (nd && nd->value) return 1; } return 0; } -/* Search for include file FNAME in the include chain starting at - SEARCH_START. Return 0 if there is no such file (or it's un-openable), - otherwise an include_file structure. */ - +/* Search for HEADER. Return 0 if there is no such file (or it's + un-openable), in which case an error code will be in errno. If + there is no include path to use it returns NO_INCLUDE_PATH, + otherwise an include_file structure. If this request originates + from a directive of TYPE #include_next, set INCLUDE_NEXT to true. */ static struct include_file * -find_include_file (pfile, fname, search_start) +find_include_file (pfile, header, type) cpp_reader *pfile; - const char *fname; - struct search_path *search_start; + const cpp_token *header; + enum include_type type; { - struct search_path *path; - char *name; + const char *fname = (const char *) header->val.str.text; + struct cpp_path *path; struct include_file *file; + char *name, *n; if (IS_ABSOLUTE_PATHNAME (fname)) - return open_file (pfile, fname); - + return open_file_pch (pfile, fname); + + /* For #include_next, skip in the search path past the dir in which + the current file was found, but if it was found via an absolute + path use the normal search logic. */ + if (type == IT_INCLUDE_NEXT && pfile->buffer->inc->foundhere) + path = pfile->buffer->inc->foundhere->next; + else if (header->type == CPP_HEADER_NAME) + path = pfile->bracket_include; + else + path = search_from (pfile, type); + + if (path == NULL) + { + cpp_error (pfile, DL_ERROR, "no include path in which to find %s", + fname); + return NO_INCLUDE_PATH; + } + /* Search directory path for the file. */ name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2); - for (path = search_start; path; path = path->next) + for (; path; path = path->next) { - memcpy (name, path->name, path->len); - name[path->len] = '/'; - strcpy (&name[path->len + 1], fname); - _cpp_simplify_pathname (name); + int len = path->len; + memcpy (name, path->name, len); + /* Don't turn / into // or // into ///; // may be a namespace + escape. */ + if (name[len-1] == '/') + len--; + name[len] = '/'; + strcpy (&name[len + 1], fname); if (CPP_OPTION (pfile, remap)) - name = remap_filename (pfile, name, path); + n = remap_filename (pfile, name, path); + else + n = name; - file = open_file (pfile, name); + file = open_file_pch (pfile, n); if (file) { file->foundhere = path; @@ -539,9 +752,20 @@ cpp_make_system_header (pfile, syshdr, externc) /* 1 = system header, 2 = system header to be treated as C. */ if (syshdr) flags = 1 + (externc != 0); - pfile->buffer->sysp = flags; - _cpp_do_file_change (pfile, FC_RENAME, pfile->buffer->nominal_fname, - pfile->buffer->lineno); + _cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file, + SOURCE_LINE (pfile->map, pfile->line), flags); +} + +/* Allow the client to change the current file. Used by the front end + to achieve pseudo-file names like . + If REASON is LC_LEAVE, then NEW_NAME must be NULL. */ +void +cpp_change_file (pfile, reason, new_name) + cpp_reader *pfile; + enum lc_reason reason; + const char *new_name; +{ + _cpp_do_file_change (pfile, reason, new_name, 1, 0); } /* Report on all files that might benefit from a multiple include guard. @@ -555,13 +779,14 @@ _cpp_report_missing_guards (pfile) (PTR) &banner); } +/* Callback function for splay_tree_foreach(). */ static int report_missing_guard (n, b) splay_tree_node n; void *b; { struct include_file *f = (struct include_file *) n->value; - int *bannerp = (int *)b; + int *bannerp = (int *) b; if (f && f->cmacro == 0 && f->include_count == 1) { @@ -576,215 +801,133 @@ report_missing_guard (n, b) return 0; } -/* Create a dependency, or issue an error message as appropriate. */ +/* Create a dependency for file FNAME, or issue an error message as + appropriate. ANGLE_BRACKETS is nonzero if the file was bracketed + like <..>. */ static void handle_missing_header (pfile, fname, angle_brackets) cpp_reader *pfile; const char *fname; int angle_brackets; { - /* We will try making the RHS pfile->buffer->sysp after 3.0. */ - int print_dep = CPP_PRINT_DEPS(pfile) > (angle_brackets - || pfile->system_include_depth); - if (CPP_OPTION (pfile, print_deps_missing_files) && print_dep) - { - if (!angle_brackets || IS_ABSOLUTE_PATHNAME (fname)) - deps_add_dep (pfile->deps, fname); - else - { - /* If requested as a system header, assume it belongs in - the first system header directory. */ - struct search_path *ptr = CPP_OPTION (pfile, bracket_include); - char *p; - int len = 0, fname_len = strlen (fname); - - if (ptr) - len = ptr->len; - - p = (char *) alloca (len + fname_len + 2); - if (len) - { - memcpy (p, ptr->name, len); - p[len++] = '/'; - } - memcpy (p + len, fname, fname_len + 1); - _cpp_simplify_pathname (p); - deps_add_dep (pfile->deps, p); - } - } - /* If -M was specified, and this header file won't be added to - the dependency list, then don't count this as an error, - because we can still produce correct output. Otherwise, we - can't produce correct output, because there may be - dependencies we need inside the missing file, and we don't - know what directory this missing file exists in. */ - else if (CPP_PRINT_DEPS (pfile) && ! print_dep) - cpp_warning (pfile, "No include path in which to find %s", fname); + bool print_dep + = CPP_OPTION (pfile, deps.style) > (angle_brackets || pfile->map->sysp); + + if (CPP_OPTION (pfile, deps.missing_files) && print_dep) + deps_add_dep (pfile->deps, fname); + /* If -M was specified, then don't count this as an error, because + we can still produce correct output. Otherwise, we can't produce + correct output, because there may be dependencies we need inside + the missing file, and we don't know what directory this missing + file exists in. */ else - cpp_error_from_errno (pfile, fname); + cpp_errno (pfile, CPP_OPTION (pfile, deps.style) && ! print_dep + ? DL_WARNING: DL_ERROR, fname); } -void -_cpp_execute_include (pfile, header, no_reinclude, include_next) +/* Handles #include-family directives (distinguished by TYPE), + including HEADER, and the command line -imacros and -include. + Returns true if a buffer was stacked. */ +bool +_cpp_execute_include (pfile, header, type) cpp_reader *pfile; const cpp_token *header; - int no_reinclude; - int include_next; + enum include_type type; { - struct search_path *search_start = 0; - unsigned int angle_brackets = header->type == CPP_HEADER_NAME; - const char *fname = (const char *) header->val.str.text; - struct include_file *inc; + bool stacked = false; + struct include_file *inc = find_include_file (pfile, header, type); - /* Help protect #include or similar from recursion. */ - if (pfile->buffer_stack_depth >= CPP_STACK_MAX) + if (inc == 0) + handle_missing_header (pfile, (const char *) header->val.str.text, + header->type == CPP_HEADER_NAME); + else if (inc != NO_INCLUDE_PATH) { - cpp_fatal (pfile, "#include nested too deeply"); - return; - } + stacked = stack_include_file (pfile, inc); - /* Check we've tidied up #include before entering the buffer. */ - if (pfile->context->prev) - { - cpp_ice (pfile, "attempt to push file buffer with contexts stacked"); - return; + if (type == IT_IMPORT) + _cpp_never_reread (inc); } - /* For #include_next, skip in the search path past the dir in which - the current file was found. If this is the last directory in the - search path, don't include anything. If the current file was - specified with an absolute path, use the normal search logic. If - this is the primary source file, use the normal search logic and - generate a warning. */ - if (include_next) - { - if (! pfile->buffer->prev) - cpp_warning (pfile, "#include_next in primary source file"); - else - { - if (pfile->buffer->inc->foundhere) - { - search_start = pfile->buffer->inc->foundhere->next; - if (! search_start) - return; - } - } - } - - if (!search_start) - { - if (angle_brackets) - search_start = CPP_OPTION (pfile, bracket_include); - else - search_start = pfile->buffer->search_from; - - if (!search_start) - { - cpp_error (pfile, "No include path in which to find %s", fname); - return; - } - } - - inc = find_include_file (pfile, fname, search_start); - if (inc) - { - if (angle_brackets) - pfile->system_include_depth++; - - stack_include_file (pfile, inc); - - if (! DO_NOT_REREAD (inc)) - { - if (no_reinclude) - _cpp_never_reread (inc); - - /* Handle -H option. */ - if (CPP_OPTION (pfile, print_include_names)) - { - cpp_buffer *fp = pfile->buffer; - while ((fp = fp->prev) != NULL) - putc ('.', stderr); - fprintf (stderr, " %s\n", inc->name); - } - } - } - else - handle_missing_header (pfile, fname, angle_brackets); + return stacked; } -/* Locate file F, and determine whether it is newer than PFILE. Return -1, - if F cannot be located or dated, 1, if it is newer and 0 if older. */ +/* Locate HEADER, and determine whether it is newer than the current + file. If it cannot be located or dated, return -1, if it is newer + newer, return 1, otherwise 0. */ int -_cpp_compare_file_date (pfile, f) +_cpp_compare_file_date (pfile, header) cpp_reader *pfile; - const cpp_token *f; + const cpp_token *header; { - const char *fname = (const char *) f->val.str.text; - struct search_path *search_start; - struct include_file *inc; - - if (f->type == CPP_HEADER_NAME) - search_start = CPP_OPTION (pfile, bracket_include); - else - search_start = pfile->buffer->search_from; + struct include_file *inc = find_include_file (pfile, header, 0); - inc = find_include_file (pfile, fname, search_start); - - if (!inc) + if (inc == NULL || inc == NO_INCLUDE_PATH) return -1; + if (inc->fd > 0) { close (inc->fd); inc->fd = -1; } - - return inc->st.st_mtime > CPP_BUFFER (pfile)->inc->st.st_mtime; + + return inc->st.st_mtime > pfile->buffer->inc->st.st_mtime; } -/* Push an input buffer and load it up with the contents of FNAME. - If FNAME is "", read standard input. */ -int +/* Push an input buffer and load it up with the contents of FNAME. If + FNAME is "", read standard input. Return true if a buffer was + stacked. */ +bool _cpp_read_file (pfile, fname) cpp_reader *pfile; const char *fname; { + /* This uses open_file, because we don't allow a PCH to be used as + the toplevel compilation (that would prevent re-compiling an + existing PCH without deleting it first). */ struct include_file *f = open_file (pfile, fname); if (f == NULL) { - cpp_error_from_errno (pfile, fname); - return 0; + cpp_errno (pfile, DL_ERROR, fname); + return false; } - stack_include_file (pfile, f); - return 1; + return stack_include_file (pfile, f); } -/* Do appropriate cleanup when a file buffer is popped off the input - stack. */ -void -_cpp_pop_file_buffer (pfile, buf) +/* Pushes the given file onto the buffer stack. Returns nonzero if + successful. */ +bool +cpp_push_include (pfile, filename) cpp_reader *pfile; - cpp_buffer *buf; + const char *filename; { - struct include_file *inc = buf->inc; + cpp_token header; - if (pfile->system_include_depth) - pfile->system_include_depth--; - if (pfile->include_depth) - pfile->include_depth--; + header.type = CPP_STRING; + header.val.str.text = (const unsigned char *) filename; + header.val.str.len = strlen (filename); + /* Make the command line directive take up a line. */ + pfile->line++; - /* Record the inclusion-preventing macro and its definedness. */ - if (pfile->mi_state == MI_OUTSIDE && inc->cmacro != NEVER_REREAD) - { - /* This could be NULL meaning no controlling macro. */ - inc->cmacro = pfile->mi_cmacro; - inc->defined = 1; - } + return _cpp_execute_include (pfile, &header, IT_CMDLINE); +} + +/* Do appropriate cleanup when a file INC's buffer is popped off the + input stack. */ +void +_cpp_pop_file_buffer (pfile, inc) + cpp_reader *pfile; + struct include_file *inc; +{ + /* Record the inclusion-preventing macro, which could be NULL + meaning no controlling macro. */ + if (pfile->mi_valid && inc->cmacro == NULL) + inc->cmacro = pfile->mi_cmacro; /* Invalidate control macros in the #including file. */ - pfile->mi_state = MI_FAILED; + pfile->mi_valid = false; inc->refcnt--; if (inc->refcnt == 0 && DO_NOT_REREAD (inc)) @@ -793,41 +936,54 @@ _cpp_pop_file_buffer (pfile, buf) /* Returns the first place in the include chain to start searching for "" includes. This involves stripping away the basename of the - current file, unless -I- was specified. */ -static struct search_path * -search_from (pfile, inc) + current file, unless -I- was specified. + + If we're handling -include or -imacros, use the "" chain, but with + the preprocessor's cwd prepended. */ +static struct cpp_path * +search_from (pfile, type) cpp_reader *pfile; - struct include_file *inc; + enum include_type type; { cpp_buffer *buffer = pfile->buffer; unsigned int dlen; - /* Ignore the current file's directory if -I- was given. */ - if (CPP_OPTION (pfile, ignore_srcdir)) - return CPP_OPTION (pfile, quote_include); + /* Command line uses the cwd, and does not cache the result. */ + if (type == IT_CMDLINE) + goto use_cwd; - dlen = lbasename (inc->name) - inc->name; - if (dlen) - { - /* We don't guarantee NAME is null-terminated. This saves - allocating and freeing memory, and duplicating it when faking - buffers in cpp_push_buffer. Drop a trailing '/'. */ - buffer->dir.name = inc->name; - if (dlen > 1) - dlen--; - } - else + /* Ignore the current file's directory? */ + if (pfile->quote_ignores_source_dir) + return pfile->quote_include; + + if (! buffer->search_cached) { - buffer->dir.name = "."; - dlen = 1; - } + buffer->search_cached = 1; - if (dlen > pfile->max_include_len) - pfile->max_include_len = dlen; + dlen = lbasename (buffer->inc->name) - buffer->inc->name; - buffer->dir.len = dlen; - buffer->dir.next = CPP_OPTION (pfile, quote_include); - buffer->dir.sysp = buffer->sysp; + if (dlen) + { + /* We don't guarantee NAME is null-terminated. This saves + allocating and freeing memory. Drop a trailing '/'. */ + buffer->dir.name = (char *) buffer->inc->name; + if (dlen > 1) + dlen--; + } + else + { + use_cwd: + buffer->dir.name = (char *) "."; + dlen = 1; + } + + if (dlen > pfile->max_include_len) + pfile->max_include_len = dlen; + + buffer->dir.len = dlen; + buffer->dir.next = pfile->quote_include; + buffer->dir.sysp = pfile->map->sysp; + } return &buffer->dir; } @@ -839,9 +995,7 @@ search_from (pfile, inc) such as DOS. The format of the file name map file is just a series of lines with two tokens on each line. The first token is the name to map, and the second token is the actual name to use. */ - -struct file_name_map -{ +struct file_name_map { struct file_name_map *map_next; char *map_from; char *map_to; @@ -850,8 +1004,7 @@ struct file_name_map #define FILE_NAME_MAP_FILE "header.gcc" /* Read a space delimited string of unlimited length from a stdio - file. */ - + file F. */ static char * read_filename_string (ch, f) int ch; @@ -862,10 +1015,10 @@ read_filename_string (ch, f) len = 20; set = alloc = xmalloc (len + 1); - if (! is_space(ch)) + if (! is_space (ch)) { *set++ = ch; - while ((ch = getc (f)) != EOF && ! is_space(ch)) + while ((ch = getc (f)) != EOF && ! is_space (ch)) { if (set - alloc == len) { @@ -882,22 +1035,19 @@ read_filename_string (ch, f) } /* This structure holds a linked list of file name maps, one per directory. */ - -struct file_name_map_list -{ +struct file_name_map_list { struct file_name_map_list *map_list_next; char *map_list_name; struct file_name_map *map_list_map; }; /* Read the file name map file for DIRNAME. */ - static struct file_name_map * read_name_map (pfile, dirname) cpp_reader *pfile; const char *dirname; { - register struct file_name_map_list *map_list_ptr; + struct file_name_map_list *map_list_ptr; char *name; FILE *f; @@ -925,17 +1075,16 @@ read_name_map (pfile, dirname) if (f) { int ch; - int dirlen = strlen (dirname); while ((ch = getc (f)) != EOF) { char *from, *to; struct file_name_map *ptr; - if (is_space(ch)) + if (is_space (ch)) continue; from = read_filename_string (ch, f); - while ((ch = getc (f)) != EOF && is_hspace(ch)) + while ((ch = getc (f)) != EOF && is_hspace (ch)) ; to = read_filename_string (ch, f); @@ -948,12 +1097,9 @@ read_name_map (pfile, dirname) ptr->map_to = to; else { - ptr->map_to = xmalloc (dirlen + strlen (to) + 2); - strcpy (ptr->map_to, dirname); - ptr->map_to[dirlen] = '/'; - strcpy (ptr->map_to + dirlen + 1, to); + ptr->map_to = concat (dirname, "/", to, NULL); free (to); - } + } ptr->map_next = map_list_ptr->map_list_map; map_list_ptr->map_list_map = ptr; @@ -964,41 +1110,41 @@ read_name_map (pfile, dirname) } fclose (f); } - + /* Add this information to the cache. */ map_list_ptr->map_list_next = CPP_OPTION (pfile, map_list); CPP_OPTION (pfile, map_list) = map_list_ptr; return map_list_ptr->map_list_map; -} - -/* Remap NAME based on the file_name_map (if any) for LOC. */ +} +/* Remap an unsimplified path NAME based on the file_name_map (if any) + for LOC. */ static char * remap_filename (pfile, name, loc) cpp_reader *pfile; char *name; - struct search_path *loc; + struct cpp_path *loc; { struct file_name_map *map; const char *from, *p; - char *dir, *dname; - - /* Get a null-terminated path. */ - dname = alloca (loc->len + 1); - memcpy (dname, loc->name, loc->len); - dname[loc->len] = '\0'; + char *dir; if (! loc->name_map) { + /* Get a null-terminated path. */ + char *dname = alloca (loc->len + 1); + memcpy (dname, loc->name, loc->len); + dname[loc->len] = '\0'; + loc->name_map = read_name_map (pfile, dname); if (! loc->name_map) return name; } - - /* FIXME: this doesn't look right - NAME has been simplified. */ + + /* This works since NAME has not been simplified yet. */ from = name + loc->len + 1; - + for (map = loc->name_map; map; map = map->map_next) if (!strcmp (map->map_from, from)) return map->map_to; @@ -1013,13 +1159,13 @@ remap_filename (pfile, name, loc) /* We know p != name as absolute paths don't call remap_filename. */ if (p == name) - cpp_ice (pfile, "absolute file name in remap_filename"); + cpp_error (pfile, DL_ICE, "absolute file name in remap_filename"); dir = (char *) alloca (p - name + 1); memcpy (dir, name, p - name); dir[p - name] = '\0'; from = p + 1; - + for (map = read_name_map (pfile, dir); map; map = map->map_next) if (! strcmp (map->map_from, from)) return map->map_to; @@ -1027,6 +1173,59 @@ remap_filename (pfile, name, loc) return name; } +/* Set the include chain for "" to QUOTE, for <> to BRACKET. If + QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the + directory of the including file. + + If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. */ +void +cpp_set_include_chains (pfile, quote, bracket, quote_ignores_source_dir) + cpp_reader *pfile; + cpp_path *quote, *bracket; + int quote_ignores_source_dir; +{ + pfile->quote_include = quote; + pfile->bracket_include = quote; + pfile->quote_ignores_source_dir = quote_ignores_source_dir; + pfile->max_include_len = 0; + + for (; quote; quote = quote->next) + { + quote->name_map = NULL; + quote->len = strlen (quote->name); + if (quote->len > pfile->max_include_len) + pfile->max_include_len = quote->len; + if (quote == bracket) + pfile->bracket_include = bracket; + } +} + +/* Returns true if it is safe to remove the final component of path, + when it is followed by a ".." component. We use lstat to avoid + symlinks if we have it. If not, we can still catch errors with + stat (). */ +static int +remove_component_p (path) + const char *path; +{ + struct stat s; + int result; + +#ifdef HAVE_LSTAT + result = lstat (path, &s); +#else + result = stat (path, &s); +#endif + + /* There's no guarantee that errno will be unchanged, even on + success. Cygwin's lstat(), for example, will often set errno to + ENOSYS. In case of success, reset errno to zero. */ + if (result == 0) + errno = 0; + + return result == 0 && S_ISDIR (s.st_mode); +} + /* Simplify a path name in place, deleting redundant components. This reduces OS overhead and guarantees that equivalent paths compare the same (modulo symlinks). @@ -1038,124 +1237,118 @@ remap_filename (pfile, name, loc) /../quux /quux //quux //quux (POSIX allows leading // as a namespace escape) - Guarantees no trailing slashes. All transforms reduce the length - of the string. - */ + Guarantees no trailing slashes. All transforms reduce the length + of the string. Returns PATH. errno is 0 if no error occurred; + nonzero if an error occurred when using stat () or lstat (). */ void -_cpp_simplify_pathname (path) - char *path; +cpp_simplify_path (path) + char *path ATTRIBUTE_UNUSED; { - char *from, *to; - char *base; - int absolute = 0; +#ifndef VMS + char *from, *to; + char *base, *orig_base; + int absolute = 0; + + errno = 0; + /* Don't overflow the empty path by putting a '.' in it below. */ + if (*path == '\0') + return; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Convert all backslashes to slashes. */ - for (from = path; *from; from++) - if (*from == '\\') *from = '/'; - - /* Skip over leading drive letter if present. */ - if (ISALPHA (path[0]) && path[1] == ':') - from = to = &path[2]; - else - from = to = path; -#else + /* Convert all backslashes to slashes. */ + for (from = path; *from; from++) + if (*from == '\\') *from = '/'; + + /* Skip over leading drive letter if present. */ + if (ISALPHA (path[0]) && path[1] == ':') + from = to = &path[2]; + else from = to = path; +#else + from = to = path; #endif - - /* Remove redundant initial /s. */ - if (*from == '/') + + /* Remove redundant leading /s. */ + if (*from == '/') { - absolute = 1; - to++; - from++; - if (*from == '/') + absolute = 1; + to++; + from++; + if (*from == '/') { - if (*++from == '/') - /* 3 or more initial /s are equivalent to 1 /. */ - while (*++from == '/'); - else - /* On some hosts // differs from /; Posix allows this. */ - to++; + if (*++from == '/') + /* 3 or more initial /s are equivalent to 1 /. */ + while (*++from == '/'); + else + /* On some hosts // differs from /; Posix allows this. */ + to++; } } - base = to; - - for (;;) + + base = orig_base = to; + for (;;) { - while (*from == '/') - from++; - - if (from[0] == '.' && from[1] == '/') - from += 2; - else if (from[0] == '.' && from[1] == '\0') - goto done; - else if (from[0] == '.' && from[1] == '.' && from[2] == '/') + int move_base = 0; + + while (*from == '/') + from++; + + if (*from == '\0') + break; + + if (*from == '.') { - if (base == to) + if (from[1] == '\0') + break; + if (from[1] == '/') { - if (absolute) - from += 3; - else - { - *to++ = *from++; - *to++ = *from++; - *to++ = *from++; - base = to; - } - } - else - { - to -= 2; - while (to > base && *to != '/') to--; - if (*to == '/') - to++; - from += 3; + from += 2; + continue; } - } - else if (from[0] == '.' && from[1] == '.' && from[2] == '\0') - { - if (base == to) + else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0')) { - if (!absolute) + /* Don't simplify if there was no previous component. */ + if (absolute && orig_base == to) { - *to++ = *from++; - *to++ = *from++; + from += 2; + continue; } - } - else - { - to -= 2; - while (to > base && *to != '/') to--; - if (*to == '/') - to++; - } - goto done; - } - else - /* Copy this component and trailing /, if any. */ - while ((*to++ = *from++) != '/') - { - if (!to[-1]) + /* Don't simplify if the previous component was "../", + or if an error has already occurred with (l)stat. */ + if (base != to && errno == 0) { - to--; - goto done; + /* We don't back up if it's a symlink. */ + *to = '\0'; + if (remove_component_p (path)) + { + while (to > base && *to != '/') + to--; + from += 2; + continue; + } } + move_base = 1; } - + } + + /* Add the component separator. */ + if (to > orig_base) + *to++ = '/'; + + /* Copy this component until the trailing null or '/'. */ + while (*from != '\0' && *from != '/') + *to++ = *from++; + + if (move_base) + base = to; } - - done: - /* Trim trailing slash */ - if (to[0] == '/' && (!absolute || to > path+1)) - to--; - - /* Change the empty string to "." so that stat() on the result - will always work. */ - if (to == path) - *to++ = '.'; - - *to = '\0'; - return; + /* Change the empty string to "." so that it is not treated as stdin. + Null terminate. */ + if (to == path) + *to++ = '.'; + *to = '\0'; +#else /* VMS */ + errno = 0; +#endif /* !VMS */ }