X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libcpp%2Ffiles.c;h=be39db9a94cee0ebe6bc10c29935e728f8b3d0de;hb=0fa4671b1780250386599f246b5a002fadf63a62;hp=cd8d077ef71f294ba5bdc1be7cc18ae82b734f82;hpb=dcb9d064d04f71f5740017573872ad9a6589f250;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libcpp/files.c b/libcpp/files.c index cd8d077ef71..be39db9a94c 100644 --- a/libcpp/files.c +++ b/libcpp/files.c @@ -1,6 +1,7 @@ /* Part of CPP library. File handling. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 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 @@ -9,7 +10,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any +Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -18,14 +19,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +along with this program; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" #include "cpplib.h" #include "internal.h" #include "mkdeps.h" +#include "obstack.h" #include "hashtab.h" #include "md5.h" #include @@ -40,6 +42,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #endif #ifdef __DJGPP__ +#include /* For DJGPP redirected input is opened in text mode. */ # define set_stdin_to_binary_mode() \ if (! isatty (0)) setmode (0, O_BINARY) @@ -71,6 +74,10 @@ struct _cpp_file /* The contents of NAME after calling read_file(). */ const uchar *buffer; + /* Pointer to the real start of BUFFER. read_file() might increment + BUFFER; when freeing, this this pointer must be used instead. */ + const uchar *buffer_start; + /* The macro, if any, preventing re-inclusion. */ const cpp_hashnode *cmacro; @@ -103,9 +110,6 @@ struct _cpp_file /* If BUFFER above contains the true contents of the file. */ bool buffer_valid; - - /* File is a PCH (on return from find_include_file). */ - bool pch; }; /* A singly-linked list for all searches for a given file name, with @@ -139,6 +143,7 @@ struct file_hash_entry { struct file_hash_entry *next; cpp_dir *start_dir; + source_location location; union { _cpp_file *file; @@ -146,6 +151,21 @@ struct file_hash_entry } u; }; +/* Number of entries to put in a file_hash_entry pool. */ +#define FILE_HASH_POOL_SIZE 127 + +/* A file hash entry pool. We allocate file_hash_entry object from + one of these. */ +struct file_hash_entry_pool +{ + /* Number of entries used from this pool. */ + unsigned int file_hash_entries_used; + /* Next pool in the chain; used when freeing. */ + struct file_hash_entry_pool *next; + /* The memory pool. */ + struct file_hash_entry pool[FILE_HASH_POOL_SIZE]; +}; + static bool open_file (_cpp_file *file); static bool pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch); @@ -157,10 +177,11 @@ static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import); static struct cpp_dir *search_path_head (cpp_reader *, const char *fname, int angle_brackets, enum include_type); static const char *dir_name_of_file (_cpp_file *file); -static void open_file_failed (cpp_reader *pfile, _cpp_file *file); +static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int); static struct file_hash_entry *search_cache (struct file_hash_entry *head, const cpp_dir *start_dir); static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname); +static void destroy_cpp_file (_cpp_file *); static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp); static void allocate_file_hash_entries (cpp_reader *pfile); static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile); @@ -172,7 +193,6 @@ static void read_name_map (cpp_dir *dir); static char *remap_filename (cpp_reader *pfile, _cpp_file *file); static char *append_file_to_dir (const char *fname, cpp_dir *dir); static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname); -static int pchf_adder (void **slot, void *data); static int pchf_save_compare (const void *e1, const void *e2); static int pchf_compare (const void *d_p, const void *e_p); static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool); @@ -225,6 +245,22 @@ open_file (_cpp_file *file) close (file->fd); file->fd = -1; } +#if defined(_WIN32) && !defined(__CYGWIN__) + else if (errno == EACCES) + { + /* On most UNIX systems, open succeeds on a directory. Above, + we check if we have opened a directory and if so, set errno + to ENOENT. However, on Windows, opening a directory + fails with EACCES. We want to return ENOENT in that + case too. */ + if (stat (file->path, &file->st) == 0 + && S_ISDIR (file->st.st_mode)) + errno = ENOENT; + else + /* The call to stat may have reset errno. */ + errno = EACCES; + } +#endif else if (errno == ENOTDIR) errno = ENOENT; @@ -252,9 +288,15 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) if (file->name[0] == '\0' || !pfile->cb.valid_pch) return false; + /* If the file is not included as first include from either the toplevel + file or the command-line it is not a valid use of PCH. */ + if (pfile->all_files + && pfile->all_files->next_file) + return false; + flen = strlen (path); len = flen + sizeof (extension); - pchname = xmalloc (len); + pchname = XNEWVEC (char, len); memcpy (pchname, path, flen); memcpy (pchname + flen, extension, sizeof (extension)); @@ -278,7 +320,7 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) if (dlen + plen > len) { len += dlen + 64; - pchname = xrealloc (pchname, len); + pchname = XRESIZEVEC (char, pchname, len); } memcpy (pchname + plen, d->d_name, dlen); valid = validate_pch (pfile, file, pchname); @@ -287,9 +329,7 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) } closedir (pchdir); } - if (valid) - file->pch = true; - else + if (!valid) *invalid_pch = true; } @@ -321,6 +361,16 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) if (path) { + hashval_t hv = htab_hash_string (path); + char *copy; + void **pp; + + if (htab_find_with_hash (pfile->nonexistent_file_hash, path, hv) != NULL) + { + file->err_no = ENOENT; + return false; + } + file->path = path; if (pch_open_file (pfile, file, invalid_pch)) return true; @@ -330,11 +380,20 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) if (file->err_no != ENOENT) { - open_file_failed (pfile, file); + open_file_failed (pfile, file, 0); return true; } + /* We copy the path name onto an obstack partly so that we don't + leak the memory, but mostly so that we don't fragment the + heap. */ + copy = (char *) obstack_copy0 (&pfile->nonexistent_file_ob, path, + strlen (path)); free (path); + pp = htab_find_slot_with_hash (pfile->nonexistent_file_hash, + copy, hv, INSERT); + *pp = copy; + file->path = file->name; } else @@ -390,11 +449,14 @@ _cpp_find_failed (_cpp_file *file) to open_file(). */ _cpp_file * -_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake) +_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake, int angle_brackets) { struct file_hash_entry *entry, **hash_slot; _cpp_file *file; bool invalid_pch = false; + bool saw_bracket_include = false; + bool saw_quote_include = false; + struct cpp_dir *found_in_cache = NULL; /* Ensure we get no confusion between cached files and directories. */ if (start_dir == NULL) @@ -415,21 +477,6 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f /* Try each path in the include chain. */ for (; !fake ;) { - if (file->dir == pfile->quote_include - || file->dir == pfile->bracket_include) - { - entry = search_cache (*hash_slot, file->dir); - if (entry) - { - /* Found the same file again. Record it as reachable - from this position, too. */ - free ((char *) file->name); - free (file); - file = entry->u.file; - goto found; - } - } - if (find_file_in_dir (pfile, file, &invalid_pch)) break; @@ -437,9 +484,16 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f if (file->dir == NULL) { if (search_path_exhausted (pfile, fname, file)) - return file; + { + /* Although this file must not go in the cache, because + the file found might depend on things (like the current file) + that aren't represented in the cache, it still has to go in + the list of all files so that #import works. */ + file->next_file = pfile->all_files; + pfile->all_files = file; + return file; + } - open_file_failed (pfile, file); if (invalid_pch) { cpp_error (pfile, CPP_DL_ERROR, @@ -448,49 +502,75 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f cpp_error (pfile, CPP_DL_ERROR, "use -Winvalid-pch for more information"); } + open_file_failed (pfile, file, angle_brackets); break; } - } - - /* This is a new file; put it in the list. */ - file->next_file = pfile->all_files; - pfile->all_files = file; - /* If this file was found in the directory-of-the-current-file, - check whether that directory is reachable via one of the normal - search paths. If so, we must record this entry as being - reachable that way, otherwise we will mistakenly reprocess this - file if it is included later from the normal search path. */ - if (file->dir && start_dir->next == pfile->quote_include) - { - cpp_dir *d; - cpp_dir *proper_start_dir = pfile->quote_include; + /* Only check the cache for the starting location (done above) + and the quote and bracket chain heads because there are no + other possible starting points for searches. */ + if (file->dir == pfile->bracket_include) + saw_bracket_include = true; + else if (file->dir == pfile->quote_include) + saw_quote_include = true; + else + continue; - for (d = proper_start_dir;; d = d->next) + entry = search_cache (*hash_slot, file->dir); + if (entry) { - if (d == pfile->bracket_include) - proper_start_dir = d; - if (d == 0) - { - proper_start_dir = 0; - break; - } - /* file->dir->name will have a trailing slash. */ - if (!strncmp (d->name, file->dir->name, file->dir->len - 1)) - break; + found_in_cache = file->dir; + break; } - if (proper_start_dir) - start_dir = proper_start_dir; } - found: + if (entry) + { + /* Cache for START_DIR too, sharing the _cpp_file structure. */ + free ((char *) file->name); + free (file); + file = entry->u.file; + } + else + { + /* This is a new file; put it in the list. */ + file->next_file = pfile->all_files; + pfile->all_files = file; + } + /* Store this new result in the hash table. */ entry = new_file_hash_entry (pfile); entry->next = *hash_slot; entry->start_dir = start_dir; + entry->location = pfile->line_table->highest_location; entry->u.file = file; *hash_slot = entry; + /* If we passed the quote or bracket chain heads, cache them also. + This speeds up processing if there are lots of -I options. */ + if (saw_bracket_include + && pfile->bracket_include != start_dir + && found_in_cache != pfile->bracket_include) + { + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = pfile->bracket_include; + entry->location = pfile->line_table->highest_location; + entry->u.file = file; + *hash_slot = entry; + } + if (saw_quote_include + && pfile->quote_include != start_dir + && found_in_cache != pfile->quote_include) + { + entry = new_file_hash_entry (pfile); + entry->next = *hash_slot; + entry->start_dir = pfile->quote_include; + entry->location = pfile->line_table->highest_location; + entry->u.file = file; + *hash_slot = entry; + } + return file; } @@ -540,7 +620,7 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file) the majority of C source files. */ size = 8 * 1024; - buf = xmalloc (size + 1); + buf = XNEWVEC (uchar, size + 1); total = 0; while ((count = read (file->fd, buf + total, size - total)) > 0) { @@ -551,7 +631,7 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file) if (regular) break; size *= 2; - buf = xrealloc (buf, size + 1); + buf = XRESIZEVEC (uchar, buf, size + 1); } } @@ -565,8 +645,11 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file) cpp_error (pfile, CPP_DL_WARNING, "%s is shorter than expected", file->path); - file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset), - buf, size, total, &file->st.st_size); + file->buffer = _cpp_convert_input (pfile, + CPP_OPTION (pfile, input_charset), + buf, size, total, + &file->buffer_start, + &file->st.st_size); file->buffer_valid = true; return true; @@ -588,7 +671,7 @@ read_file (cpp_reader *pfile, _cpp_file *file) if (file->fd == -1 && !open_file (file)) { - open_file_failed (pfile, file); + open_file_failed (pfile, file, 0); return false; } @@ -628,11 +711,12 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) return false; /* Handle PCH files immediately; don't stack them. */ - if (file->pch) + if (file->pchname) { pfile->cb.read_pch (pfile, file->pchname, file->fd, file->path); - close (file->fd); file->fd = -1; + free ((void *) file->pchname); + file->pchname = NULL; return false; } @@ -667,12 +751,38 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) if ((import || f->once_only) && f->err_no == 0 && f->st.st_mtime == file->st.st_mtime - && f->st.st_size == file->st.st_size - && read_file (pfile, f) - /* Size might have changed in read_file(). */ - && f->st.st_size == file->st.st_size - && !memcmp (f->buffer, file->buffer, f->st.st_size)) - break; + && f->st.st_size == file->st.st_size) + { + _cpp_file *ref_file; + bool same_file_p = false; + + if (f->buffer && !f->buffer_valid) + { + /* We already have a buffer but it is not valid, because + the file is still stacked. Make a new one. */ + ref_file = make_cpp_file (pfile, f->dir, f->name); + ref_file->path = f->path; + } + else + /* The file is not stacked anymore. We can reuse it. */ + ref_file = f; + + same_file_p = read_file (pfile, ref_file) + /* Size might have changed in read_file(). */ + && ref_file->st.st_size == file->st.st_size + && !memcmp (ref_file->buffer, + file->buffer, + file->st.st_size); + + if (f->buffer && !f->buffer_valid) + { + ref_file->path = 0; + destroy_cpp_file (ref_file); + } + + if (same_file_p) + break; + } } return f == NULL; @@ -709,7 +819,8 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) /* Stack the buffer. */ buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size, - CPP_OPTION (pfile, preprocessed)); + CPP_OPTION (pfile, preprocessed) + && !CPP_OPTION (pfile, directives_only)); buffer->file = file; buffer->sysp = sysp; @@ -750,7 +861,8 @@ search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets, /* 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 && file->dir) + if (type == IT_INCLUDE_NEXT && file->dir + && file->dir != &pfile->no_search_path) dir = file->dir->next; else if (angle_brackets) dir = pfile->bracket_include; @@ -780,7 +892,7 @@ dir_name_of_file (_cpp_file *file) if (!file->dir_name) { size_t len = lbasename (file->path) - file->path; - char *dir_name = xmalloc (len + 1); + char *dir_name = XNEWVEC (char, len + 1); memcpy (dir_name, file->path, len); dir_name[len] = '\0'; @@ -804,16 +916,17 @@ _cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets, if (!dir) return false; - file = _cpp_find_file (pfile, fname, dir, false); - - /* Compensate for the increment in linemap_add. In the case of a - normal #include, we're currently at the start of the line - *following* the #include. A separate source_location for this - location makes no sense (until we do the LC_LEAVE), and - complicates LAST_SOURCE_LINE_LOCATION. This does not apply if we - found a PCH file (in which case linemap_add is not called) or we - were included from the command-line. */ - if (! file->pch && file->err_no == 0 && type != IT_CMDLINE) + file = _cpp_find_file (pfile, fname, dir, false, angle_brackets); + + /* Compensate for the increment in linemap_add that occurs in + _cpp_stack_file. In the case of a normal #include, we're + currently at the start of the line *following* the #include. A + separate source_location for this location makes no sense (until + we do the LC_LEAVE), and complicates LAST_SOURCE_LINE_LOCATION. + This does not apply if we found a PCH file (in which case + linemap_add is not called) or we were included from the + command-line. */ + if (file->pchname == NULL && file->err_no == 0 && type != IT_CMDLINE) pfile->line_table->highest_location--; return _cpp_stack_file (pfile, file, type == IT_IMPORT); @@ -821,22 +934,35 @@ _cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets, /* Could not open FILE. The complication is dependency output. */ static void -open_file_failed (cpp_reader *pfile, _cpp_file *file) +open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets) { int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0; - bool print_dep = CPP_OPTION (pfile, deps.style) > !!sysp; + bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp); errno = file->err_no; if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT) - deps_add_dep (pfile->deps, file->name); + { + deps_add_dep (pfile->deps, file->name); + /* If the preprocessor output (other than dependency information) is + being used, we must also flag an error. */ + if (CPP_OPTION (pfile, deps.need_preprocessor_output)) + cpp_errno (pfile, CPP_DL_FATAL, file->path); + } else { - /* If we are outputting dependencies but not for this file then - don't error because we can still produce correct output. */ - if (CPP_OPTION (pfile, deps.style) && ! print_dep) - cpp_errno (pfile, CPP_DL_WARNING, file->path); + /* If we are not outputting dependencies, or if we are and dependencies + were requested for this file, or if preprocessor output is needed + in addition to dependency information, this is an error. + + Otherwise (outputting dependencies but not for this file, and not + using the preprocessor output), we can still produce correct output + so it's only a warning. */ + if (CPP_OPTION (pfile, deps.style) == DEPS_NONE + || print_dep + || CPP_OPTION (pfile, deps.need_preprocessor_output)) + cpp_errno (pfile, CPP_DL_FATAL, file->path); else - cpp_errno (pfile, CPP_DL_ERROR, file->path); + cpp_errno (pfile, CPP_DL_WARNING, file->path); } } @@ -845,14 +971,10 @@ open_file_failed (cpp_reader *pfile, _cpp_file *file) static struct file_hash_entry * search_cache (struct file_hash_entry *head, const cpp_dir *start_dir) { - struct file_hash_entry *p; - - /* Look for a file that was found from a search starting at the - given location. */ - for (p = head; p; p = p->next) - if (p->start_dir == start_dir) - return p; - return 0; + while (head && head->start_dir != start_dir) + head = head->next; + + return head; } /* Allocate a new _cpp_file structure. */ @@ -861,7 +983,7 @@ make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname) { _cpp_file *file; - file = xcalloc (1, sizeof (_cpp_file)); + file = XCNEW (_cpp_file); file->main_file = !pfile->buffer; file->fd = -1; file->dir = dir; @@ -870,6 +992,29 @@ make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname) return file; } +/* Release a _cpp_file structure. */ +static void +destroy_cpp_file (_cpp_file *file) +{ + if (file->buffer_start) + free ((void *) file->buffer_start); + free ((void *) file->name); + free (file); +} + +/* Release all the files allocated by this reader. */ +static void +destroy_all_cpp_files (cpp_reader *pfile) +{ + _cpp_file *iter = pfile->all_files; + while (iter) + { + _cpp_file *next = iter->next_file; + destroy_cpp_file (iter); + iter = next; + } +} + /* A hash of directory names. The directory names are the path names of files which contain a #include "", the included file name is appended to this directories. @@ -884,7 +1029,7 @@ make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) cpp_dir *dir; hash_slot = (struct file_hash_entry **) - htab_find_slot_with_hash (pfile->file_hash, dir_name, + htab_find_slot_with_hash (pfile->dir_hash, dir_name, htab_hash_string (dir_name), INSERT); @@ -893,7 +1038,7 @@ make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) if (entry->start_dir == NULL) return entry->u.dir; - dir = xcalloc (1, sizeof (cpp_dir)); + dir = XCNEW (cpp_dir); dir->next = pfile->quote_include; dir->name = (char *) dir_name; dir->len = strlen (dir_name); @@ -904,6 +1049,7 @@ make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) entry = new_file_hash_entry (pfile); entry->next = *hash_slot; entry->start_dir = NULL; + entry->location = pfile->line_table->highest_location; entry->u.dir = dir; *hash_slot = entry; @@ -914,20 +1060,35 @@ make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) static void allocate_file_hash_entries (cpp_reader *pfile) { - pfile->file_hash_entries_used = 0; - pfile->file_hash_entries_allocated = 127; - pfile->file_hash_entries = xmalloc - (pfile->file_hash_entries_allocated * sizeof (struct file_hash_entry)); + struct file_hash_entry_pool *pool = XNEW (struct file_hash_entry_pool); + pool->file_hash_entries_used = 0; + pool->next = pfile->file_hash_entries; + pfile->file_hash_entries = pool; } /* Return a new file hash entry. */ static struct file_hash_entry * new_file_hash_entry (cpp_reader *pfile) { - if (pfile->file_hash_entries_used == pfile->file_hash_entries_allocated) + unsigned int idx; + if (pfile->file_hash_entries->file_hash_entries_used == FILE_HASH_POOL_SIZE) allocate_file_hash_entries (pfile); - return &pfile->file_hash_entries[pfile->file_hash_entries_used++]; + idx = pfile->file_hash_entries->file_hash_entries_used++; + return &pfile->file_hash_entries->pool[idx]; +} + +/* Free the file hash entry pools. */ +static void +free_file_hash_entries (cpp_reader *pfile) +{ + struct file_hash_entry_pool *iter = pfile->file_hash_entries; + while (iter) + { + struct file_hash_entry_pool *next = iter->next; + free (iter); + iter = next; + } } /* Returns TRUE if a file FNAME has ever been successfully opened. @@ -938,8 +1099,8 @@ cpp_included (cpp_reader *pfile, const char *fname) { struct file_hash_entry *entry; - entry = htab_find_with_hash (pfile->file_hash, fname, - htab_hash_string (fname)); + entry = (struct file_hash_entry *) + htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname)); while (entry && (entry->start_dir == NULL || entry->u.file->err_no)) entry = entry->next; @@ -947,6 +1108,25 @@ cpp_included (cpp_reader *pfile, const char *fname) return entry != NULL; } +/* Returns TRUE if a file FNAME has ever been successfully opened + before LOCATION. This routine is not intended to correctly handle + filenames aliased by links or redundant . or .. traversals etc. */ +bool +cpp_included_before (cpp_reader *pfile, const char *fname, + source_location location) +{ + struct file_hash_entry *entry; + + entry = (struct file_hash_entry *) + htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname)); + + while (entry && (entry->start_dir == NULL || entry->u.file->err_no + || entry->location > location)) + entry = entry->next; + + return entry != NULL; +} + /* Calculate the hash value of a file hash entry P. */ static hashval_t @@ -978,13 +1158,29 @@ file_hash_eq (const void *p, const void *q) return strcmp (hname, fname) == 0; } +/* Compare entries in the nonexistent file hash table. These are just + strings. */ +static int +nonexistent_file_hash_eq (const void *p, const void *q) +{ + return strcmp ((const char *) p, (const char *) q) == 0; +} + /* Initialize everything in this source file. */ void _cpp_init_files (cpp_reader *pfile) { pfile->file_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, NULL, xcalloc, free); + pfile->dir_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq, + NULL, xcalloc, free); allocate_file_hash_entries (pfile); + pfile->nonexistent_file_hash = htab_create_alloc (127, htab_hash_string, + nonexistent_file_hash_eq, + NULL, xcalloc, free); + _obstack_begin (&pfile->nonexistent_file_ob, 0, 0, + (void *(*) (long)) xmalloc, + (void (*) (void *)) free); } /* Finalize everything in this source file. */ @@ -992,13 +1188,29 @@ void _cpp_cleanup_files (cpp_reader *pfile) { htab_delete (pfile->file_hash); + htab_delete (pfile->dir_hash); + htab_delete (pfile->nonexistent_file_hash); + obstack_free (&pfile->nonexistent_file_ob, 0); + free_file_hash_entries (pfile); + destroy_all_cpp_files (pfile); +} + +/* Make the parser forget about files it has seen. This can be useful + for resetting the parser to start another run. */ +void +cpp_clear_file_cache (cpp_reader *pfile) +{ + _cpp_cleanup_files (pfile); + pfile->file_hash_entries = NULL; + pfile->all_files = NULL; + _cpp_init_files (pfile); } /* Enter a file name in the hash for the sake of cpp_included. */ void _cpp_fake_include (cpp_reader *pfile, const char *fname) { - _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true); + _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0); } /* Not everyone who wants to set system-header-ness on a buffer can @@ -1029,12 +1241,19 @@ cpp_change_file (cpp_reader *pfile, enum lc_reason reason, _cpp_do_file_change (pfile, reason, new_name, 1, 0); } +struct report_missing_guard_data +{ + const char **paths; + size_t count; +}; + /* Callback function for htab_traverse. */ static int -report_missing_guard (void **slot, void *b) +report_missing_guard (void **slot, void *d) { struct file_hash_entry *entry = (struct file_hash_entry *) *slot; - int *bannerp = (int *) b; + struct report_missing_guard_data *data + = (struct report_missing_guard_data *) d; /* Skip directories. */ if (entry->start_dir != NULL) @@ -1042,21 +1261,28 @@ report_missing_guard (void **slot, void *b) _cpp_file *file = entry->u.file; /* We don't want MI guard advice for the main file. */ - if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file) + if (!file->once_only && file->cmacro == NULL + && file->stack_count == 1 && !file->main_file) { - if (*bannerp == 0) + if (data->paths == NULL) { - fputs (_("Multiple include guards may be useful for:\n"), - stderr); - *bannerp = 1; + data->paths = XCNEWVEC (const char *, data->count); + data->count = 0; } - fputs (entry->u.file->path, stderr); - putc ('\n', stderr); + data->paths[data->count++] = file->path; } } - return 0; + /* Keep traversing the hash table. */ + return 1; +} + +/* Comparison function for qsort. */ +static int +report_missing_guard_cmp (const void *p1, const void *p2) +{ + return strcmp (*(const char *const *) p1, *(const char *const *) p2); } /* Report on all files that might benefit from a multiple include guard. @@ -1064,9 +1290,29 @@ report_missing_guard (void **slot, void *b) void _cpp_report_missing_guards (cpp_reader *pfile) { - int banner = 0; + struct report_missing_guard_data data; - htab_traverse (pfile->file_hash, report_missing_guard, &banner); + data.paths = NULL; + data.count = htab_elements (pfile->file_hash); + htab_traverse (pfile->file_hash, report_missing_guard, &data); + + if (data.paths != NULL) + { + size_t i; + + /* Sort the paths to avoid outputting them in hash table + order. */ + qsort (data.paths, data.count, sizeof (const char *), + report_missing_guard_cmp); + fputs (_("Multiple include guards may be useful for:\n"), + stderr); + for (i = 0; i < data.count; i++) + { + fputs (data.paths[i], stderr); + putc ('\n', stderr); + } + free (data.paths); + } } /* Locate HEADER, and determine whether it is newer than the current @@ -1083,7 +1329,7 @@ _cpp_compare_file_date (cpp_reader *pfile, const char *fname, if (!dir) return -1; - file = _cpp_find_file (pfile, fname, dir, false); + file = _cpp_find_file (pfile, fname, dir, false, angle_brackets); if (file->err_no) return -1; @@ -1117,13 +1363,22 @@ _cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file) /* Invalidate control macros in the #including file. */ pfile->mi_valid = false; - if (file->buffer) + if (file->buffer_start) { - free ((void *) file->buffer); + free ((void *) file->buffer_start); + file->buffer_start = NULL; file->buffer = NULL; + file->buffer_valid = false; } } +/* Inteface to file statistics record in _cpp_file structure. */ +struct stat * +_cpp_get_file_stat (_cpp_file *file) +{ + return &file->st; +} + /* 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. @@ -1156,7 +1411,7 @@ append_file_to_dir (const char *fname, cpp_dir *dir) dlen = dir->len; flen = strlen (fname); - path = xmalloc (dlen + 1 + flen + 1); + path = XNEWVEC (char, dlen + 1 + flen + 1); memcpy (path, dir->name, dlen); if (dlen && path[dlen - 1] != '/') path[dlen++] = '/'; @@ -1174,7 +1429,7 @@ read_filename_string (int ch, FILE *f) int len; len = 20; - set = alloc = xmalloc (len + 1); + set = alloc = XNEWVEC (char, len + 1); if (! is_space (ch)) { *set++ = ch; @@ -1183,7 +1438,7 @@ read_filename_string (int ch, FILE *f) if (set - alloc == len) { len *= 2; - alloc = xrealloc (alloc, len + 1); + alloc = XRESIZEVEC (char, alloc, len + 1); set = alloc + len / 2; } *set++ = ch; @@ -1204,14 +1459,14 @@ read_name_map (cpp_dir *dir) size_t len, count = 0, room = 9; len = dir->len; - name = alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1); + name = (char *) alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1); memcpy (name, dir->name, len); if (len && name[len - 1] != '/') name[len++] = '/'; strcpy (name + len, FILE_NAME_MAP_FILE); f = fopen (name, "r"); - dir->name_map = xmalloc (room * sizeof (char *)); + dir->name_map = XNEWVEC (const char *, room); /* Silently return NULL if we cannot open. */ if (f) @@ -1228,7 +1483,7 @@ read_name_map (cpp_dir *dir) if (count + 2 > room) { room += 8; - dir->name_map = xrealloc (dir->name_map, room * sizeof (char *)); + dir->name_map = XRESIZEVEC (const char *, dir->name_map, room); } dir->name_map[count] = read_filename_string (ch, f); @@ -1285,7 +1540,7 @@ remap_filename (cpp_reader *pfile, _cpp_file *file) return NULL; len = dir->len + (p - fname + 1); - new_dir = xmalloc (len + 1); + new_dir = XNEWVEC (char, len + 1); memcpy (new_dir, dir->name, dir->len); memcpy (new_dir + dir->len, fname, p - fname + 1); new_dir[len] = '\0'; @@ -1378,6 +1633,16 @@ cpp_get_prev (cpp_buffer *b) that's OK. The code does rely on having entries with the same size next to each other. */ +struct pchf_entry { + /* The size of this file. This is used to save running a MD5 checksum + if the sizes don't match. */ + off_t size; + /* The MD5 checksum of this file. */ + unsigned char sum[16]; + /* Is this file to be included only once? */ + bool once_only; +}; + struct pchf_data { /* Number of pchf_entry structures. */ size_t count; @@ -1387,51 +1652,59 @@ struct pchf_data { the structure if we're processing a regular #include. */ bool have_once_only; - struct pchf_entry { - /* The size of this file. This is used to save running a MD5 checksum - if the sizes don't match. */ - off_t size; - /* The MD5 checksum of this file. */ - unsigned char sum[16]; - /* Is this file to be included only once? */ - bool once_only; - } entries[1]; + struct pchf_entry entries[1]; }; static struct pchf_data *pchf; -/* Data for pchf_addr. */ -struct pchf_adder_info +/* A qsort ordering function for pchf_entry structures. */ + +static int +pchf_save_compare (const void *e1, const void *e2) { - cpp_reader *pfile; - struct pchf_data *d; -}; + return memcmp (e1, e2, sizeof (struct pchf_entry)); +} -/* A hash traversal function to add entries into DATA->D. */ +/* Create and write to F a pchf_data structure. */ -static int -pchf_adder (void **slot, void *data) +bool +_cpp_save_file_entries (cpp_reader *pfile, FILE *fp) { - struct file_hash_entry *h = (struct file_hash_entry *) *slot; - struct pchf_adder_info *i = (struct pchf_adder_info *) data; + size_t count = 0; + struct pchf_data *result; + size_t result_size; + _cpp_file *f; + + for (f = pfile->all_files; f; f = f->next_file) + ++count; + + result_size = (sizeof (struct pchf_data) + + sizeof (struct pchf_entry) * (count - 1)); + result = XCNEWVAR (struct pchf_data, result_size); - if (h->start_dir != NULL && h->u.file->stack_count != 0) + result->count = 0; + result->have_once_only = false; + + for (f = pfile->all_files; f; f = f->next_file) { - struct pchf_data *d = i->d; - _cpp_file *f = h->u.file; - size_t count = d->count++; + size_t count; /* This should probably never happen, since if a read error occurred the PCH file shouldn't be written... */ if (f->dont_read || f->err_no) - return 1; + continue; - d->entries[count].once_only = f->once_only; + if (f->stack_count == 0) + continue; + + count = result->count++; + + result->entries[count].once_only = f->once_only; /* |= is avoided in the next line because of an HP C compiler bug */ - d->have_once_only = d->have_once_only | f->once_only; + result->have_once_only = result->have_once_only | f->once_only; if (f->buffer_valid) - md5_buffer ((const char *)f->buffer, - f->st.st_size, d->entries[count].sum); + md5_buffer ((const char *)f->buffer, + f->st.st_size, result->entries[count].sum); else { FILE *ff; @@ -1439,48 +1712,16 @@ pchf_adder (void **slot, void *data) if (!open_file (f)) { - open_file_failed (i->pfile, f); - return 0; + open_file_failed (pfile, f, 0); + return false; } ff = fdopen (f->fd, "rb"); - md5_stream (ff, d->entries[count].sum); + md5_stream (ff, result->entries[count].sum); fclose (ff); f->fd = oldfd; } - d->entries[count].size = f->st.st_size; + result->entries[count].size = f->st.st_size; } - return 1; -} - -/* A qsort ordering function for pchf_entry structures. */ - -static int -pchf_save_compare (const void *e1, const void *e2) -{ - return memcmp (e1, e2, sizeof (struct pchf_entry)); -} - -/* Create and write to F a pchf_data structure. */ - -bool -_cpp_save_file_entries (cpp_reader *pfile, FILE *f) -{ - size_t count = 0; - struct pchf_data *result; - size_t result_size; - struct pchf_adder_info pai; - - count = htab_elements (pfile->file_hash); - result_size = (sizeof (struct pchf_data) - + sizeof (struct pchf_entry) * (count - 1)); - result = xcalloc (result_size, 1); - - result->count = 0; - result->have_once_only = false; - - pai.pfile = pfile; - pai.d = result; - htab_traverse (pfile->file_hash, pchf_adder, &pai); result_size = (sizeof (struct pchf_data) + sizeof (struct pchf_entry) * (result->count - 1)); @@ -1488,7 +1729,7 @@ _cpp_save_file_entries (cpp_reader *pfile, FILE *f) qsort (result->entries, result->count, sizeof (struct pchf_entry), pchf_save_compare); - return fwrite (result, result_size, 1, f) == 1; + return fwrite (result, result_size, 1, fp) == 1; } /* Read the pchf_data structure from F. */ @@ -1502,7 +1743,7 @@ _cpp_read_file_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, FILE *f) != 1) return false; - pchf = xmalloc (sizeof (struct pchf_data) + pchf = XNEWVAR (struct pchf_data, sizeof (struct pchf_data) + sizeof (struct pchf_entry) * (d.count - 1)); memcpy (pchf, &d, sizeof (struct pchf_data) - sizeof (struct pchf_entry)); if (fread (pchf->entries, sizeof (struct pchf_entry), d.count, f)