This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Fix for "" vs <> inclusion bug


This patch fixes the bug reported by Jakub Jelinek
(http://gcc.gnu.org/ml/gcc-patches/2000-06/msg00285.html) and possibly
others, where

#include <errno.h>
#include "errno.h"

will not look for an errno.h in the current directory.  Instead of a
hash table keyed by the name that appeared in the #include, we now
have a tree keyed by the actual path name.  (I switched to trees
because hashing complete paths is unlikely to work well.)  The include
path controls a series of lookups in that tree.

This approach does have somewhat higher overhead than the previous
one, but it is simpler to understand and easier to prove correct.  It
fixes not just Jakub's bug, but almost all other problems with path
aliasing, too.  For example, the old code would miss the reinclusion
optimization for b.h in

   top.c:
   #include "a/a.h"
   #include "b/b.h"

   a/a.h:
   #include "../b/b.h"

this one gets it right.  There remains potential for confusion if you
use a mix of absolute and relative paths to refer to the same
directory tree, but I hope no one actually does that.  Symlinks may
also cause problems.

I would add a test case for this bug but I can't think of a safe way
to do it.  Dropping an "errno.h" into one of the common testcase
directories will interfere with all the other tests in that
directory.  Any ideas?

There's an experimental feature included in this patch: header files
without reinclusion guards are held open in case we need them again
(we usually do).  I'm interested to know if this causes problems or if
it makes any noticeable performance difference.  The new lexer mmaps
files where possible, and we may try caching the mappings as well.

zw

	* cppfiles.c: Include splay-tree.h, not hashtab.h.
	(redundant_include_p, make_IHASH, hash_IHASH, eq_IHASH): Delete.
	(destroy_include_file_node): New.
	(_cpp_init_include_hash): Rename _cpp_init_include_table.
	Create a splay tree, not a hash table.
	(open_include_file): Look up the path in the include table,
	do the multiple include optimization here, etc.
	(cpp_included): Walk the path.
	(find_include_file): Just walk the path calling
	open_include_file, or call it directly for an absolute path.
	(_cpp_fake_ihash): Rename _cpp_fake_include and update for new
	scheme.
	(read_include_file): Update for new scheme.  Don't close the
	file unless reading fails.
	(_cpp_execute_include, cpp_read_file): Tweak for new scheme.

	* cpphash.h (struct ihash, NEVER_REINCLUDE): Delete.
	(struct include_file): New.
	(NEVER_REREAD, DO_NOT_REREAD, CPP_IN_SYSTEM_HEADER): New
	macros.
	(CPP_PEDANTIC, CPP_WTRADITIONAL): Update.
	Update prototypes.

	* cppinit.c: Include splay-tree.h.
	(cpp_reader_init, cpp_cleanup): Update.

	* cpplib.h (struct cpp_buffer): Change ihash field to 
	'struct include_file *inc'.  Remove system_header_p.
	(struct cpp_reader): Change all_include_files to a
	struct splay_tree_s *.

	* cpplex.c: Update all references to cpp_buffer->ihash and/or
	cpp_buffer->system_header_p.
	(cpp_pop_buffer): Close file here, only if DO_NOT_REREAD.

===================================================================
Index: cppfiles.c
--- cppfiles.c	2000/06/09 14:37:56	1.65
+++ cppfiles.c	2000/06/21 18:18:46
@@ -22,11 +22,11 @@ Foundation, 59 Temple Place - Suite 330,
 
 #include "config.h"
 #include "system.h"
-#include "hashtab.h"
 #include "cpplib.h"
 #include "cpphash.h"
 #include "intl.h"
 #include "mkdeps.h"
+#include "splay-tree.h"
 
 #ifdef HAVE_MMAP_FILE
 # include <sys/mman.h>
@@ -43,10 +43,6 @@ Foundation, 59 Temple Place - Suite 330,
 # define O_BINARY 0
 #endif
 
-static IHASH *redundant_include_p PARAMS ((IHASH *, struct file_name_list *));
-static IHASH *make_IHASH	PARAMS ((const char *, const char *,
-					 struct file_name_list *,
-					 unsigned int, IHASH **));
 static struct file_name_map *read_name_map
 				PARAMS ((cpp_reader *, const char *));
 static char *read_filename_string PARAMS ((int, FILE *));
@@ -54,485 +50,265 @@ static char *remap_filename 	PARAMS ((cp
 					 struct file_name_list *));
 static struct file_name_list *actual_directory
 				PARAMS ((cpp_reader *, const char *));
-static unsigned int hash_IHASH	PARAMS ((const void *));
-static int eq_IHASH		PARAMS ((const void *, const void *));
-static int find_include_file	PARAMS ((cpp_reader *, const char *,
-					struct file_name_list *,
-					IHASH **, int *));
-static inline int open_include_file PARAMS ((cpp_reader *, const char *));
-static int read_include_file	PARAMS ((cpp_reader *, int, IHASH *));
+static struct include_file *find_include_file
+				PARAMS ((cpp_reader *, const char *,
+					 struct file_name_list *));
+static struct include_file *open_include_file
+				PARAMS ((cpp_reader *, const char *));
+static int read_include_file	PARAMS ((cpp_reader *, struct include_file *));
 static ssize_t read_with_read	PARAMS ((cpp_buffer *, int, ssize_t));
 static ssize_t read_file	PARAMS ((cpp_buffer *, int, ssize_t));
 
+static void destroy_include_file_node	PARAMS ((splay_tree_value));
+
 #if 0
 static void hack_vms_include_specification PARAMS ((char *));
 #endif
 
-/* Initial size of include hash table.  */
-#define IHASHSIZE 50
-
 #ifndef INCLUDE_LEN_FUDGE
 #define INCLUDE_LEN_FUDGE 0
 #endif
 
-/* Calculate hash of an IHASH entry.  */
-static unsigned int
-hash_IHASH (x)
-     const void *x;
-{
-  const IHASH *i = (const IHASH *)x;
-  return i->hash;
-}
-
-/* Compare an existing IHASH structure with a potential one.  */
-static int
-eq_IHASH (x, y)
-     const void *x;
-     const void *y;
-{
-  const char *a = ((const IHASH *)x)->nshort;
-  const char *b = ((const IHASH *)y)->nshort;
-  return !strcmp (a, b);
+/* 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)
+    {
+      if (f->fd != -1)
+	close (f->fd);
+      free (f);
+    }
 }
 
-/* Init the hash table.  In here so it can see the hash and eq functions.  */
 void
-_cpp_init_include_hash (pfile)
+_cpp_init_include_table (pfile)
      cpp_reader *pfile;
 {
   pfile->all_include_files
-    = htab_create (IHASHSIZE, hash_IHASH, eq_IHASH, free);
+    = splay_tree_new ((splay_tree_compare_fn) strcmp,
+		      (splay_tree_delete_key_fn) free,
+		      destroy_include_file_node);
 }
-
-/* Return 0 if the file pointed to by IHASH has never been included before,
-         -1 if it has been included before and need not be again,
-	 or a pointer to an IHASH entry which is the file to be reread.
-   "Never before" is with respect to the position in ILIST.
-
-   This will not detect redundancies involving odd uses of the
-   `current directory' rule for "" includes.  They aren't quite
-   pathological, but I think they are rare enough not to worry about.
-   The simplest example is:
 
-   top.c:
-   #include "a/a.h"
-   #include "b/b.h"
+/* Given a filename, look it up and possibly open it.  If the file
+   does not exist, return NULL.  If the file does exist but doesn't
+   need to be reread, return an include_file entry with fd == -1.
+   If it needs to be (re)read, return an include_file entry with
+   fd a file descriptor open on the file. */
 
-   a/a.h:
-   #include "../b/b.h"
-
-   and the problem is that for `current directory' includes,
-   ihash->foundhere is not on any of the global include chains,
-   so the test below (i->foundhere == l) may be false even when
-   the directories are in fact the same.  */
-
-static IHASH *
-redundant_include_p (ihash, ilist)
-     IHASH *ihash;
-     struct file_name_list *ilist;
+static struct include_file *
+open_include_file (pfile, filename)
+     cpp_reader *pfile;
+     const char *filename;
 {
-  struct file_name_list *l;
-  IHASH *i;
+  splay_tree_node nd;
+  struct include_file *file = 0;
+  int fd;
 
-  if (! ihash->foundhere)
-    return 0;
+  nd = splay_tree_lookup (pfile->all_include_files,
+			  (splay_tree_key) filename);
 
-  for (i = ihash; i; i = i->next_this_file)
-    for (l = ilist; l; l = l->next)
-       if (i->foundhere == l)
-	 /* The cmacro works like this: If it's NULL, the file is to
-	    be included again.  If it's NEVER_REINCLUDE, 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 not defined.  */
-	 return (i->cmacro
-		 && (i->cmacro == NEVER_REINCLUDE
-		     || i->cmacro->type != T_VOID))
-	     ? (IHASH *)-1 : i;
+  if (nd)
+    {
+      if (nd->value == 0)
+	return 0;
 
-  return 0;
-}
+      file = (struct include_file *)nd->value;
 
-/* Return 1 if the file named by FNAME has been included before in
-   any context, 0 otherwise.  */
-int
-cpp_included (pfile, fname)
-     cpp_reader *pfile;
-     const char *fname;
-{
-  IHASH dummy, *ptr;
-  dummy.nshort = fname;
-  dummy.hash = _cpp_calc_hash ((const U_CHAR *)fname, strlen (fname));
-  ptr = htab_find_with_hash (pfile->all_include_files,
-			     (const void *)&dummy, dummy.hash);
-  return (ptr != NULL);
-}
-
-/* Create an IHASH entry and insert it in SLOT.  */
-static IHASH *
-make_IHASH (name, fname, path, hash, slot)
-     const char *name, *fname;
-     struct file_name_list *path;
-     unsigned int hash;
-     IHASH **slot;
-{
-  IHASH *ih;
-  if (path == ABSOLUTE_PATH)
-    {
-      ih = (IHASH *) xmalloc (sizeof (IHASH) + strlen (name));
-      ih->nshort = ih->name;
-    }
-  else
-    {
-      char *s;
-      
-      if ((s = strstr (name, fname)) != NULL)
+      if (DO_NOT_REREAD (file))
 	{
-	  ih = (IHASH *) xmalloc (sizeof (IHASH) + strlen (name));
-	  ih->nshort = ih->name + (s - name);
+	  if (file->fd != -1)
+	    {
+	      close (file->fd);
+	      file->fd = -1;
+	    }
+	  return file;
 	}
-      else
-	{
-	  ih = (IHASH *) xmalloc (sizeof (IHASH) + strlen (name)
-				  + strlen (fname) + 1);
-	  ih->nshort = ih->name + strlen (name) + 1;
-	  strcpy ((char *)ih->nshort, fname);
-	}
-    }
-  strcpy ((char *)ih->name, name);
-  ih->foundhere = path;
-  ih->cmacro = NULL;
-  ih->hash = hash;
-  ih->next_this_file = *slot;
-  *slot = ih;
-  return ih;
-}
-
-/* Centralize calls to open(2) here.  This provides a hook for future
-   changes which might, e.g. look for and open a precompiled version
-   of the header.  It also means all the magic currently associated
-   with calling open is in one place, and if we ever need more, it'll
-   be in one place too.
-
-   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 systems, but
-   paranoia is a virtue).
-
-   Use the three-argument form of open even though we aren't
-   specifying O_CREAT, to defend against broken system headers.
-
-   O_BINARY tells some runtime libraries (notably DJGPP) not to do
-   newline translation; we can handle DOS line breaks just fine
-   ourselves.  */
-
-static inline int
-open_include_file (pfile, filename)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     const char *filename;
-{
-  return open (filename, O_RDONLY|O_NOCTTY|O_BINARY, 0666);
-}
 
-/* Search for include file FNAME in the include chain starting at
-   SEARCH_START.  Return -2 if this file doesn't need to be included
-   (because it was included already and it's marked idempotent),
-   -1 if an error occurred, or a file descriptor open on the file.
-   *IHASH is set to point to the include hash entry for this file, and
-   *BEFORE is set to 1 if the file was included before (but needs to be read
-   again). */
-static int
-find_include_file (pfile, fname, search_start, ihash, before)
-     cpp_reader *pfile;
-     const char *fname;
-     struct file_name_list *search_start;
-     IHASH **ihash;
-     int *before;
-{
-  struct file_name_list *path;
-  IHASH *ih, **slot;
-  IHASH dummy;
-  int f;
-  char *name;
-
-  dummy.nshort = fname;
-  dummy.hash = _cpp_calc_hash ((const U_CHAR *)fname, strlen (fname));
-  path = (fname[0] == '/') ? ABSOLUTE_PATH : search_start;
-  slot = (IHASH **) htab_find_slot_with_hash (pfile->all_include_files,
-					      (const void *) &dummy,
-					      dummy.hash, INSERT);
-
-  if (*slot && (ih = redundant_include_p (*slot, path)))
-    {
-      if (ih == (IHASH *)-1)
-	return -2;
-
-      *before = 1;
-      *ihash = ih;
-      return open_include_file (pfile, ih->name);
+      /* File descriptors are cached for files that might be reread.  */
+      if (file->fd != -1)
+	{
+	  lseek (file->fd, 0, SEEK_SET);
+	  return file;
+	}
     }
 
-  if (path == ABSOLUTE_PATH)
-    {
-      name = (char *) fname;
-      f = open_include_file (pfile, name);
-    }
+  /* 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
+     systems, but paranoia is a virtue).
+
+     Use the three-argument form of open even though we aren't
+     specifying O_CREAT, to defend against broken system headers.
+
+     O_BINARY tells some runtime libraries (notably DJGPP) not to do
+     newline translation; we can handle DOS line breaks just fine
+     ourselves.
+
+     Special case: the empty string is translated to stdin.  */
+  if (filename[0] == '\0')
+    fd = 0;
   else
-    {
-      /* Search directory path, trying to open the file.  */
-      name = (char *) alloca (strlen (fname) + pfile->max_include_len
-		     + 2 + INCLUDE_LEN_FUDGE);
-      do
-	{
-	  memcpy (name, path->name, path->nlen);
-	  name[path->nlen] = '/';
-	  strcpy (&name[path->nlen+1], fname);
-	  _cpp_simplify_pathname (name);
-	  if (CPP_OPTION (pfile, remap))
-	    name = remap_filename (pfile, name, path);
+    fd = open (filename, O_RDONLY|O_NOCTTY|O_BINARY, 0666);
 
-	  f = open_include_file (pfile, name);
+  if (fd == -1)
+    {
 #ifdef EACCES
-	  if (f == -1 && errno == EACCES)
-	    {
-	      cpp_error (pfile,
-			 "included file `%s' exists but is not readable",
-			 name);
-	      return -1;
-	    }
+      if (errno == EACCES)
+	{
+	  cpp_error (pfile, "included file `%s' exists but is not readable",
+		     filename);
+	}
 #endif
