/* 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 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
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. */
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
#endif
#ifdef __DJGPP__
+#include <io.h>
/* For DJGPP redirected input is opened in text mode. */
# define set_stdin_to_binary_mode() \
if (! isatty (0)) setmode (0, O_BINARY)
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);
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);
flen = strlen (path);
len = flen + sizeof (extension);
- pchname = xmalloc (len);
+ pchname = XNEWVEC (char, len);
memcpy (pchname, path, flen);
memcpy (pchname + flen, extension, sizeof (extension));
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);
if (file->err_no != ENOENT)
{
- open_file_failed (pfile, file);
+ open_file_failed (pfile, file, 0);
return true;
}
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;
/* 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;
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);
+ open_file_failed (pfile, file, angle_brackets);
if (invalid_pch)
{
cpp_error (pfile, CPP_DL_ERROR,
}
break;
}
- }
- /* This is a new file; put it in the list. */
- file->next_file = pfile->all_files;
- pfile->all_files = file;
+ /* 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
+ && file->dir != pfile->quote_include)
+ continue;
- /* 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;
+ entry = search_cache (*hash_slot, file->dir);
+ if (entry)
+ break;
+ }
- for (d = proper_start_dir;; d = d->next)
- {
- 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;
- }
- if (proper_start_dir)
- start_dir = proper_start_dir;
+ 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;
}
- found:
/* Store this new result in the hash table. */
entry = new_file_hash_entry (pfile);
entry->next = *hash_slot;
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)
{
if (regular)
break;
size *= 2;
- buf = xrealloc (buf, size + 1);
+ buf = XRESIZEVEC (uchar, buf, size + 1);
}
}
if (file->fd == -1 && !open_file (file))
{
- open_file_failed (pfile, file);
+ open_file_failed (pfile, file, 0);
return false;
}
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;
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';
if (!dir)
return false;
- file = _cpp_find_file (pfile, fname, dir, false);
+ file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
/* Compensate for the increment in linemap_add. In the case of a
normal #include, we're currently at the start of the line
/* 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)
static struct file_hash_entry *
search_cache (struct file_hash_entry *head, const cpp_dir *start_dir)
{
- struct file_hash_entry *p;
+ while (head && head->start_dir != start_dir)
+ head = head->next;
- /* 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;
+ return head;
}
/* Allocate a new _cpp_file structure. */
{
_cpp_file *file;
- file = xcalloc (1, sizeof (_cpp_file));
+ file = XCNEW (_cpp_file);
file->main_file = !pfile->buffer;
file->fd = -1;
file->dir = dir;
return file;
}
+/* Release a _cpp_file structure. */
+static void
+destroy_cpp_file (_cpp_file *file)
+{
+ if (file->buffer)
+ free ((void *) file->buffer);
+ free ((void *) file->name);
+ free (file);
+}
+
/* 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.
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);
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);
{
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));
+ pfile->file_hash_entries = XNEWVEC (struct file_hash_entry,
+ pfile->file_hash_entries_allocated);
}
/* Return a new file hash entry. */
{
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;
{
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);
}
_cpp_cleanup_files (cpp_reader *pfile)
{
htab_delete (pfile->file_hash);
+ htab_delete (pfile->dir_hash);
}
/* 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
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;
{
free ((void *) file->buffer);
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.
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++] = '/';
int len;
len = 20;
- set = alloc = xmalloc (len + 1);
+ set = alloc = XNEWVEC (char, len + 1);
if (! is_space (ch))
{
*set++ = ch;
if (set - alloc == len)
{
len *= 2;
- alloc = xrealloc (alloc, len + 1);
+ alloc = XRESIZEVEC (char, alloc, len + 1);
set = alloc + len / 2;
}
*set++ = ch;
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)
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);
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';
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;
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;
- if (h->start_dir != NULL && h->u.file->stack_count != 0)
+ result_size = (sizeof (struct pchf_data)
+ + sizeof (struct pchf_entry) * (count - 1));
+ result = XCNEWVAR (struct pchf_data, result_size);
+
+ 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;
+
+ if (f->stack_count == 0)
+ continue;
- d->entries[count].once_only = f->once_only;
+ 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;
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));
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. */
!= 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)