X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcppfiles.c;h=65db6db5d570f532f9ccd82a911a911ad17099ef;hp=c2d91f581d8962e66ad9611d74f0e8b4e94e7818;hb=d6c39c7a53f108fa9b43ccee34cd7dd78de2df39;hpb=aaf491c2b55c44fc41aeb42295de90caaed47571 diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index c2d91f581d8..65db6db5d57 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -1,6 +1,6 @@ /* Part of CPP library. File handling. Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 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 @@ -28,6 +28,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "intl.h" #include "mkdeps.h" #include "hashtab.h" +#include "md5.h" #include /* Variable length record files on VMS will have a stat size that includes @@ -108,11 +109,8 @@ struct _cpp_file /* If BUFFER above contains the true contents of the file. */ bool buffer_valid; - /* 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. */ - uchar pch; + /* 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 @@ -179,7 +177,10 @@ 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 bool include_pch_p (_cpp_file *file); +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); /* Given a filename in FILE->PATH, with the empty string interpreted as , open it. @@ -291,8 +292,10 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) } closedir (pchdir); } - file->pch |= valid; - *invalid_pch |= ! valid; + if (valid) + file->pch = true; + else + *invalid_pch = true; } if (valid) @@ -305,7 +308,7 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) /* Try to open the path FILE->name appended to FILE->dir. This is where remap and PCH intercept the file lookup process. Return true - if the file was found, whether or not the open was successful. + if the file was found, whether or not the open was successful. Set *INVALID_PCH to true if a PCH file is found but wasn't valid. */ static bool @@ -316,23 +319,58 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch) if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file))) ; else - path = append_file_to_dir (file->name, file->dir); + if (file->dir->construct) + path = file->dir->construct (file->name, file->dir); + else + path = append_file_to_dir (file->name, file->dir); - file->path = path; - if (pch_open_file (pfile, file, invalid_pch)) - return true; + if (path) + { + file->path = path; + if (pch_open_file (pfile, file, invalid_pch)) + return true; - if (open_file (file)) - return true; + if (open_file (file)) + return true; + + if (file->err_no != ENOENT) + { + open_file_failed (pfile, file); + return true; + } - if (file->err_no != ENOENT) + free (path); + file->path = file->name; + } + else { - open_file_failed (pfile, file); - return true; + file->err_no = ENOENT; + file->path = NULL; + } + + return false; +} + +/* Return tue iff the missing_header callback found the given HEADER. */ +static bool +search_path_exhausted (cpp_reader *pfile, const char *header, _cpp_file *file) +{ + missing_header_cb func = pfile->cb.missing_header; + + /* When the regular search path doesn't work, try context dependent + headers search paths. */ + if (func + && file->dir == NULL) + { + if ((file->path = func (pfile, header, &file->dir)) != NULL) + { + if (open_file (file)) + return true; + free ((void *)file->path); + } + file->path = file->name; } - free (path); - file->path = file->name; return false; } @@ -344,7 +382,7 @@ _cpp_find_failed (_cpp_file *file) /* Given a filename FNAME search for such a file in the include path starting from START_DIR. If FNAME is the empty string it is - interpreted as STDIN if START_DIR is PFILE->no_seach_path. + interpreted as STDIN if START_DIR is PFILE->no_search_path. If the file is not found in the file cache fall back to the O/S and add the result to our cache. @@ -388,13 +426,16 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool f file->dir = file->dir->next; if (file->dir == NULL) { + if (search_path_exhausted (pfile, fname, file)) + return file; + open_file_failed (pfile, file); if (invalid_pch) { - cpp_error (pfile, CPP_DL_ERROR, + cpp_error (pfile, CPP_DL_ERROR, "one or more PCH files were found, but they were invalid"); if (!cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_ERROR, + cpp_error (pfile, CPP_DL_ERROR, "use -Winvalid-pch for more information"); } break; @@ -450,7 +491,7 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file) ssize_t size, total, count; uchar *buf; bool regular; - + if (S_ISBLK (file->st.st_mode)) { cpp_error (pfile, CPP_DL_ERROR, "%s is a block device", file->path); @@ -507,15 +548,8 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file) cpp_error (pfile, CPP_DL_WARNING, "%s is shorter than expected", file->path); - /* Shrink buffer if we allocated substantially too much. */ - if (total + 4096 < size) - buf = xrealloc (buf, total + 1); - - /* The lexer requires that the buffer be \n-terminated. */ - buf[total] = '\n'; - - file->buffer = buf; - file->st.st_size = total; + file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset), + buf, size, total, &file->st.st_size); file->buffer_valid = true; return true; @@ -559,7 +593,7 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) if (file->once_only) return false; - /* We must mark the file once-only if #import now, before header + /* We must mark the file once-only if #import now, before header guard checks. Otherwise, undefining the header guard might cause the file to be re-stacked. */ if (import) @@ -577,7 +611,7 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) return false; /* Handle PCH files immediately; don't stack them. */ - if (include_pch_p (file)) + if (file->pch) { pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname); close (file->fd); @@ -588,6 +622,19 @@ should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) if (!read_file (pfile, file)) return false; + /* Check the file against the PCH file. This is done before + checking against files we've already seen, since it may save on + I/O. */ + if (check_file_against_entries (pfile, file, import)) + { + /* If this isn't a #import, but yet we can't include the file, + that means that it was #import-ed in the PCH file, + so we can never include it again. */ + if (! import) + _cpp_mark_file_once_only (pfile, file); + return false; + } + /* Now we've read the file's contents, we can stack it if there are no once-only files. */ if (!pfile->seen_once_only) @@ -627,8 +674,10 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) if (!should_stack_file (pfile, file, import)) return false; - sysp = MAX ((pfile->map ? pfile->map->sysp : 0), - (file->dir ? file->dir->sysp : 0)); + if (pfile->buffer == NULL || file->dir == NULL) + sysp = 0; + else + sysp = MAX (pfile->buffer->sysp, file->dir->sysp); /* Add the file to the dependencies on its first inclusion. */ if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count) @@ -645,6 +694,7 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import) buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size, CPP_OPTION (pfile, preprocessed)); buffer->file = file; + buffer->sysp = sysp; /* Initialize controlling macro state. */ pfile->mi_valid = true; @@ -694,7 +744,8 @@ search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets, else if (pfile->quote_ignores_source_dir) dir = pfile->quote_include; else - return make_cpp_dir (pfile, dir_name_of_file (file), pfile->map->sysp); + return make_cpp_dir (pfile, dir_name_of_file (file), + pfile->buffer ? pfile->buffer->sysp : 0); if (dir == NULL) cpp_error (pfile, CPP_DL_ERROR, @@ -730,20 +781,32 @@ _cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets, enum include_type type) { struct cpp_dir *dir; + _cpp_file *file; dir = search_path_head (pfile, fname, angle_brackets, type); if (!dir) return false; - return _cpp_stack_file (pfile, _cpp_find_file (pfile, fname, dir, false), - type == IT_IMPORT); + 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) + pfile->line_table->highest_location--; + + return _cpp_stack_file (pfile, file, type == IT_IMPORT); } /* Could not open FILE. The complication is dependency output. */ static void open_file_failed (cpp_reader *pfile, _cpp_file *file) { - int sysp = pfile->map ? pfile->map->sysp: 0; + int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0; bool print_dep = CPP_OPTION (pfile, deps.style) > !!sysp; errno = file->err_no; @@ -814,6 +877,7 @@ make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp) dir->name = (char *) dir_name; dir->len = strlen (dir_name); dir->sysp = sysp; + dir->construct = 0; /* Store this new result in the hash table. */ entry = new_file_hash_entry (pfile); @@ -862,7 +926,7 @@ cpp_included (cpp_reader *pfile, const char *fname) return entry != NULL; } -/* Calculate the hash value of a file hash entry P. */ +/* Calculate the hash value of a file hash entry P. */ static hashval_t file_hash_hash (const void *p) @@ -923,12 +987,15 @@ void cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc) { int flags = 0; + const struct line_maps *line_table = pfile->line_table; + const struct line_map *map = &line_table->maps[line_table->used-1]; /* 1 = system header, 2 = system header to be treated as C. */ if (syshdr) flags = 1 + (externc != 0); - _cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file, - SOURCE_LINE (pfile->map, pfile->line), flags); + pfile->buffer->sysp = flags; + _cpp_do_file_change (pfile, LC_RENAME, map->to_file, + SOURCE_LINE (map, pfile->line_table->highest_line), flags); } /* Allow the client to change the current file. Used by the front end @@ -1013,8 +1080,6 @@ _cpp_compare_file_date (cpp_reader *pfile, const char *fname, bool cpp_push_include (cpp_reader *pfile, const char *fname) { - /* Make the command line directive take up a line. */ - pfile->line++; return _cpp_stack_include (pfile, fname, false, IT_CMDLINE); } @@ -1209,13 +1274,6 @@ remap_filename (cpp_reader *pfile, _cpp_file *file) } } -/* Return true if FILE is usable by PCH. */ -static bool -include_pch_p (_cpp_file *file) -{ - return file->pch & 1; -} - /* Returns true if PCHNAME is a valid PCH file for FILE. */ static bool validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) @@ -1237,7 +1295,7 @@ validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) if (CPP_OPTION (pfile, print_include_names)) { unsigned int i; - for (i = 1; i < pfile->line_maps.depth; i++) + for (i = 1; i < pfile->line_table->depth; i++) putc ('.', stderr); fprintf (stderr, "%c %s\n", valid ? '!' : 'x', pchname); @@ -1247,3 +1305,261 @@ validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) file->path = saved_path; return valid; } + +/* Get the path associated with the _cpp_file F. The path includes + the base name from the include directive and the directory it was + found in via the search path. */ + +const char * +cpp_get_path (struct _cpp_file *f) +{ + return f->path; +} + +/* Get the directory associated with the _cpp_file F. */ + +cpp_dir * +cpp_get_dir (struct _cpp_file *f) +{ + return f->dir; +} + +/* Get the cpp_buffer currently associated with the cpp_reader + PFILE. */ + +cpp_buffer * +cpp_get_buffer (cpp_reader *pfile) +{ + return pfile->buffer; +} + +/* Get the _cpp_file associated with the cpp_buffer B. */ + +_cpp_file * +cpp_get_file (cpp_buffer *b) +{ + return b->file; +} + +/* Get the previous cpp_buffer given a cpp_buffer B. The previous + buffer is the buffer that included the given buffer. */ + +cpp_buffer * +cpp_get_prev (cpp_buffer *b) +{ + return b->prev; +} + +/* This data structure holds the list of header files that were seen + while the PCH was being built. The 'entries' field is kept sorted + in memcmp() order; yes, this means that on little-endian systems, + it's sorted initially by the least-significant byte of 'size', but + that's OK. The code does rely on having entries with the same size + next to each other. */ + +struct pchf_data { + /* Number of pchf_entry structures. */ + size_t count; + + /* Are there any values with once_only set? + This is used as an optimisation, it means we don't have to search + 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]; +}; + +static struct pchf_data *pchf; + +/* Data for pchf_addr. */ +struct pchf_adder_info +{ + cpp_reader *pfile; + struct pchf_data *d; +}; + +/* A hash traversal function to add entries into DATA->D. */ + +static int +pchf_adder (void **slot, void *data) +{ + struct file_hash_entry *h = (struct file_hash_entry *) *slot; + struct pchf_adder_info *i = (struct pchf_adder_info *) data; + + if (h->start_dir != NULL && h->u.file->stack_count != 0) + { + struct pchf_data *d = i->d; + _cpp_file *f = h->u.file; + size_t count = d->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; + + d->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; + if (f->buffer_valid) + md5_buffer ((const char *)f->buffer, + f->st.st_size, d->entries[count].sum); + else + { + FILE *ff; + int oldfd = f->fd; + + if (!open_file (f)) + { + open_file_failed (i->pfile, f); + return 0; + } + ff = fdopen (f->fd, "rb"); + md5_stream (ff, d->entries[count].sum); + fclose (ff); + f->fd = oldfd; + } + d->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)); + + qsort (result->entries, result->count, sizeof (struct pchf_entry), + pchf_save_compare); + + return fwrite (result, result_size, 1, f) == 1; +} + +/* Read the pchf_data structure from F. */ + +bool +_cpp_read_file_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, FILE *f) +{ + struct pchf_data d; + + if (fread (&d, sizeof (struct pchf_data) - sizeof (struct pchf_entry), 1, f) + != 1) + return false; + + pchf = xmalloc (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) + != d.count) + return false; + return true; +} + +/* The parameters for pchf_compare. */ + +struct pchf_compare_data +{ + /* The size of the file we're looking for. */ + off_t size; + + /* The MD5 checksum of the file, if it's been computed. */ + unsigned char sum[16]; + + /* Is SUM valid? */ + bool sum_computed; + + /* Do we need to worry about entries that don't have ONCE_ONLY set? */ + bool check_included; + + /* The file that we're searching for. */ + _cpp_file *f; +}; + +/* bsearch comparison function; look for D_P in E_P. */ + +static int +pchf_compare (const void *d_p, const void *e_p) +{ + const struct pchf_entry *e = (const struct pchf_entry *)e_p; + struct pchf_compare_data *d = (struct pchf_compare_data *)d_p; + int result; + + result = memcmp (&d->size, &e->size, sizeof (off_t)); + if (result != 0) + return result; + + if (! d->sum_computed) + { + _cpp_file *const f = d->f; + + md5_buffer ((const char *)f->buffer, f->st.st_size, d->sum); + d->sum_computed = true; + } + + result = memcmp (d->sum, e->sum, 16); + if (result != 0) + return result; + + if (d->check_included || e->once_only) + return 0; + else + return 1; +} + +/* Check that F is not in a list read from a PCH file (if any). + Assumes that f->buffer_valid is true. Return TRUE if the file + should not be read. */ + +static bool +check_file_against_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, + _cpp_file *f, + bool check_included) +{ + struct pchf_compare_data d; + + if (pchf == NULL + || (! check_included && ! pchf->have_once_only)) + return false; + + d.size = f->st.st_size; + d.sum_computed = false; + d.f = f; + d.check_included = check_included; + return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry), + pchf_compare) != NULL; +}