-	  if (f >= 0)
-	    break;
-	  path = path->next;
+      /* Nonexistent or inaccessible file.  Create a negative node for it.  */
+      if (nd)
+	{
+	  cpp_ice (pfile,
+		   "node for '%s' exists, open failed, error '%s', value %lx\n",
+		   filename, strerror (errno), nd->value);
+	  destroy_include_file_node (nd->value);
 	}
-      while (path);
+      splay_tree_insert (pfile->all_include_files,
+			 (splay_tree_key) xstrdup (filename), 0);
+      return 0;
+    }
+
+  /* If we haven't seen this file before, create a positive node for it.  */
+  if (!nd)
+    {
+      file = xnew (struct include_file);
+      file->cmacro = 0;
+      file->before = 0;
+      file->sysp = 0;
+      file->foundhere = 0;
+      file->name = xstrdup (filename);
+      splay_tree_insert (pfile->all_include_files,
+			 (splay_tree_key) file->name,
+			 (splay_tree_value) file);
     }
-  if (f == -1)
-    return -1;
 
-  ih = make_IHASH (name, fname, path, dummy.hash, slot);
-  *before = 0;
-  *ihash = ih;
-  return f;
+  file->fd = fd;
+  return file;
 }
 
-/* Create a dummy IHASH entry for FNAME, and return its name pointer.
-   This is used by #line.  */
-const char *
-_cpp_fake_ihash (pfile, fname)
+/* Return 1 if the file named by FNAME has been included before in
+   any context, 0 otherwise.  */
+int
+cpp_included (pfile, fname)
      cpp_reader *pfile;
      const char *fname;
