X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcppfiles.c;h=892583e2329df3022ad453f8ae8f82f1213f6769;hb=6ff922f90a7927d17c494884947931ddc0d49564;hp=72af4333531e87b82f2e779e77797543df13563d;hpb=3ec84a0b0aef46187209d9d69ecb389c487cc2a3;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 72af4333531..892583e2329 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 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 @@ -33,6 +33,26 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # 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 @@ -43,10 +63,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define O_BINARY 0 #endif -#ifndef INCLUDE_LEN_FUDGE -# define INCLUDE_LEN_FUDGE 0 -#endif - /* If errno is inspected immediately after a system call fails, it will be nonzero, and no error number will ever be zero. */ #ifndef ENOENT @@ -55,9 +71,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ENOTDIR # define ENOTDIR 0 #endif -#ifndef ENOMEM -# define ENOMEM 0 -#endif /* Suppress warning about function macros used w/o arguments in traditional C. It is unlikely that glibc's strcmp macro helps this file at all. */ @@ -74,21 +87,30 @@ struct include_file 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 */ }; +/* 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. */ + 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) static struct file_name_map *read_name_map PARAMS ((cpp_reader *, const char *)); @@ -96,35 +118,33 @@ 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 *)); + 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 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_include_file_node PARAMS ((splay_tree_value)); +static void destroy_node PARAMS ((splay_tree_value)); static int report_missing_guard PARAMS ((splay_tree_node, void *)); - -/* We use a splay tree to store information about all the include - files seen in this compilation. The key of each tree node is the - physical path to the file. The value is 0 if the file does not - exist, or a struct include_file pointer. */ - -static void -destroy_include_file_node (v) - splay_tree_value v; -{ - struct include_file *f = (struct include_file *)v; - - if (f) - { - purge_cache (f); - free (f); /* The tree is registered with free to free f->name. */ - } -} - +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 + file we tried to open but failed; this saves system calls since we + 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. + The path string has been malloced, as is automatically freed by + registering free () as the splay tree key deletion function. + + A node's value is a pointer to a struct include_file, and is never + NULL. */ void _cpp_init_includes (pfile) cpp_reader *pfile; @@ -132,9 +152,10 @@ _cpp_init_includes (pfile) pfile->all_include_files = splay_tree_new ((splay_tree_compare_fn) strcmp, (splay_tree_delete_key_fn) free, - destroy_include_file_node); + destroy_node); } +/* Tear down the splay tree. */ void _cpp_cleanup_includes (pfile) cpp_reader *pfile; @@ -142,6 +163,20 @@ _cpp_cleanup_includes (pfile) splay_tree_delete (pfile->all_include_files); } +/* Free a node. The path string is automatically freed. */ +static void +destroy_node (v) + splay_tree_value v; +{ + struct include_file *f = (struct include_file *)v; + + if (f) + { + purge_cache (f); + free (f); + } +} + /* Mark a file to not be reread (e.g. #import, read failure). */ void _cpp_never_reread (file) @@ -150,24 +185,42 @@ _cpp_never_reread (file) file->cmacro = NEVER_REREAD; } -/* Put a file name in the splay tree, for the sake of cpp_included (). - Assume that FNAME has already had its path simplified. */ -void -_cpp_fake_include (pfile, fname) +/* Lookup a filename, which is simplified after making a copy, and + create an entry if none exists. errno is nonzero iff a (reported) + stat() error occurred during simplification. */ +static splay_tree_node +find_or_create_entry (pfile, fname) cpp_reader *pfile; const char *fname; { - splay_tree_node nd; + splay_tree_node node; + struct include_file *file; + char *name = xstrdup (fname); - nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname); - if (! nd) + _cpp_simplify_pathname (name); + node = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name); + if (node) + free (name); + else { - struct include_file *file = xcnew (struct include_file); - file->name = xstrdup (fname); - splay_tree_insert (pfile->all_include_files, - (splay_tree_key) file->name, - (splay_tree_value) file); + file = xcnew (struct include_file); + file->name = name; + file->err_no = errno; + node = splay_tree_insert (pfile->all_include_files, + (splay_tree_key) file->name, + (splay_tree_value) file); } + + return node; +} + +/* Enter a file name in the splay tree, for the sake of cpp_included. */ +void +_cpp_fake_include (pfile, fname) + cpp_reader *pfile; + const char *fname; +{ + find_or_create_entry (pfile, fname); } /* Given a file name, look it up in the cache; if there is no entry, @@ -179,43 +232,29 @@ _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; const char *filename; { - splay_tree_node nd; - struct include_file *file; - - nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) filename); + splay_tree_node nd = find_or_create_entry (pfile, filename); + struct include_file *file = (struct include_file *) nd->value; - if (nd) + if (file->err_no) { - file = (struct include_file *) nd->value; - - /* Don't retry opening if we failed previously. */ - if (file->fd == -2) - return 0; - - /* Don't reopen an idempotent file. */ - if (DO_NOT_REREAD (file)) - return file; - - /* Don't reopen one which is already loaded. */ - if (file->buffer != NULL) - return file; - } - else - { - /* In particular, this clears foundhere. */ - file = xcnew (struct include_file); - file->name = xstrdup (filename); - splay_tree_insert (pfile->all_include_files, - (splay_tree_key) file->name, - (splay_tree_value) file); + /* Ugh. handle_missing_header () needs errno to be set. */ + errno = file->err_no; + return 0; } + /* Don't reopen an idempotent file. */ + if (DO_NOT_REREAD (file)) + return file; + + /* Don't reopen one which is already loaded. */ + if (file->buffer != NULL) + return file; + /* We used to open files in nonblocking mode, but that caused more problems than it solved. Do take care not to acquire a controlling terminal by mistake (this can't happen on sane @@ -231,82 +270,100 @@ 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; - } - - return file; + 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; } - /* 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; - + file->err_no = errno; return 0; } -/* 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. */ - -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); + } /* 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; + 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. @@ -314,30 +371,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, @@ -350,7 +403,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; @@ -360,17 +413,17 @@ 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; inc->mapped = 1; } else #endif { - buf = (U_CHAR *) xmalloc (size); + buf = (uchar *) xmalloc (size + 1); offset = 0; while (offset < size) { @@ -379,21 +432,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 @@ -403,37 +458,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; @@ -458,7 +514,7 @@ cpp_included (pfile, fname) const char *fname; { struct search_path *path; - char *name; + char *name, *n; splay_tree_node nd; if (IS_ABSOLUTE_PATHNAME (fname)) @@ -467,56 +523,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 + INCLUDE_LEN_FUDGE); + name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2); for (path = CPP_OPTION (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; { + const char *fname = (const char *) header->val.str.text; struct search_path *path; - char *name; struct include_file *file; + char *name, *n; if (IS_ABSOLUTE_PATHNAME (fname)) return open_file (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 = CPP_OPTION (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 + INCLUDE_LEN_FUDGE); - for (path = search_start; path; path = path->next) + name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2); + 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 (pfile, n); if (file) { file->foundhere = path; @@ -540,9 +620,8 @@ 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); } /* Report on all files that might benefit from a multiple include guard. @@ -556,6 +635,7 @@ _cpp_report_missing_guards (pfile) (PTR) &banner); } +/* Callback function for splay_tree_foreach(). */ static int report_missing_guard (n, b) splay_tree_node n; @@ -577,181 +657,83 @@ report_missing_guard (n, b) return 0; } -void -_cpp_execute_include (pfile, header, no_reinclude, include_next) +/* Create a dependency for file FNAME, or issue an error message as + appropriate. ANGLE_BRACKETS is non-zero if the file was bracketed + like <..>. */ +static void +handle_missing_header (pfile, fname, angle_brackets) cpp_reader *pfile; - const cpp_token *header; - int no_reinclude; - int include_next; + const char *fname; + int angle_brackets; { - struct search_path *search_start = 0; - unsigned int len = header->val.str.len; - unsigned int angle_brackets = header->type == CPP_HEADER_NAME; - struct include_file *inc; - char *fname; - int print_dep; - - /* Help protect #include or similar from recursion. */ - if (pfile->buffer_stack_depth >= CPP_STACK_MAX) - { - cpp_fatal (pfile, "#include nested too deeply"); - return; - } - - /* 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; - } - - /* 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; - } - } - } + 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_errno (pfile, CPP_OPTION (pfile, deps.style) && ! print_dep + ? DL_WARNING: DL_ERROR, fname); +} - fname = alloca (len + 1); - memcpy (fname, header->val.str.text, len); - fname[len] = '\0'; +/* 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; + enum include_type type; +{ + bool stacked = false; + struct include_file *inc = find_include_file (pfile, header, type); - if (!search_start) + if (inc == 0) + handle_missing_header (pfile, (const char *) header->val.str.text, + header->type == CPP_HEADER_NAME); + else if (inc != NO_INCLUDE_PATH) { - if (angle_brackets) - search_start = CPP_OPTION (pfile, bracket_include); - else - search_start = pfile->buffer->search_from; + stacked = stack_include_file (pfile, inc); - if (!search_start) - { - cpp_error (pfile, "No include path in which to find %s", fname); - return; - } + if (type == IT_IMPORT) + _cpp_never_reread (inc); } - 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 = CPP_BUFFER (pfile); - while ((fp = CPP_PREV_BUFFER (fp)) != NULL) - putc ('.', stderr); - fprintf (stderr, " %s\n", inc->name); - } - } - - return; - } - - /* We will try making the RHS pfile->buffer->sysp after 3.0. */ - 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 - { - char *p; - struct search_path *ptr; - int len; - - /* If requested as a system header, assume it belongs in - the first system header directory. */ - if (CPP_OPTION (pfile, bracket_include)) - ptr = CPP_OPTION (pfile, bracket_include); - else - ptr = CPP_OPTION (pfile, quote_include); - - /* FIXME: ptr can be null, no? */ - len = ptr->len; - p = (char *) alloca (len + strlen (fname) + 2); - if (len) - { - memcpy (p, ptr->name, len); - p[len++] = '/'; - } - strcpy (p + len, fname); - _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); - else - cpp_error_from_errno (pfile, fname); + 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; { - unsigned int len = f->val.str.len; - char *fname; - struct search_path *search_start; - struct include_file *inc; - - if (f->type == CPP_HEADER_NAME) - search_start = CPP_OPTION (pfile, bracket_include); - else if (CPP_OPTION (pfile, ignore_srcdir)) - search_start = pfile->buffer->search_from; - - fname = alloca (len + 1); - memcpy (fname, f->val.str.text, len); - fname[len] = '\0'; - inc = find_include_file (pfile, fname, search_start); - - if (!inc) + struct include_file *inc = find_include_file (pfile, header, 0); + + 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; @@ -760,38 +742,27 @@ _cpp_read_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. */ +/* Do appropriate cleanup when a file INC's buffer is popped off the + input stack. */ void -_cpp_pop_file_buffer (pfile, buf) +_cpp_pop_file_buffer (pfile, inc) cpp_reader *pfile; - cpp_buffer *buf; + struct include_file *inc; { - struct include_file *inc = buf->inc; - - if (pfile->system_include_depth) - pfile->system_include_depth--; - if (pfile->include_depth) - pfile->include_depth--; - - /* 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; - } + /* 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)) @@ -800,41 +771,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. */ + 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 search_path * -search_from (pfile, inc) +search_from (pfile, type) cpp_reader *pfile; - struct include_file *inc; + enum include_type type; { cpp_buffer *buffer = pfile->buffer; unsigned int dlen; + /* Command line uses the cwd, and does not cache the result. */ + if (type == IT_CMDLINE) + goto use_cwd; + /* Ignore the current file's directory if -I- was given. */ if (CPP_OPTION (pfile, ignore_srcdir)) return CPP_OPTION (pfile, quote_include); - dlen = basename (inc->name) - inc->name; - if (dlen) + if (! buffer->search_cached) { - /* 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 - { - buffer->dir.name = "."; - dlen = 1; - } + buffer->search_cached = 1; + + dlen = lbasename (buffer->inc->name) - buffer->inc->name; - if (dlen > pfile->max_include_len) - pfile->max_include_len = dlen; + if (dlen) + { + /* We don't guarantee NAME is null-terminated. This saves + allocating and freeing memory. Drop a trailing '/'. */ + buffer->dir.name = buffer->inc->name; + if (dlen > 1) + dlen--; + } + else + { + use_cwd: + buffer->dir.name = "."; + dlen = 1; + } + + if (dlen > pfile->max_include_len) + pfile->max_include_len = dlen; - buffer->dir.len = dlen; - buffer->dir.next = CPP_OPTION (pfile, quote_include); - buffer->dir.sysp = buffer->sysp; + buffer->dir.len = dlen; + buffer->dir.next = CPP_OPTION (pfile, quote_include); + buffer->dir.sysp = pfile->map->sysp; + } return &buffer->dir; } @@ -846,7 +830,6 @@ 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 *map_next; @@ -857,8 +840,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; @@ -889,7 +871,6 @@ 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 *map_list_next; @@ -898,13 +879,12 @@ struct file_name_map_list }; /* 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; @@ -932,7 +912,6 @@ read_name_map (pfile, dirname) if (f) { int ch; - int dirlen = strlen (dirname); while ((ch = getc (f)) != EOF) { @@ -955,12 +934,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; @@ -971,16 +947,16 @@ 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; @@ -989,23 +965,23 @@ remap_filename (pfile, name, 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; @@ -1020,13 +996,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; @@ -1034,6 +1010,32 @@ remap_filename (pfile, name, loc) return name; } +/* 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). @@ -1045,124 +1047,121 @@ 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. - */ -void + 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 (). */ +char * _cpp_simplify_pathname (path) - char *path; + char *path; { - 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 path; #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; - } + from += 2; + continue; } - else + else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0')) { - to -= 2; - while (to > base && *to != '/') to--; - if (*to == '/') - to++; - from += 3; - } - } - else if (from[0] == '.' && from[1] == '.' && from[2] == '\0') - { - if (base == to) - { - 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'; + + return path; +#else /* VMS */ + errno = 0; + return path; +#endif /* !VMS */ }