-{
-  IHASH *ih, **slot;
-  IHASH dummy;
-
-  dummy.nshort = fname;
-  dummy.hash = _cpp_calc_hash ((const U_CHAR *)fname, strlen (fname));
-  slot = (IHASH **) htab_find_slot_with_hash (pfile->all_include_files,
-					      (const void *) &dummy,
-					      dummy.hash, INSERT);
-  if (*slot)
-    return (*slot)->name;
-  ih = make_IHASH (fname, 0, ABSOLUTE_PATH, dummy.hash, slot);
-  return ih->name;
-}
-
-
-/* The file_name_map structure holds a mapping of file names for a
-   particular directory.  This mapping is read from the file named
-   FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
-   map filenames on a file system with severe filename restrictions,
-   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;
-  char *map_from;
-  char *map_to;
-};
-
-#define FILE_NAME_MAP_FILE "header.gcc"
-
-/* Read a space delimited string of unlimited length from a stdio
-   file.  */
-
-static char *
-read_filename_string (ch, f)
-     int ch;
-     FILE *f;
 {
-  char *alloc, *set;
-  int len;
+  struct file_name_list *path;
+  char *name;
+  splay_tree_node nd;
 
-  len = 20;
-  set = alloc = xmalloc (len + 1);
-  if (! is_space(ch))
+  if (fname[0] == '/')
     {
-      *set++ = ch;
-      while ((ch = getc (f)) != EOF && ! is_space(ch))
-	{
-	  if (set - alloc == len)
-	    {
-	      len *= 2;
-	      alloc = xrealloc (alloc, len + 1);
-	      set = alloc + len / 2;
-	    }
-	  *set++ = ch;
-	}
+      /* Just look it up.  */
+      nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname);
+      return (nd && nd->value);
     }
-  *set = '\0';
-  ungetc (ch, f);
-  return alloc;
+      
+  /* Search directory path for the file.  */
+  name = (char *) alloca (strlen (fname) + pfile->max_include_len
+			  + 2 + INCLUDE_LEN_FUDGE);
+  for (path = CPP_OPTION (pfile, quote_include); path; path = path->next)
+    {
+      memcpy (name, path->name, path->nlen);
+      name[path->nlen] = '/';
+      strcpy (&name[path->nlen+1], fname);
+      _cpp_simplify_pathname (name);
+      if (CPP_OPTION (pfile, remap))
+	name = remap_filename (pfile, name, path);
+
+      nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
+      if (nd && nd->value)
+	return 1;
+    }
+  return 0;
 }
-
-/* 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;
-  char *map_list_name;
-  struct file_name_map *map_list_map;
-};
 
-/* Read the file name map file for DIRNAME.  */
+/* 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, possibly with a file descriptor
+   open on the file.  */
 
-static struct file_name_map *
-read_name_map (pfile, dirname)
+static struct include_file *
+find_include_file (pfile, fname, search_start)
      cpp_reader *pfile;
-     const char *dirname;
+     const char *fname;
+     struct file_name_list *search_start;
 {
-  register struct file_name_map_list *map_list_ptr;
+  struct file_name_list *path;
   char *name;
-  FILE *f;
-
-  for (map_list_ptr = CPP_OPTION (pfile, map_list); map_list_ptr;
-       map_list_ptr = map_list_ptr->map_list_next)
-    if (! strcmp (map_list_ptr->map_list_name, dirname))
-      return map_list_ptr->map_list_map;
-
-  map_list_ptr = ((struct file_name_map_list *)
-		  xmalloc (sizeof (struct file_name_map_list)));
-  map_list_ptr->map_list_name = xstrdup (dirname);
+  struct include_file *file;
 
-  name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
-  strcpy (name, dirname);
-  if (*dirname)
-    strcat (name, "/");
-  strcat (name, FILE_NAME_MAP_FILE);
-  f = fopen (name, "r");
-  if (!f)
-    map_list_ptr->map_list_map = (struct file_name_map *)-1;
-  else
-    {
-      int ch;
-      int dirlen = strlen (dirname);
+  if (fname[0] == '/')
+    return open_include_file (pfile, fname);
+      
+  /* 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)
+    {
+      memcpy (name, path->name, path->nlen);
+      name[path->nlen] = '/';
+      strcpy (&name[path->nlen+1], fname);
+      _cpp_simplify_pathname (name);
+      if (CPP_OPTION (pfile, remap))
+	name = remap_filename (pfile, name, path);
 
-      while ((ch = getc (f)) != EOF)
+      file = open_include_file (pfile, name);
+      if (file)
 	{
-	  char *from, *to;
-	  struct file_name_map *ptr;
-
-	  if (is_space(ch))
-	    continue;
-	  from = read_filename_string (ch, f);
-	  while ((ch = getc (f)) != EOF && is_hspace(ch))
-	    ;
-	  to = read_filename_string (ch, f);
-
-	  ptr = ((struct file_name_map *)
-		 xmalloc (sizeof (struct file_name_map)));
-	  ptr->map_from = from;
-
-	  /* Make the real filename absolute.  */
-	  if (*to == '/')
-	    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);
-	      free (to);
-	    }	      
-
-	  ptr->map_next = map_list_ptr->map_list_map;
-	  map_list_ptr->map_list_map = ptr;
-
-	  while ((ch = getc (f)) != '\n')
-	    if (ch == EOF)
-	      break;
+	  file->sysp = path->sysp;
+	  file->foundhere = path;
+	  return file;
 	}
-      fclose (f);
     }
-  
-  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. */
+  return 0;
+}
 
-static char *
-remap_filename (pfile, name, loc)
+/* #line uses this to save artificial file names.  We have to try
+   opening the file because an all_include_files entry is always
+   either + or -, there's no 'I don't know' value.  */
+const char *
+_cpp_fake_include (pfile, fname)
      cpp_reader *pfile;
-     char *name;
-     struct file_name_list *loc;
+     const char *fname;
 {
-  struct file_name_map *map;
-  const char *from, *p, *dir;
+  splay_tree_node nd;
+  struct include_file *file;
+  char *name;
 
-  if (! loc->name_map)
-    loc->name_map = read_name_map (pfile,
-				   loc->name
-				   ? loc->name : ".");
+  file = find_include_file (pfile, fname, CPP_OPTION (pfile, quote_include));
+  if (file)
+    return file->name;
 
-  if (loc->name_map == (struct file_name_map *)-1)
-    return name;
-  
-  from = name + strlen (loc->name) + 1;
-  
-  for (map = loc->name_map; map; map = map->map_next)
-    if (!strcmp (map->map_from, from))
-      return map->map_to;
-
-  /* Try to find a mapping file for the particular directory we are
-     looking in.  Thus #include <sys/types.h> will look up sys/types.h
-     in /usr/include/header.gcc and look up types.h in
-     /usr/include/sys/header.gcc.  */
-  p = strrchr (name, '/');
-  if (!p)
-    p = name;
-  if (loc && loc->name
-      && strlen (loc->name) == (size_t) (p - name)
-      && !strncmp (loc->name, name, p - name))
-    /* FILENAME is in SEARCHPTR, which we've already checked.  */
-    return name;
+  name = xstrdup (fname);
+  _cpp_simplify_pathname (name);
 
-  if (p == name)
-    {
-      dir = ".";
-      from = name;
-    }
-  else
+  /* We cannot just blindly insert a node, because there's still the
+     chance that the node already exists but isn't on the search path.  */
+  nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
+  if (nd)
     {
-      char * newdir = (char *) alloca (p - name + 1);
-      memcpy (newdir, name, p - name);
-      newdir[p - name] = '\0';
-      dir = newdir;
-      from = p + 1;
+      free (name);
+      return (const char *) nd->key;
     }
-  
-  for (map = read_name_map (pfile, dir); map; map = map->map_next)
-    if (! strcmp (map->map_from, name))
-      return map->map_to;
 
-  return name;
+  splay_tree_insert (pfile->all_include_files, (splay_tree_key) name, 0);
+  return (const char *)name;
 }
 
-
+#define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
 void
 _cpp_execute_include (pfile, f, len, no_reinclude, search_start)
      cpp_reader *pfile;
@@ -541,11 +317,9 @@ _cpp_execute_include (pfile, f, len, no_
      int no_reinclude;
      struct file_name_list *search_start;
 {
-  IHASH *ihash;
+  struct include_file *inc;
   char *fname = (char *)f;
-  int fd;
   int angle_brackets = fname[0] == '<';
-  int before;
 
   if (!search_start)
     {
@@ -568,83 +342,80 @@ _cpp_execute_include (pfile, f, len, no_
   len -= 2;
   fname[len] = '\0';
 
-  fd = find_include_file (pfile, fname, search_start, &ihash, &before);
+  inc = find_include_file (pfile, fname, search_start);
 
-  if (fd == -2)
-    return;
-  
-  if (fd == -1)
+  if (inc)
     {
-      if (CPP_OPTION (pfile, print_deps_missing_files)
-	  && CPP_PRINT_DEPS (pfile) > (angle_brackets ||
-				       (pfile->system_include_depth > 0)))
-        {
-	  if (!angle_brackets)
-	    deps_add_dep (pfile->deps, fname);
-	  else
-	    {
-	      char *p;
-	      struct file_name_list *ptr;
-	      /* 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);
-
-	      p = (char *) alloca (strlen (ptr->name)
-				   + strlen (fname) + 2);
-	      if (*ptr->name != '\0')
-	        {
-		  strcpy (p, ptr->name);
-		  strcat (p, "/");
-	        }
-	      strcat (p, fname);
-	      deps_add_dep (pfile->deps, p);
-	    }
+      if (inc->fd == -1)
+	return;
+
+      /* For -M, add the file to the dependencies on its first inclusion. */
+      if (!inc->before && PRINT_THIS_DEP (pfile, angle_brackets))
+	deps_add_dep (pfile->deps, inc->name);
+      inc->before = 1;
+
+      /* 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);
 	}
-      /* 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)
-	       && (CPP_PRINT_DEPS (pfile)
-		   <= (angle_brackets || (pfile->system_include_depth > 0))))
-	cpp_warning (pfile, "No include path in which to find %s", fname);
-      else
-	cpp_error_from_errno (pfile, fname);
 
+      /* Actually process the file.  */
+      if (no_reinclude)
+	inc->cmacro = NEVER_REREAD;
+  
+      if (read_include_file (pfile, inc))
+	{
+	  if (angle_brackets)
+	    pfile->system_include_depth++;
+	}
       return;
     }
-
-  /* For -M, add the file to the dependencies on its first inclusion. */
-  if (!before && (CPP_PRINT_DEPS (pfile)
-		  > (angle_brackets || (pfile->system_include_depth > 0))))
-    deps_add_dep (pfile->deps, ihash->name);
-
-  /* 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", ihash->name);
-    }
-
-  /* Actually process the file.  */
-  if (no_reinclude)
-    ihash->cmacro = NEVER_REINCLUDE;
-  
-  if (read_include_file (pfile, fd, ihash))
+      
+  if (CPP_OPTION (pfile, print_deps_missing_files)
+      && PRINT_THIS_DEP (pfile, angle_brackets))
     {
-      if (angle_brackets)
-	pfile->system_include_depth++;
+      if (!angle_brackets)
+	deps_add_dep (pfile->deps, fname);
+      else
+	{
+	  char *p;
+	  struct file_name_list *ptr;
+	  /* 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);
+
+	  p = (char *) alloca (strlen (ptr->name)
+			       + strlen (fname) + 2);
+	  if (*ptr->name != '\0')
+	    {
+	      strcpy (p, ptr->name);
+	      strcat (p, "/");
+	    }
+	  strcat (p, 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_THIS_DEP (pfile, angle_brackets))
+    cpp_warning (pfile, "No include path in which to find %s", fname);
+  else
+    cpp_error_from_errno (pfile, fname);
 }
 
-
 /* Push an input buffer and load it up with the contents of FNAME.
    If FNAME is "" or NULL, read standard input.  */
 int
@@ -652,53 +423,28 @@ cpp_read_file (pfile, fname)
      cpp_reader *pfile;
      const char *fname;
 {
-  IHASH *ih, **slot;
-  IHASH dummy;
-  int f;
+  struct include_file *f;
 
   if (fname == NULL)
     fname = "";
 
-  dummy.nshort = fname;
-  /* _cpp_calc_hash doesn't like zero-length strings.  */
-  if (*fname == 0)
-    dummy.hash = 0;
-  else
-    dummy.hash = _cpp_calc_hash ((const U_CHAR *)fname, strlen (fname));
-  slot = (IHASH **) htab_find_slot_with_hash (pfile->all_include_files,
-					      (const void *) &dummy,
-					      dummy.hash, INSERT);
-  if (*slot && (ih = redundant_include_p (*slot, ABSOLUTE_PATH)))
-    {
-      if (ih == (IHASH *) -1)
-	return 1;  /* Already included.  */
-    }
-  else
-    ih = make_IHASH (fname, 0, ABSOLUTE_PATH, dummy.hash, slot);
+  f = open_include_file (pfile, fname);
 
-  if (*fname == '\0')
-    f = 0;
-  else
-    f = open_include_file (pfile, fname);
-
-  return read_include_file (pfile, f, ih);
+  return read_include_file (pfile, f);
 }
 
-/* Read the contents of FD into the buffer on the top of PFILE's stack.
-   IHASH points to the include hash entry for the file associated with
-   FD.
+/* Read the file referenced by INC into a new buffer on PFILE's stack.
+   Return 1 if successful, 0 if not.  */
 
-   The caller is responsible for the cpp_push_buffer.  */
-
 static int
-read_include_file (pfile, fd, ihash)
+read_include_file (pfile, inc)
      cpp_reader *pfile;
-     int fd;
-     IHASH *ihash;
+     struct include_file *inc;
 {
   struct stat st;
   ssize_t length;
   cpp_buffer *fp;
+  int fd = inc->fd;
 
   fp = cpp_push_buffer (pfile, NULL, 0);
 
@@ -733,7 +479,7 @@ read_include_file (pfile, fd, ihash)
 	 does not bite us.  */
       if (st.st_size > INTTYPE_MAXIMUM (ssize_t))
 	{
-	  cpp_error (pfile, "%s is too large", ihash->name);
+	  cpp_error (pfile, "%s is too large", inc->name);
 	  goto fail;
 	}
       st_size = st.st_size;
@@ -741,16 +487,16 @@ read_include_file (pfile, fd, ihash)
       if (length == -1)
 	goto perror_fail;
       if (length < st_size)
-	cpp_warning (pfile, "%s is shorter than expected\n", ihash->name);
+	cpp_warning (pfile, "%s is shorter than expected\n", inc->name);
     }
   else if (S_ISBLK (st.st_mode))
     {
-      cpp_error (pfile, "%s is a block device", ihash->name);
+      cpp_error (pfile, "%s is a block device", inc->name);
       goto fail;
     }
   else if (S_ISDIR (st.st_mode))
     {
-      cpp_error (pfile, "%s is a directory", ihash->name);
+      cpp_error (pfile, "%s is a directory", inc->name);
       goto fail;
     }
   else
@@ -764,38 +510,38 @@ read_include_file (pfile, fd, ihash)
     }
 
   /* These must be set before prescan.  */
-  fp->ihash = ihash;
-  fp->nominal_fname = ihash->name;
+  fp->inc = inc;
+  fp->nominal_fname = inc->name;
   
   if (length == 0)
-    ihash->cmacro = NEVER_REINCLUDE;
+    inc->cmacro = NEVER_REREAD;
   else
     /* Temporary - I hope.  */
     length = _cpp_prescan (pfile, fp, length);
 
   fp->rlimit = fp->buf + length;
   fp->cur = fp->buf;
-  if (ihash->foundhere != ABSOLUTE_PATH)
-    fp->system_header_p = ihash->foundhere->sysp;
   fp->lineno = 1;
   fp->line_base = fp->buf;
 
   /* The ->actual_dir field is only used when ignore_srcdir is not in effect;
      see do_include */
   if (!CPP_OPTION (pfile, ignore_srcdir))
-    fp->actual_dir = actual_directory (pfile, ihash->name);
+    fp->actual_dir = actual_directory (pfile, inc->name);
 
   pfile->input_stack_listing_current = 0;
   pfile->only_seen_white = 2;
-  close (fd);
   return 1;
 
  perror_fail:
-  cpp_error_from_errno (pfile, ihash->name);
+  cpp_error_from_errno (pfile, inc->name);
+  /* Do not try to read this file again.  */
+  close (fd);
+  inc->fd = -1;
+  inc->cmacro = NEVER_REREAD;
  fail:
   cpp_pop_buffer (pfile);
  push_fail:
-  close (fd);
   return 0;
 }
 
@@ -867,6 +613,200 @@ read_with_read (fp, fd, size)
   return offset;
 }
 
+/* The file_name_map structure holds a mapping of file names for a
+   particular directory.  This mapping is read from the file named
+   FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
+   map filenames on a file system with severe filename restrictions,
+   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;
+  char *map_from;
+  char *map_to;
+};
+
+#define FILE_NAME_MAP_FILE "header.gcc"
+
+/* Read a space delimited string of unlimited length from a stdio
+   file.  */
+
+static char *
+read_filename_string (ch, f)
+     int ch;
+     FILE *f;
+{
+  char *alloc, *set;
+  int len;
+
+  len = 20;
+  set = alloc = xmalloc (len + 1);
+  if (! is_space(ch))
+    {
+      *set++ = ch;
+      while ((ch = getc (f)) != EOF && ! is_space(ch))
+	{
+	  if (set - alloc == len)
+	    {
+	      len *= 2;
+	      alloc = xrealloc (alloc, len + 1);
+	      set = alloc + len / 2;
+	    }
+	  *set++ = ch;
+	}
+    }
+  *set = '\0';
+  ungetc (ch, f);
+  return alloc;
+}
+
+/* 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;
+  char *map_list_name;
+  struct file_name_map *map_list_map;
+};
+
+/* Read the file name map file for DIRNAME.  */
+
+static struct file_name_map *
+read_name_map (pfile, dirname)
+     cpp_reader *pfile;
+     const char *dirname;
+{
+  register struct file_name_map_list *map_list_ptr;
+  char *name;
+  FILE *f;
+
+  for (map_list_ptr = CPP_OPTION (pfile, map_list); map_list_ptr;
+       map_list_ptr = map_list_ptr->map_list_next)
+    if (! strcmp (map_list_ptr->map_list_name, dirname))
+      return map_list_ptr->map_list_map;
+
+  map_list_ptr = ((struct file_name_map_list *)
+		  xmalloc (sizeof (struct file_name_map_list)));
+  map_list_ptr->map_list_name = xstrdup (dirname);
+
+  name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
+  strcpy (name, dirname);
+  if (*dirname)
+    strcat (name, "/");
+  strcat (name, FILE_NAME_MAP_FILE);
+  f = fopen (name, "r");
+  if (!f)
+    map_list_ptr->map_list_map = (struct file_name_map *)-1;
+  else
+    {
+      int ch;
+      int dirlen = strlen (dirname);
+
+      while ((ch = getc (f)) != EOF)
+	{
+	  char *from, *to;
+	  struct file_name_map *ptr;
+
+	  if (is_space(ch))
+	    continue;
+	  from = read_filename_string (ch, f);
+	  while ((ch = getc (f)) != EOF && is_hspace(ch))
+	    ;
+	  to = read_filename_string (ch, f);
+
+	  ptr = ((struct file_name_map *)
+		 xmalloc (sizeof (struct file_name_map)));
+	  ptr->map_from = from;
+
+	  /* Make the real filename absolute.  */
+	  if (*to == '/')
+	    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);
+	      free (to);
+	    }	      
+
+	  ptr->map_next = map_list_ptr->map_list_map;
+	  map_list_ptr->map_list_map = ptr;
+
+	  while ((ch = getc (f)) != '\n')
+	    if (ch == EOF)
+	      break;
+	}
+      fclose (f);
+    }
+  
+  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. */
+
+static char *
+remap_filename (pfile, name, loc)
+     cpp_reader *pfile;
+     char *name;
+     struct file_name_list *loc;
+{
+  struct file_name_map *map;
+  const char *from, *p, *dir;
+
+  if (! loc->name_map)
+    loc->name_map = read_name_map (pfile,
+				   loc->name
+				   ? loc->name : ".");
+
+  if (loc->name_map == (struct file_name_map *)-1)
+    return name;
+  
+  from = name + strlen (loc->name) + 1;
+  
+  for (map = loc->name_map; map; map = map->map_next)
+    if (!strcmp (map->map_from, from))
+      return map->map_to;
+
+  /* Try to find a mapping file for the particular directory we are
+     looking in.  Thus #include <sys/types.h> will look up sys/types.h
+     in /usr/include/header.gcc and look up types.h in
+     /usr/include/sys/header.gcc.  */
+  p = strrchr (name, '/');
+  if (!p)
+    p = name;
+  if (loc && loc->name
+      && strlen (loc->name) == (size_t) (p - name)
+      && !strncmp (loc->name, name, p - name))
+    /* FILENAME is in SEARCHPTR, which we've already checked.  */
+    return name;
+
+  if (p == name)
+    {
+      dir = ".";
+      from = name;
+    }
+  else
+    {
+      char * newdir = (char *) alloca (p - name + 1);
+      memcpy (newdir, name, p - name);
+      newdir[p - name] = '\0';
+      dir = newdir;
+      from = p + 1;
+    }
+  
+  for (map = read_name_map (pfile, dir); map; map = map->map_next)
+    if (! strcmp (map->map_from, name))
+      return map->map_to;
+
+  return name;
+}
+
 /* Given a path FNAME, extract the directory component and place it
    onto the actual_dirs list.  Return a pointer to the allocated
    file_name_list structure.  These structures are used to implement
@@ -919,7 +859,7 @@ actual_directory (pfile, fname)
   x->nlen = dlen;
   x->next = CPP_OPTION (pfile, quote_include);
   x->alloc = pfile->actual_dirs;
-  x->sysp = CPP_BUFFER (pfile)->system_header_p;
+  x->sysp = CPP_BUFFER (pfile)->inc->sysp;
   x->name_map = NULL;
 
   pfile->actual_dirs = x;
===================================================================
Index: cpphash.c
--- cpphash.c	2000/05/28 05:56:38	1.92
+++ cpphash.c	2000/06/21 18:18:47
@@ -1148,7 +1148,7 @@ special_symbol (pfile, hp)
     case T_STDC:
 #ifdef STDC_0_IN_SYSTEM_HEADERS
       ip = cpp_file_buffer (pfile);
-      if (ip && ip->system_header_p
+      if (ip && ip->inc->sysp
 	  && !cpp_defined (pfile, DSC("__STRICT_ANSI__")))
 	{
 	  CPP_PUTC (pfile, '0');
===================================================================
Index: cpphash.h
--- cpphash.h	2000/05/29 16:19:31	1.53
+++ cpphash.h	2000/06/21 18:18:47
@@ -53,28 +53,28 @@ struct file_name_list
 };
 #define ABSOLUTE_PATH ((struct file_name_list *)-1)
 
-/* This structure is used for the table of all includes.  It is
-   indexed by the `short name' (the name as it appeared in the
-   #include statement) which is stored in *nshort.  */
-struct ihash
+/* This structure is used for the table of all includes.  */
+struct include_file
 {
-  /* Next file with the same short name but a
-     different (partial) pathname). */
-  struct ihash *next_this_file;
-
-  /* Location of the file in the include search path.
-     Used for include_next and to detect redundant includes. */
-  struct file_name_list *foundhere;
-
-  unsigned int hash;		/* save hash value for future reference */
-  const char *nshort;		/* name of file as referenced in #include;
-				   points into name[]  */
+  const char *name;		/* actual path name of file */
   const cpp_hashnode *cmacro;	/* macro, if any, preventing reinclusion.  */
-  const char name[1];		/* (partial) pathname of file */
+  const struct file_name_list *foundhere;
+				/* location in search path where file was
+				   found, for #include_next */
+  int fd;			/* file descriptor possibly open on file */
+  unsigned char before;		/* file has been included before */
+  unsigned char sysp;		/* file is a system header */
 };
-typedef struct ihash IHASH;
-#define NEVER_REINCLUDE ((const cpp_hashnode *)-1)
 
+/* 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 not defined.  */
+#define NEVER_REREAD ((const cpp_hashnode *)-1)
+#define DO_NOT_REREAD(inc) \
+((inc)->cmacro && \
+ ((inc)->cmacro == NEVER_REREAD || (inc)->cmacro->type != T_VOID))
+
 /* Character classes.
    If the definition of `numchar' looks odd to you, please look up the
    definition of a pp-number in the C standard [section 6.4.8 of C99] */
@@ -143,10 +143,11 @@ extern unsigned char _cpp_IStable[256];
 
 #define CPP_PRINT_DEPS(PFILE) CPP_OPTION (PFILE, print_deps)
 #define CPP_TRADITIONAL(PFILE) CPP_OPTION (PFILE, traditional)
-#define CPP_PEDANTIC(PFILE) \
-  (CPP_OPTION (PFILE, pedantic) && !CPP_BUFFER (PFILE)->system_header_p)
+#define CPP_IN_SYSTEM_HEADER(PFILE) (cpp_file_buffer (PFILE)->inc->sysp)
+#define CPP_PEDANTIC(PF) \
+  (CPP_OPTION (PF, pedantic) && !CPP_IN_SYSTEM_HEADER (PF))
 #define CPP_WTRADITIONAL(PF) \
-  (CPP_OPTION (PF, warn_traditional) && !CPP_BUFFER (PF)->system_header_p)
+  (CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (PF))
 
 /* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.
    (Note that it is false while we're expanding macro *arguments*.) */
@@ -192,8 +193,8 @@ extern void _cpp_simplify_pathname	PARAM
 extern void _cpp_execute_include	PARAMS ((cpp_reader *, U_CHAR *,
 						 unsigned int, int,
 						 struct file_name_list *));
-extern void _cpp_init_include_hash	PARAMS ((cpp_reader *));
-extern const char *_cpp_fake_ihash	PARAMS ((cpp_reader *, const char *));
+extern void _cpp_init_include_table	PARAMS ((cpp_reader *));
+extern const char *_cpp_fake_include	PARAMS ((cpp_reader *, const char *));
 
 /* In cppexp.c */
 extern int _cpp_parse_expr		PARAMS ((cpp_reader *));
@@ -233,6 +234,10 @@ extern void _cpp_expand_token_space	PARA
 extern int _cpp_handle_directive	PARAMS ((cpp_reader *));
 extern void _cpp_unwind_if_stack	PARAMS ((cpp_reader *, cpp_buffer *));
 extern void _cpp_check_directive        PARAMS ((cpp_toklist *, cpp_token *));
+
+/* Utility routines and macros.  */
+#define xnew(T)		(T *) xmalloc (sizeof(T))
+#define xnewvec(T, N)	(T *) xmalloc (sizeof(T) * (N))
 
 /* These are inline functions instead of macros so we can get type
    checking.  */
===================================================================
Index: cppinit.c
--- cppinit.c	2000/05/28 05:56:38	1.82
+++ cppinit.c	2000/06/21 18:18:48
@@ -22,6 +22,7 @@ Foundation, 59 Temple Place - Suite 330,
 #include "config.h"
 #include "system.h"
 #include "hashtab.h"
+#include "splay-tree.h"
 #include "cpplib.h"
 #include "cpphash.h"
 #include "output.h"
@@ -551,7 +552,7 @@ cpp_reader_init (pfile)
     (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
 
   _cpp_init_macro_hash (pfile);
-  _cpp_init_include_hash (pfile);
+  _cpp_init_include_table (pfile);
 }
 
 /* Initialize a cpp_printer structure.  As a side effect, open the
@@ -605,7 +606,7 @@ cpp_cleanup (pfile)
     deps_free (pfile->deps);
 
   htab_delete (pfile->hashtab);
-  htab_delete (pfile->all_include_files);
+  splay_tree_delete (pfile->all_include_files);
 }
 
 
===================================================================
Index: cpplex.c
--- cpplex.c	2000/06/20 22:42:17	1.54
+++ cpplex.c	2000/06/21 18:18:49
@@ -211,7 +211,7 @@ cpp_pop_buffer (pfile)
   if (ACTIVE_MARK_P (pfile))
     cpp_ice (pfile, "mark active in cpp_pop_buffer");
 
-  if (buf->ihash)
+  if (buf->inc)
     {
       _cpp_unwind_if_stack (pfile, buf);
       if (buf->buf)
@@ -220,10 +220,17 @@ cpp_pop_buffer (pfile)
 	pfile->system_include_depth--;
       if (pfile->potential_control_macro)
 	{
-	  buf->ihash->cmacro = pfile->potential_control_macro;
+	  if (buf->inc->cmacro != NEVER_REREAD)
+	    buf->inc->cmacro = pfile->potential_control_macro;
 	  pfile->potential_control_macro = 0;
 	}
       pfile->input_stack_listing_current = 0;
+      /* If the file will not be included again, then close it.  */
+      if (DO_NOT_REREAD (buf->inc))
+	{
+	  close (buf->inc->fd);
+	  buf->inc->fd = -1;
+	}
     }
   else if (buf->macro)
     {
@@ -321,13 +328,13 @@ output_line_command (pfile, print, line)
   if (CPP_OPTION (pfile, cplusplus))
     fprintf (print->outf, "# %u \"%s\"%s%s%s\n", line, ip->nominal_fname,
 	     codes[change],
-	     ip->system_header_p ? " 3" : "",
-	     (ip->system_header_p == 2) ? " 4" : "");
+	     ip->inc->sysp ? " 3" : "",
+	     (ip->inc->sysp == 2) ? " 4" : "");
   else
 #endif
     fprintf (print->outf, "# %u \"%s\"%s%s\n", line, ip->nominal_fname,
 	     codes[change],
-	     ip->system_header_p ? " 3" : "");
+	     ip->inc->sysp ? " 3" : "");
   print->lineno = line;
 }
 
@@ -516,7 +523,7 @@ cpp_file_buffer (pfile)
   cpp_buffer *ip;
 
   for (ip = CPP_BUFFER (pfile); ip; ip = CPP_PREV_BUFFER (ip))
-    if (ip->ihash != NULL)
+    if (ip->inc != NULL)
       return ip;
   return NULL;
 }
@@ -914,7 +921,7 @@ skip_comment (pfile, m)
     }
   else if (m == '/' && PEEKC() == '/')
     {
-      if (CPP_BUFFER (pfile)->system_header_p)
+      if (CPP_IN_SYSTEM_HEADER (pfile))
 	{
 	  /* We silently allow C++ comments in system headers, irrespective
 	     of conformance mode, because lots of busted systems do that
@@ -2965,7 +2972,7 @@ _cpp_lex_line (pfile, list)
 		     irrespective of conformance mode, because lots of
 		     broken systems do that and trying to clean it up
 		     in fixincludes is a nightmare.  */
-		  if (buffer->system_header_p)
+		  if (CPP_IN_SYSTEM_HEADER (pfile))
 		    goto do_line_comment;
 		  else if (CPP_OPTION (pfile, cplusplus_comments))
 		    {
===================================================================
Index: cpplib.c
--- cpplib.c	2000/06/13 07:19:22	1.175
+++ cpplib.c	2000/06/21 18:18:49
@@ -214,7 +214,7 @@ _cpp_handle_directive (pfile)
 	return 0;
 
       if (CPP_PEDANTIC (pfile)
-	  && CPP_BUFFER (pfile)->ihash
+	  && CPP_BUFFER (pfile)->inc
 	  && ! CPP_OPTION (pfile, preprocessed))
 	cpp_pedwarn (pfile, "# followed by integer");
       i = T_LINE;
@@ -463,7 +463,7 @@ do_import (pfile)
   U_CHAR *token;
 
   if (CPP_OPTION (pfile, warn_import)
-      && !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning)
+      && !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning)
     {
       pfile->import_warning = 1;
       cpp_warning (pfile,
@@ -508,8 +508,8 @@ do_include_next (pfile)
      file like any other included source, but generate a warning.  */
   if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)))
     {
-      if (CPP_BUFFER (pfile)->ihash->foundhere != ABSOLUTE_PATH)
-	search_start = CPP_BUFFER (pfile)->ihash->foundhere->next;
+      if (CPP_BUFFER (pfile)->inc->foundhere)
+	search_start = CPP_BUFFER (pfile)->inc->foundhere->next;
     }
   else
     cpp_warning (pfile, "#include_next in primary source file");
@@ -603,23 +603,23 @@ do_line (pfile)
 	  if (action_number == 1)
 	    {
 	      pfile->buffer_stack_depth++;
-	      ip->system_header_p = 0;
+	      ip->inc->sysp = 0;
 	      read_line_number (pfile, &action_number);
 	    }
 	  else if (action_number == 2)
 	    {
 	      pfile->buffer_stack_depth--;
-	      ip->system_header_p = 0;
+	      ip->inc->sysp = 0;
 	      read_line_number (pfile, &action_number);
 	    }
 	  if (action_number == 3)
 	    {
-	      ip->system_header_p = 1;
+	      ip->inc->sysp = 1;
 	      read_line_number (pfile, &action_number);
 	    }
 	  if (action_number == 4)
 	    {
-	      ip->system_header_p = 2;
+	      ip->inc->sysp = 2;
 	      read_line_number (pfile, &action_number);
 	    }
 	}
@@ -628,10 +628,10 @@ do_line (pfile)
       
       if (strcmp ((const char *)fname, ip->nominal_fname))
 	{
-	  if (!strcmp ((const char *)fname, ip->ihash->name))
-	    ip->nominal_fname = ip->ihash->name;
+	  if (!strcmp ((const char *)fname, ip->inc->name))
+	    ip->nominal_fname = ip->inc->name;
 	  else
-	    ip->nominal_fname = _cpp_fake_ihash (pfile, (const char *)fname);
+	    ip->nominal_fname = _cpp_fake_include (pfile, (const char *)fname);
 	}
     }
   else if (token != CPP_VSPACE && token != CPP_EOF)
@@ -868,13 +868,13 @@ do_pragma_once (pfile)
 
   /* Allow #pragma once in system headers, since that's not the user's
      fault.  */
-  if (!ip->system_header_p)
+  if (!CPP_IN_SYSTEM_HEADER (pfile))
     cpp_warning (pfile, "#pragma once is obsolete");
       
   if (CPP_PREV_BUFFER (ip) == NULL)
     cpp_warning (pfile, "#pragma once outside include file");
   else
-    ip->ihash->cmacro = NEVER_REINCLUDE;
+    ip->inc->cmacro = NEVER_REREAD;
 
   return 1;
 }
@@ -978,7 +978,7 @@ do_pragma_system_header (pfile)
   if (CPP_PREV_BUFFER (ip) == NULL)
     cpp_warning (pfile, "#pragma system_header outside include file");
   else
-    ip->system_header_p = 1;
+    ip->inc->sysp = 1;
 
   return 1;
 }
===================================================================
Index: cpplib.h
--- cpplib.h	2000/05/29 16:19:32	1.99
+++ cpplib.h	2000/06/21 18:18:49
@@ -233,9 +233,9 @@ struct cpp_buffer
   /* Actual directory of this file, used only for "" includes */
   struct file_name_list *actual_dir;
 
-  /* Pointer into the include hash table.  Used for include_next and
+  /* Pointer into the include table.  Used for include_next and
      to record control macros. */
-  struct ihash *ihash;
+  struct include_file *inc;
 
   /* If the buffer is the expansion of a macro, this points to the
      macro's hash table entry.  */
@@ -248,9 +248,6 @@ struct cpp_buffer
   /* Line number at line_base (above). */
   unsigned int lineno;
 
-  /* True if this is a header file included using <FILENAME>.  */
-  char system_header_p;
-
   /* True if buffer contains escape sequences.
      Currently there are two kinds:
      "\r-" means following identifier should not be macro-expanded.
@@ -499,7 +496,7 @@ struct cpp_reader
   struct htab *hashtab;
 
   /* Hash table of other included files.  See cppfiles.c */
-  struct htab *all_include_files;
+  struct splay_tree_s *all_include_files;
 
   /* Chain of `actual directory' file_name_list entries,
      for "" inclusion. */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]