cpplib: rewrite of include file handling

Zack Weinberg zack@rabi.columbia.edu
Tue Nov 17 20:05:00 GMT 1998


This patch cleans up handling of #include in cpplib.  It uses the same
basic ideas as the current cccp code, but is designed somewhat
differently.  It bootstraps successfully, and builds glibc with no problem.

All else being equal, cpplib is still much slower than cccp.  Some
stats:  to compile glibc with identical configuration and compiler
options takes

1:42:47 - usr 4229.88 sys 868.86	1.1.1pre, cccp
2:28:33 - usr 6932.07 sys 854.58	CVS 11/15, cppmain

The difference is all 'usr' (calculation) time.  Unless there's a
reason why snapshot cc1 would be doing lots more crunching than 1.1.1
cc1 for identical options on x86, the slowdown is cpp's fault.  I
don't think there's been that much work added to the core compiler since
1.1?

I can see several more places to speed up cpplib, and will hopefully
be sending more patches soon.

zw

1998-11-17 22:22 -0500  Zack Weinberg  <zack@rabi.phys.columbia.edu>

	* cpplib.h: Delete struct import_file.  Add ihash element to
	struct cpp_buffer; delete dir element.  Delete
	dont_repeat_files and import_hash_table elements from
	cpp_reader; change all_include_files to a hash table.  Delete
	all foobar_include / last_foobar_include elements from struct
	cpp_options; put back four such: quote_include,
	bracket_include, system_include, after_include.  Redo struct
	file_name_list completely.  Add new structure type
	include_hash.  Add prototypes for merge_include_chains and
	include_hash.  Change prototypes for finclude,
	find_include_file, and append_include_chain to match changes
	below.

	* cppfiles.c (simplify_pathname, include_hash,
	remap_filename, merge_include_chains): New functions.
	(add_import, lookup_import, open_include_file): Removed.
	(INO_T_EQ): Define this (copied from cccp.c).
	(hack_vms_include_specification): Prototype it.
	(append_include_chain): Change calling convention; now takes
	only one directory at a time, and sets up the data structure
	itself.
	(redundant_include_p): Rewritten - this is now used for all
	include redundancy, whether by #ifndef, #import, or #pragma
	once.  Looks up things in the include hash table.  
	(file_cleanup): Decrement pfile->system_include_depth here if
	it's >0.
	(find_include_file): Calling convention changed; now passes
	around a struct include_hash instead of 3 separate parameters.
	Guts ripped out and replaced with new include_hash mechanism.
	(finclude): Calling convention changed as for
	find_include_file.  Error exits pulled out-of-line.  Reformat.
	(safe_read): Return a long, not an int.
	(deps_output): Don't recurse.

	* cpplib.c (is_system_include): Deleted.
	(path_include): Fix up call to append_include_chain.
	(do_include): Fix up calls to find_include_file and finclude.
	Clean up dependency output a bit.  Shorten obnoxiously lengthy
	#import warning message.  Don't decrement
	pfile->system_include_depth here.
	(do_pragma): Understand the include_hash structure.  Reformat.
	(do_endif): Correct handling of control macros.  Understand
	the include_hash.
	(cpp_start_read): Fix up calls to finclude.  Call
	merge_include_chains.
	(cpp_handle_option): Fix up calls to append_include_chain.
	Understand the four partial include chains.
	(cpp_finish): Add debugging code (#if 0-ed out) for the
	include_hash.
	(cpp_cleanup): Free the include_hash, not the import hash and
	the all_include and dont_repeat lists which no longer exist.

============================================================
Index: cppfiles.c
--- cppfiles.c	1998/11/07 13:00:15	1.2
+++ cppfiles.c	1998/11/18 04:04:10
@@ -28,335 +28,515 @@
 #include "cpplib.h"
 
 /* The entry points to this file are: find_include_file, finclude,
-   append_include_chain, deps_output, and file_cleanup.
+   include_hash, append_include_chain, deps_output, and file_cleanup.
    file_cleanup is only called through CPP_BUFFER(pfile)->cleanup,
    so it's static anyway. */
 
-static void add_import			PROTO ((cpp_reader *, int, char *));
-static int lookup_import		PROTO ((cpp_reader *, char *,
+static struct include_hash *redundant_include_p
+					PROTO ((cpp_reader *,
+						struct include_hash *,
 						struct file_name_list *));
-static int redundant_include_p		PROTO ((cpp_reader *, char *));
 static struct file_name_map *read_name_map	PROTO ((cpp_reader *, char *));
 static char *read_filename_string	PROTO ((int, FILE *));
-static int open_include_file		PROTO ((cpp_reader *, char *,
+static char *remap_filename 		PROTO ((cpp_reader *, char *,
 						struct file_name_list *));
-static int safe_read			PROTO ((int, char *, int));
+static long safe_read			PROTO ((int, char *, int));
+static void simplify_pathname		PROTO ((char *));
+#ifdef VMS
+static void hack_vms_include_specification PROTO ((char *));
+#endif
 
 /* Not safe to prototype these. */
 extern char *xmalloc();
 extern char *xrealloc();
 
-/* Append a chain of `struct file_name_list's
-   to the end of the main include chain.
-   FIRST is the beginning of the chain to append, and LAST is the end.  */
+/* Windows does not natively support inodes, and neither does MSDOS.
+   VMS has non-numeric inodes. */
+#ifdef VMS
+#define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a)))
+#elif (defined _WIN32 && !defined CYGWIN) || defined __MSDOS__
+#define INO_T_EQ(a, b) 0
+#else
+#define INO_T_EQ(a, b) ((a) == (b))
+#endif
 
+/* Append an entry for dir DIR to list LIST, simplifying it if
+   possible.  SYS says whether this is a system include directory.
+   *** DIR is modified in place.  It must be writable and permanently
+   allocated. LIST is a pointer to the head pointer, because we actually
+   *prepend* the dir, and reverse the list later (in merge_include_chains). */
 void
-append_include_chain (pfile, first, last)
+append_include_chain (pfile, list, dir, sysp)
      cpp_reader *pfile;
-     struct file_name_list *first, *last;
+     struct file_name_list **list;
+     char *dir;
+     int sysp;
 {
-  struct cpp_options *opts = CPP_OPTIONS (pfile);
-  struct file_name_list *dir;
-
-  if (!first || !last)
-    return;
-
-  if (opts->include == 0)
-    opts->include = first;
-  else
-    opts->last_include->next = first;
+  struct file_name_list *new;
+  struct stat st;
+  unsigned int len;
 
-  if (opts->first_bracket_include == 0)
-    opts->first_bracket_include = first;
+  dir = savestring (dir);
+  simplify_pathname (dir);
+  if (stat (dir, &st))
+    {
+      /* Dirs that don't exist are silently ignored. */
+      if (errno != ENOENT)
+	cpp_perror_with_name (pfile, dir);
+      return;
+    }
 
-  for (dir = first; ; dir = dir->next) {
-    int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
-    if (len > pfile->max_include_len)
-      pfile->max_include_len = len;
-    if (dir == last)
-      break;
-  }
+  if (!S_ISDIR (st.st_mode))
+    {
+      cpp_message (pfile, 1, "%s: %s: Not a directory", progname, dir);
+      return;
+    }
 
-  last->next = NULL;
-  opts->last_include = last;
-}
+  len = strlen(dir);
+  if (len > pfile->max_include_len)
+    pfile->max_include_len = len;
+  
+  new = (struct file_name_list *)xmalloc (sizeof (struct file_name_list));
+  new->name = dir;
+  new->nlen = len;
+  new->next = *list;
+  new->ino  = st.st_ino;
+  new->dev  = st.st_dev;
+  new->sysp = sysp;
+  new->name_map = NULL;
+
+  *list = new;
+}
+
+/* Merge the four include chains together in the order quote, bracket,
+   system, after.  Remove duplicate dirs (as determined by
+   INO_T_EQ()).  The system_include and after_include chains are never
+   referred to again after this function; all access is through the
+   bracket_include path.
 
-/* Add output to `deps_buffer' for the -M switch.
-   STRING points to the text to be output.
-   SPACER is ':' for targets, ' ' for dependencies, zero for text
-   to be inserted literally.  */
+   For the future: Check if the directory is empty (but
+   how?) and possibly preload the include hash. */
 
 void
-deps_output (pfile, string, spacer)
-     cpp_reader *pfile;
-     char *string;
-     int spacer;
+merge_include_chains (opts)
+     struct cpp_options *opts;
 {
-  int size;
+  struct file_name_list *prev, *next, *cur, *other;
+  struct file_name_list *quote, *brack, *systm, *after;
+  struct file_name_list *qtail, *btail, *stail, *atail;
+
+  qtail = opts->quote_include;
+  btail = opts->bracket_include;
+  stail = opts->system_include;
+  atail = opts->after_include;
+
+  /* Nreverse the four lists. */
+  prev = 0;
+  for (cur = qtail; cur; cur = next)
+    {
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
+    }
+  quote = prev;
 
-  if (!*string)
-    return;
+  prev = 0;
+  for (cur = btail; cur; cur = next)
+    {
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
+    }
+  brack = prev;
 
-#ifdef VMS
-  hack_vms_include_specification (string);
-#endif
+  prev = 0;
+  for (cur = stail; cur; cur = next)
+    {
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
+    }
+  systm = prev;
 
-  size = strlen (string);
+  prev = 0;
+  for (cur = atail; cur; cur = next)
+    {
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
+    }
+  after = prev;
+
+  /* Paste together bracket, system, and after include chains. */
+  if (stail)
+    stail->next = after;
+  else
+    systm = after;
+  if (btail)
+    btail->next = systm;
+  else
+    brack = systm;
 
-#ifndef MAX_OUTPUT_COLUMNS
-#define MAX_OUTPUT_COLUMNS 72
-#endif
-  if (spacer
-      && pfile->deps_column > 0
-      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
+  /* This is a bit tricky.
+     First we drop dupes from the quote-include list.
+     Then we drop dupes from the bracket-include list.
+     Finally, if qtail and brack are the same directory,
+     we cut out qtail.
+
+     We can't just merge the lists and then uniquify them because
+     then we may lose directories from the <> search path that should
+     be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux. It is however
+     safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written
+     -Ibar -I- -Ifoo -Iquux. */
+
+  for (cur = quote; cur; cur = cur->next)
     {
-      deps_output (pfile, " \\\n  ", 0);
-      pfile->deps_column = 0;
+      for (other = quote; other != cur; other = other->next)
+        if (INO_T_EQ (cur->ino, other->ino)
+	    && cur->dev == other->dev)
+          {
+	    prev->next = cur->next;
+	    free (cur->name);
+	    free (cur);
+	    cur = prev;
+	    break;
+	  }
+      prev = cur;
     }
+  qtail = prev;
 
-  if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
+  for (cur = brack; cur; cur = cur->next)
     {
-      pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
-      pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
-					      pfile->deps_allocated_size);
+      for (other = brack; other != cur; other = other->next)
+        if (INO_T_EQ (cur->ino, other->ino)
+	    && cur->dev == other->dev)
+          {
+	    prev->next = cur->next;
+	    free (cur->name);
+	    free (cur);
+	    cur = prev;
+	    break;
+	  }
+      prev = cur;
     }
-  if (spacer == ' ' && pfile->deps_column > 0)
-    pfile->deps_buffer[pfile->deps_size++] = ' ';
-  bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
-  pfile->deps_size += size;
-  pfile->deps_column += size;
-  if (spacer == ':')
-    pfile->deps_buffer[pfile->deps_size++] = ':';
-  pfile->deps_buffer[pfile->deps_size] = 0;
+
+  if (quote)
+    {
+      if (INO_T_EQ (qtail->ino, brack->ino) && qtail->dev == brack->dev)
+        {
+	  if (quote == qtail)
+	    {
+	      free (quote->name);
+	      free (quote);
+	      quote = brack;
+	    }
+	  else
+	    {
+	      cur = quote;
+	      while (cur->next != qtail)
+		  cur = cur->next;
+	      cur->next = brack;
+	      free (qtail->name);
+	      free (qtail);
+	    }
+	}
+      else
+	  qtail->next = brack;
+    }
+  else
+      quote = brack;
+
+  /* If opts->ignore_srcdir is not set, the first place to look for ""
+     includes is the current directory.  That's the directory that the
+     top file on the stack is in, NOT the directory the compiler is
+     running in.  (-I. always means the directory the compiler is
+     running in.) We prepend a special entry to the quote_include path
+     to handle this case; it has an empty string for a name.  simplify_path
+     ensures that a path to the cwd always comes out ".". */
+  if (!opts->ignore_srcdir)
+    {
+      cur = (struct file_name_list *)xmalloc (sizeof (struct file_name_list));
+
+      cur->name = "";
+      cur->ino = 0;
+      cur->dev = 0;
+      cur->sysp = 0;
+      cur->next = quote;
+      quote = cur;
+    }
+  
+  opts->quote_include = quote;
+  opts->bracket_include = brack;
+  opts->system_include = NULL;
+  opts->after_include = NULL;
 }
 
+/* Look up or add an entry to the table of all includes.  This table
+ is indexed by the name as it appears in the #include line.  The
+ ->next_this_file chain stores all different files with the same
+ #include name (there are at least three ways this can happen).  The
+ hash function could probably be improved a bit. */
+
+struct include_hash *
+include_hash (pfile, fname, add)
+     cpp_reader *pfile;
+     char *fname;
+     int add;
+{
+  unsigned int hash = 0;
+  struct include_hash *l, *m;
+  char *f = fname;
+
+  while (*f)
+    hash += *f++;
+
+  l = pfile->all_include_files[hash % ALL_INCLUDE_HASHSIZE];
+  m = 0;
+  for (; l; m = l, l = l->next)
+    if (!strcmp (l->nshort, fname))
+      return l;
+
+  if (!add)
+    return 0;
+  
+  l = (struct include_hash *) xmalloc (sizeof (struct include_hash));
+  l->next = NULL;
+  l->next_this_file = NULL;
+  l->foundhere = NULL;
+  l->buf = NULL;
+  l->limit = NULL;
+  if (m)
+    m->next = l;
+  else
+    pfile->all_include_files[hash % ALL_INCLUDE_HASHSIZE] = l;
+  
+  return l;
+}
+
+/* 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. */
+
+static struct include_hash *
+redundant_include_p (pfile, ihash, ilist)
+     cpp_reader *pfile;
+     struct include_hash *ihash;
+     struct file_name_list *ilist;
+{
+  struct file_name_list *l;
+  struct include_hash *i;
+
+  if (! ihash->foundhere)
+    return 0;
+  else
+  {
+    for (i = ihash; i; i = i->next_this_file)
+      for (l = ilist; l; l = l->next)
+	 if (i->foundhere == l)
+	   {
+	     if (l != ABSOLUTE_PATH && l->name[0] == '\0')
+	       {
+		   /* If this hash entry was included from the
+		      "current directory", we must verify that the
+		      "current directory" for this hash entry is the
+		      same as the "current directory" for the file
+		      being included. */
+		 cpp_buffer *b = CPP_BUFFER (pfile);
+		 char *end;
+		 size_t dl1, dl2;
+#ifndef VMS
+		 end = rindex (i->name, '/');
+#else
+		 end = rindex (i->name, ']');
+		 if (!end) end = rindex (i->name, ':');
+		 if (!end) end = rindex (i->name, '>');
+		 if (!end) end++;
+#endif
+		 if (end)
+		   dl1 = end - i->name;
+		 else
+		   dl1 = 0;
+
+		 while (!b->fname)
+		     b = CPP_PREV_BUFFER (b);
+#ifndef VMS
+		 end = rindex (b->fname, '/');
+#else
+		 end = rindex (b->fname, ']');
+		 if (!end) end = rindex (b->fname, ':');
+		 if (!end) end = rindex (b->fname, '>');
+		 if (!end) end++;
+#endif
+		 if (end)
+		   dl1 = end - b->fname;
+		 else
+		   dl1 = 0;
+
+		 if (dl1 != dl2 || strncmp (i->name, b->fname, dl1))
+		   continue;
+	       }
+
+	     /* The control_macro works like this: If it's NULL, the file
+		is to be included again.  If it's "", the file is never to
+		be included again.  If it's a string, the file is not to be
+		included again if the string is the name of a defined macro. */
+	     return (i->control_macro
+		     && (i->control_macro[0] == '\0'
+			 || cpp_lookup (pfile, i->control_macro, -1, -1)))
+		 ? (struct include_hash *)-1 : i;
+	   }
+    return 0;
+  }
+}
+
 static int
 file_cleanup (pbuf, pfile)
      cpp_buffer *pbuf;
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_reader *pfile;
 {
   if (pbuf->buf)
     {
       free (pbuf->buf);
       pbuf->buf = 0;
     }
+  if (pfile->system_include_depth)
+    pfile->system_include_depth--;
   return 0;
 }
 
+/* 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 1 if the file was included before (but needs to be read
+   again). */
 int
-find_include_file (pfile, fbeg, flen, fname,
-		   importing, search_start, foundhere)
+find_include_file (pfile, fname, search_start, ihash, before)
      cpp_reader *pfile;
-     char *fbeg;
-     unsigned long flen;
      char *fname;
-     int importing;
      struct file_name_list *search_start;
-     struct file_name_list **foundhere;
+     struct include_hash **ihash;
+     int *before;
 {
-  struct file_name_list *searchptr;
-  int f;
-    
-  /* If specified file name is absolute, just open it.  */
-
-  if (*fbeg == '/')
-  {
-    strcpy (fname, fbeg);
-#ifdef VMS
-    hack_vms_include_specification (fname);
-#endif
-    if (redundant_include_p (pfile, fname))
-      return -2;
-    if (importing)
-      f = lookup_import (pfile, fname, NULL_PTR);
-    else
-      f = open_include_file (pfile, fname, NULL_PTR);
-    if (f == -2)
-      return -2;	/* Already included this file */
-  }
-  else
-  {
-    /* Search directory path, trying to open the file.
-       Copy each filename tried into FNAME.  */
+  struct file_name_list *l, *m;
+  struct include_hash *ih, *jh;
+  int f, len;
+  char *name;
+  
+  ih = include_hash (pfile, fname, 1);
+  jh = redundant_include_p (pfile, ih,
+			    fname[0] == '/' ? ABSOLUTE_PATH : search_start);
 
-    for (searchptr = search_start; searchptr; searchptr = searchptr->next)
+  if (jh != 0)
     {
-      unsigned int l = 0;
-      if (searchptr->fname)
-      {
-	/* The empty string in a search path is ignored.
-	   This makes it possible to turn off entirely
-	   a standard piece of the list.  */
-	if (searchptr->fname[0] == 0)
-	  continue;
-
-	l = strlen (searchptr->fname);
+      *before = 1;
+      *ihash = jh;
 
-	bcopy (searchptr->fname, fname, l);
-	fname[l++] = '/';
-      }
-
-      bcopy (fbeg, &fname[l], flen);
-      fname[flen+l] = '\0';
-#ifdef VMS
-      hack_vms_include_specification (fname);
-#endif /* VMS */
-      /* ??? There are currently 3 separate mechanisms for avoiding processing
-	 of redundant include files: #import, #pragma once, and
-	 redundant_include_p.  It would be nice if they were unified.  */
-      if (redundant_include_p (pfile, fname))
+      if (jh == (struct include_hash *)-1)
 	return -2;
-      if (importing)
-	f = lookup_import (pfile, fname, searchptr);
       else
-	f = open_include_file (pfile, fname, searchptr);
-      if (f == -2)
-	return -2;			/* Already included this file */
-#ifdef EACCES
-      else if (f == -1 && errno == EACCES)
-	cpp_warning (pfile, "Header file %s exists, but is not readable",
-		     fname);
-#endif
-      if (f >= 0)
-	break;
+	return open (jh->name, O_RDONLY, 0666);
     }
-  }
 
-  if (f < 0)
+  if (ih->foundhere)
+    /* A file is already known by this name, but it's not the same file.
+       Allocate another include_hash block and add it to the next_this_file
+       chain. */
     {
-      /* A file that was not found.  */
-      bcopy (fbeg, fname, flen);
-      fname[flen] = 0;
+      jh = (struct include_hash *)xmalloc (sizeof (struct include_hash));
+      while (ih->next_this_file) ih = ih->next_this_file;
 
-      return -1;
-    }
-  else
+      ih->next_this_file = jh;
+      jh = ih;
+      ih = ih->next_this_file;
+
+      ih->next = NULL;
+      ih->next_this_file = NULL;
+      ih->buf = NULL;
+      ih->limit = NULL;
+    }
+  *before = 0;
+  *ihash = ih;
+  ih->nshort = savestring (fname);
+  ih->control_macro = NULL;
+  
+  /* If the pathname is absolute, just open it. */ 
+  if (name[0] == '/')
     {
-      /* Check to see if this include file is a once-only include file.
-	 If so, give up.  */
+      ih->foundhere = ABSOLUTE_PATH;
+      ih->name = ih->nshort;
+#ifdef VMS
+      hack_vms_include_specification (ih->name);
+#endif
+      return open (ih->name, O_RDONLY, 0666);
+    }
 
-      struct file_name_list *ptr;
+  /* Search directory path, trying to open the file. */
+  len = strlen (fname);
+  name = xmalloc (len + pfile->max_include_len + 2 + INCLUDE_LEN_FUDGE);
 
-      for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next)
-	  if (!strcmp (ptr->fname, fname))
+  for (l = search_start; l; l = l->next)
+    {
+      if (l->name[0])
+        {
+	  /* Real directory in search path. */
+	  bcopy (l->name, name, l->nlen);
+	  name[l->nlen] = '/';
+	  strcpy (&name[l->nlen+1], fname);
+	}
+      else
+	/* The empty string in l->name means to check the directory
+	   containing the current file. */
+        {
+	  char *dir, *limit;
+	  dir = CPP_BUFFER (pfile)->fname;
+	  limit = rindex (dir, '/');
+	  if (!limit)
+	      strcpy (name, fname);
+	  else
 	    {
-	      close (f);
-	      return -2;		/* This file was once'd.  */
+	      size_t dlen = limit - dir;
+	      if (dlen > pfile->max_include_len)
+		name = xrealloc (name, dlen + len + 2 + INCLUDE_LEN_FUDGE);
+
+	      bcopy (dir, name, dlen);
+	      name[dlen] = '/';
+	      strcpy (&name[dlen + 1], fname);
 	    }
+	}
+      simplify_pathname (name);
+#ifdef VMS
+      hack_vms_include_specification (name);
+#endif
+      if (CPP_OPTIONS (pfile)->remap)
+	name = remap_filename (pfile, name, l);
+      
+      f = open (name, O_RDONLY, 0666);
+#ifdef EACCES
+      if (f == -1 && errno == EACCES)
+	cpp_warning (pfile, "Header file %s exists, but is not readable",
+		     fname);
+#endif
+      if (f >= 0)
+        {
+	  ih->foundhere = l;
+	  ih->name = xrealloc (name, strlen (name)+1);
+	  return f;
+        }
     }
-
-    /* Record file on "seen" list for #import.  */
-    add_import (pfile, f, fname);
-
-    *foundhere = searchptr;
-    return f;
-}
-
-/* Return nonzero if there is no need to include file NAME
-   because it has already been included and it contains a conditional
-   to make a repeated include do nothing.  */
-
-static int
-redundant_include_p (pfile, name)
-     cpp_reader *pfile;
-     char *name;
-{
-  struct file_name_list *l = pfile->all_include_files;
-  for (; l; l = l->next)
-    if (! strcmp (name, l->fname)
-	&& l->control_macro
-	&& cpp_lookup (pfile, l->control_macro, -1, -1))
-      return 1;
-  return 0;
-}
-
-
-
-/* Maintain and search list of included files, for #import.  */
-
-/* Hash a file name for import_hash_table.  */
-
-static int 
-import_hash (f)
-     char *f;
-{
-  int val = 0;
-
-  while (*f) val += *f++;
-  return (val%IMPORT_HASH_SIZE);
-}
-
-/* Search for file FILENAME in import_hash_table.
-   Return -2 if found, either a matching name or a matching inode.
-   Otherwise, open the file and return a file descriptor if successful
-   or -1 if unsuccessful.  */
-
-static int
-lookup_import (pfile, filename, searchptr)
-     cpp_reader *pfile;
-     char *filename;
-     struct file_name_list *searchptr;
-{
-  struct import_file *i;
-  int h;
-  int hashval;
-  struct stat sb;
-  int fd;
-
-  hashval = import_hash (filename);
-
-  /* Attempt to find file in list of already included files */
-  i = pfile->import_hash_table[hashval];
-
-  while (i) {
-    if (!strcmp (filename, i->name))
-      return -2;		/* return found */
-    i = i->next;
-  }
-  /* Open it and try a match on inode/dev */
-  fd = open_include_file (pfile, filename, searchptr);
-  if (fd < 0)
-    return fd;
-  fstat (fd, &sb);
-  for (h = 0; h < IMPORT_HASH_SIZE; h++) {
-    i = pfile->import_hash_table[h];
-    while (i) {
-      /* Compare the inode and the device.
-	 Supposedly on some systems the inode is not a scalar.  */
-      if (!bcmp ((char *) &i->inode, (char *) &sb.st_ino, sizeof (sb.st_ino))
-	  && i->dev == sb.st_dev) {
-        close (fd);
-        return -2;		/* return found */
+  
+    if (jh)
+      {
+	jh->next_this_file = NULL;
+	free (ih);
       }
-      i = i->next;
-    }
-  }
-  return fd;			/* Not found, return open file */
+    free (name);
+    *ihash = NULL;
+    return -1;
 }
 
-/* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
-
-static void
-add_import (pfile, fd, fname)
-     cpp_reader *pfile;
-     int fd;
-     char *fname;
-{
-  struct import_file *i;
-  int hashval;
-  struct stat sb;
-
-  hashval = import_hash (fname);
-  fstat (fd, &sb);
-  i = (struct import_file *)xmalloc (sizeof (struct import_file));
-  i->name = (char *)xmalloc (strlen (fname)+1);
-  strcpy (i->name, fname);
-  bcopy ((char *) &sb.st_ino, (char *) &i->inode, sizeof (sb.st_ino));
-  i->dev = sb.st_dev;
-  i->next = pfile->import_hash_table[hashval];
-  pfile->import_hash_table[hashval] = i;
-}
-
 /* 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
@@ -434,7 +614,6 @@
   map_list_ptr = ((struct file_name_map_list *)
 		  xmalloc (sizeof (struct file_name_map_list)));
   map_list_ptr->map_list_name = savestring (dirname);
-  map_list_ptr->map_list_map = NULL;
 
   name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
   strcpy (name, dirname);
@@ -443,7 +622,7 @@
   strcat (name, FILE_NAME_MAP_FILE);
   f = fopen (name, "r");
   if (!f)
-    map_list_ptr->map_list_map = NULL;
+    map_list_ptr->map_list_map = (struct file_name_map *)-1;
   else
     {
       int ch;
@@ -493,220 +672,164 @@
   return map_list_ptr->map_list_map;
 }  
 
-/* Try to open include file FILENAME.  SEARCHPTR is the directory
-   being tried from the include file search path.  This function maps
-   filenames on file systems based on information read by
-   read_name_map.  */
+/* Remap NAME based on the file_name_map (if any) for LOC. */
 
-static int
-open_include_file (pfile, filename, searchptr)
+static char *
+remap_filename (pfile, name, loc)
      cpp_reader *pfile;
-     char *filename;
-     struct file_name_list *searchptr;
+     char *name;
+     struct file_name_list *loc;
 {
-  if (CPP_OPTIONS (pfile)->remap)
-    {
-      register struct file_name_map *map;
-      register char *from;
-      char *p, *dir;
+  struct file_name_map *map;
+  char *from;
+  char *p, *dir;
+
+  if (! loc->name_map)
+    loc->name_map = read_name_map (pfile,
+				   loc->name
+				   ? loc->name : ".");
 
-      if (searchptr && ! searchptr->got_name_map)
-	{
-	  searchptr->name_map = read_name_map (pfile,
-					       searchptr->fname
-					       ? searchptr->fname : ".");
-	  searchptr->got_name_map = 1;
-	}
+  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 = rindex (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;
 
-      /* First check the mapping for the directory we are using.  */
-      if (searchptr && searchptr->name_map)
-	{
-	  from = filename;
-	  if (searchptr->fname)
-	    from += strlen (searchptr->fname) + 1;
-	  for (map = searchptr->name_map; map; map = map->map_next)
-	    {
-	      if (! strcmp (map->map_from, from))
-		{
-		  /* Found a match.  */
-		  return open (map->map_to, O_RDONLY, 0666);
-		}
-	    }
-	}
+  if (p == name)
+    {
+      dir = ".";
+      from = name;
+    }
+  else
+    {
+      dir = (char *) alloca (p - name + 1);
+      bcopy (name, dir, p - name);
+      dir[p - name] = '\0';
+      from = p + 1;
+    }
+  
+  for (map = read_name_map (pfile, dir); map; map = map->map_next)
+    if (! strcmp (map->map_from, name))
+      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 = rindex (filename, '/');
-      if (! p)
-	p = filename;
-      if (searchptr
-	  && searchptr->fname
-	  && strlen (searchptr->fname) == (size_t) (p - filename)
-	  && ! strncmp (searchptr->fname, filename, p - filename))
-	{
-	  /* FILENAME is in SEARCHPTR, which we've already checked.  */
-	  return open (filename, O_RDONLY, 0666);
-	}
+  return name;
+}
 
-      if (p == filename)
-	{
-	  dir = ".";
-	  from = filename;
-	}
-      else
-	{
-	  dir = (char *) alloca (p - filename + 1);
-	  bcopy (filename, dir, p - filename);
-	  dir[p - filename] = '\0';
-	  from = p + 1;
-	}
-      for (map = read_name_map (pfile, dir); map; map = map->map_next)
-	if (! strcmp (map->map_from, from))
-	  return open (map->map_to, O_RDONLY, 0666);
-    }
-
-  return open (filename, O_RDONLY, 0666);
-}
-
-/* Process the contents of include file FNAME, already open on descriptor F,
-   with output to OP.
-   SYSTEM_HEADER_P is 1 if this file resides in any one of the known
-   "system" include directories (as decided by the `is_system_include'
-   function above).
-   DIRPTR is the link in the dir path through which this file was found,
-   or 0 if the file name was absolute or via the current directory.
-   Return 1 on success, 0 on failure.
+/* 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.
 
    The caller is responsible for the cpp_push_buffer.  */
 
 int
-finclude (pfile, f, fname, system_header_p, dirptr)
+finclude (pfile, fd, ihash)
      cpp_reader *pfile;
-     int f;
-     char *fname;
-     int system_header_p;
-     struct file_name_list *dirptr;
+     int fd;
+     struct include_hash *ihash;
 {
   struct stat st;
   size_t st_size;
-  long i;
-  int length;
-  cpp_buffer *fp;			/* For input stack frame */
-#if 0
-  int missing_newline = 0;
-#endif
+  long i, length;
+  cpp_buffer *fp;
 
-  if (fstat (f, &st) < 0)
-    {
-      cpp_perror_with_name (pfile, fname);
-      close (f);
-      cpp_pop_buffer (pfile);
-      return 0;
-    }
-
+  if (fstat (fd, &st) < 0)
+    goto perror_fail;
+  
   fp = CPP_BUFFER (pfile);
-  fp->nominal_fname = fp->fname = fname;
-#if 0
-  fp->length = 0;
-#endif
-  fp->dir = dirptr;
-  fp->system_header_p = system_header_p;
+  fp->nominal_fname = fp->fname = ihash->name;
+  fp->ihash = ihash;
+  fp->system_header_p = (ihash->foundhere != ABSOLUTE_PATH
+			 && ihash->foundhere->sysp);
   fp->lineno = 1;
   fp->colno = 1;
   fp->cleanup = file_cleanup;
 
-  if (S_ISREG (st.st_mode)) {
-    st_size = (size_t) st.st_size;
-    if (st_size != st.st_size || st_size + 2 < st_size) {
-      cpp_error (pfile, "file `%s' too large", fname);
-      close (f);
-      return 0;
-    }
-    fp->buf = (U_CHAR *) xmalloc (st_size + 2);
-    fp->alimit = fp->buf + st_size + 2;
-    fp->cur = fp->buf;
-
-    /* Read the file contents, knowing that st_size is an upper bound
-       on the number of bytes we can read.  */
-    length = safe_read (f, fp->buf, st_size);
-    fp->rlimit = fp->buf + length;
-    if (length < 0) goto nope;
-  }
-  else if (S_ISDIR (st.st_mode)) {
-    cpp_error (pfile, "directory `%s' specified in #include", fname);
-    close (f);
-    return 0;
-  } else {
-    /* Cannot count its file size before reading.
-       First read the entire file into heap and
-       copy them into buffer on stack.  */
-
-    size_t bsize = 2000;
-
-    st_size = 0;
-    fp->buf = (U_CHAR *) xmalloc (bsize + 2);
-
-    for (;;) {
-      i = safe_read (f, fp->buf + st_size, bsize - st_size);
-      if (i < 0)
-	goto nope;      /* error! */
-      st_size += i;
-      if (st_size != bsize)
-	break;	/* End of file */
-      bsize *= 2;
-      fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
+  if (S_ISREG (st.st_mode))
+    {
+      st_size = (size_t) st.st_size;
+      if (st_size != st.st_size || st_size + 2 < st_size)
+      {
+        cpp_error (pfile, "file `%s' too large", ihash->name);
+	goto fail;
+      }
+      fp->buf = (U_CHAR *) xmalloc (st_size + 2);
+      fp->alimit = fp->buf + st_size + 2;
+      fp->cur = fp->buf;
+      
+      /* Read the file contents, knowing that st_size is an upper bound
+	 on the number of bytes we can read.  */
+      length = safe_read (fd, fp->buf, st_size);
+      fp->rlimit = fp->buf + length;
+      if (length < 0)
+	  goto perror_fail;
     }
-    fp->cur = fp->buf;
-    length = st_size;
-  }
+  else if (S_ISDIR (st.st_mode))
+    {
+      cpp_pop_buffer (pfile);
+      cpp_error (pfile, "directory `%s' specified in #include", ihash->name);
+      goto fail;
+    }
+  else
+    {
+      /* Cannot count its file size before reading.
+	 First read the entire file into heap and
+	 copy them into buffer on stack.  */
+
+      size_t bsize = 2000;
+
+      st_size = 0;
+      fp->buf = (U_CHAR *) xmalloc (bsize + 2);
+
+      for (;;)
+        {
+	  i = safe_read (fd, fp->buf + st_size, bsize - st_size);
+	  if (i < 0)
+	    goto perror_fail;
+	  st_size += i;
+	  if (st_size != bsize)
+	    break;	/* End of file */
+	  bsize *= 2;
+	  fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
+	}
+      fp->cur = fp->buf;
+      length = st_size;
+    }
 
+  /* FIXME: Broken in presence of trigraphs (consider ??/<EOF>)
+     and doesn't warn about a missing newline. */
   if ((length > 0 && fp->buf[length - 1] != '\n')
-      /* Backslash-newline at end is not good enough.  */
-      || (length > 1 && fp->buf[length - 2] == '\\')) {
+      || (length > 1 && fp->buf[length - 2] == '\\'))
     fp->buf[length++] = '\n';
-#if 0
-    missing_newline = 1;
-#endif
-  }
+
   fp->buf[length] = '\0';
   fp->rlimit = fp->buf + length;
-
-  /* Close descriptor now, so nesting does not use lots of descriptors.  */
-  close (f);
-
-  /* Must do this before calling trigraph_pcp, so that the correct file name
-     will be printed in warning messages.  */
 
+  close (fd);
   pfile->input_stack_listing_current = 0;
-
-#if 0
-  if (!no_trigraphs)
-    trigraph_pcp (fp);
-#endif
-
-#if 0
-  rescan (op, 0);
-
-  if (missing_newline)
-    fp->lineno--;
-
-  if (CPP_PEDANTIC (pfile) && missing_newline)
-    pedwarn ("file does not end in newline");
-
-  indepth--;
-  input_file_stack_tick++;
-  free (fp->buf);
-#endif
   return 1;
 
- nope:
-
-  cpp_perror_with_name (pfile, fname);
-  close (f);
-  free (fp->buf);
-  return 1;
+ perror_fail:
+  cpp_pop_buffer (pfile);
+  cpp_error_from_errno (pfile, ihash->name);
+ fail:
+  close (fd);
+  return 0;
 }
 
 /* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
@@ -715,7 +838,7 @@
    otherwise return the actual number of bytes read,
    which must be LEN unless end-of-file was reached.  */
 
-static int
+static long
 safe_read (desc, ptr, len)
      int desc;
      char *ptr;
@@ -745,6 +868,183 @@
     left -= nchars;
   }
   return len - left;
+}
+
+/* Add output to `deps_buffer' for the -M switch.
+   STRING points to the text to be output.
+   SPACER is ':' for targets, ' ' for dependencies, zero for text
+   to be inserted literally.  */
+
+void
+deps_output (pfile, string, spacer)
+     cpp_reader *pfile;
+     char *string;
+     int spacer;
+{
+  int size;
+  int cr = 0;
+
+  if (!*string)
+    return;
+
+#ifdef VMS
+  hack_vms_include_specification (string);
+#endif
+
+  size = strlen (string);
+
+#ifndef MAX_OUTPUT_COLUMNS
+#define MAX_OUTPUT_COLUMNS 72
+#endif
+  if (pfile->deps_column > 0
+      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
+    {
+      size += 5;
+      cr = 1;
+      pfile->deps_column = 0;
+    }
+
+  if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
+    {
+      pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
+      pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
+					      pfile->deps_allocated_size);
+    }
+
+  if (cr)
+    {
+      bcopy (" \\\n  ", &pfile->deps_buffer[pfile->deps_size], 5);
+      pfile->deps_size += 5;
+    }
+  
+  if (spacer == ' ' && pfile->deps_column > 0)
+    pfile->deps_buffer[pfile->deps_size++] = ' ';
+  bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
+  pfile->deps_size += size;
+  pfile->deps_column += size;
+  if (spacer == ':')
+    pfile->deps_buffer[pfile->deps_size++] = ':';
+  pfile->deps_buffer[pfile->deps_size] = 0;
+}
+
+/* Simplify a path name in place, deleting redundant components.  This
+   reduces OS overhead and guarantees that equivalent paths compare
+   the same (modulo symlinks).
+
+   Transforms made:
+   foo/bar/../quux	foo/quux
+   foo/./bar		foo/bar
+   foo//bar		foo/bar
+   /../quux		/quux
+   //quux		//quux  (POSIX allows leading // as a namespace escape)
+
+   Guarantees no trailing slashes. All transforms reduce the length
+   of the string.
+ */
+static void
+simplify_pathname (char *path)
+{
+    char *from, *to;
+    char *base;
+    int absolute = 0;
+
+    from = to = path;
+
+    /* Remove redundant initial /s.  */
+    if (*from == '/')
+    {
+	absolute = 1;
+	to++;
+	from++;
+	if (*from == '/')
+	{
+	    if (*++from == '/')
+		/* 3 or more initial /s are equivalent to 1 /.  */
+		while (*++from == '/');
+	    else
+		/* On some hosts // differs from /; Posix allows this.  */
+		to++;
+	}
+    }
+    base = to;
+    
+    for (;;)
+    {
+	while (*from == '/')
+	    from++;
+
+	if (from[0] == '.' && from[1] == '/')
+	    from += 2;
+	else if (from[0] == '.' && from[1] == '\0')
+	    goto done;
+	else if (from[0] == '.' && from[1] == '.' && from[2] == '/')
+	{
+	    if (base == to)
+	    {
+		if (absolute)
+		    from += 3;
+		else
+		{
+		    *to++ = *from++;
+		    *to++ = *from++;
+		    *to++ = *from++;
+		    base = to;
+		}
+	    }
+	    else
+	    {
+		to -= 2;
+		while (to > base && *to != '/') to--;
+		if (*to == '/')
+		    to++;
+		from += 3;
+	    }
+	}
+	else if (from[0] == '.' && from[1] == '.' && from[2] == '\0')
+	{
+	    if (base == to)
+	    {
+		if (!absolute)
+		{
+		    *to++ = *from++;
+		    *to++ = *from++;
+		}
+	    }
+	    else
+	    {
+		to -= 2;
+		while (to > base && *to != '/') to--;
+		if (*to == '/')
+		    to++;
+	    }
+	    goto done;
+	}
+	else
+	    /* Copy this component and trailing /, if any.  */
+	    while ((*to++ = *from++) != '/')
+	    {
+		if (!to[-1])
+		{
+		    to--;
+		    goto done;
+		}
+	    }
+	
+    }
+    
+ done:
+    /* Trim trailing slash */
+    if (to[0] == '/' && (!absolute || to > path+1))
+	to--;
+
+    /* Change the empty string to "." so that stat() on the result
+       will always work. */
+    if (to == path)
+      *to++ = '.';
+    
+    *to = '\0';
+
+    return;
 }
 
 #ifdef VMS
============================================================
Index: cpplib.c
--- cpplib.c	1998/11/08 15:09:53	1.43
+++ cpplib.c	1998/11/18 04:04:10
@@ -214,7 +214,6 @@
 						DEFINITION *, DEFINITION *));
 static int compare_token_lists		PROTO ((struct arglist *,
 						struct arglist *));
-static int is_system_include		PROTO ((cpp_reader *, char *));
 static HOST_WIDE_INT eval_if_expression	PROTO ((cpp_reader *, U_CHAR *, int));
 static int change_newlines		PROTO ((U_CHAR *, int));
 static struct arglist *read_token_list	PROTO ((cpp_reader *, int *));
@@ -593,7 +592,6 @@
     while (1) {
       char *q = p;
       char *name;
-      struct file_name_list *dirtmp;
 
       /* Find the end of this name.  */
       while (*q != 0 && *q != PATH_SEPARATOR) q++;
@@ -609,14 +607,8 @@
 	name[q - p] = 0;
       }
 
-      dirtmp = (struct file_name_list *)
-	xmalloc (sizeof (struct file_name_list));
-      dirtmp->next = 0;		/* New one goes on the end */
-      dirtmp->control_macro = 0;
-      dirtmp->c_system_include_path = 0;
-      dirtmp->fname = name;
-      dirtmp->got_name_map = 0;
-      append_include_chain (pfile, dirtmp, dirtmp);
+      append_include_chain (pfile,
+			    &(CPP_OPTIONS (pfile)->bracket_include), name, 0);
 
       /* Advance past this name.  */
       p = q;
@@ -2948,16 +2940,15 @@
   int importing = (keyword->type == T_IMPORT);
   int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
   int angle_brackets = 0;	/* 0 for "...", 1 for <...> */
-  char *fname;		/* Dynamically allocated fname buffer */
-  char *fbeg, *fend;		/* Beginning and end of fname */
+  int before;  /* included before? */
   long flen;
+  char *fbeg, *fend;
 
   enum cpp_token token;
 
   /* Chain of dirs to search */
-  struct file_name_list *search_start = CPP_OPTIONS (pfile)->include;
-  struct file_name_list dsp;	/* First in chain, if #include "..." */
-  struct file_name_list *foundhere, *ptr;
+  struct include_hash *ihash;
+  struct file_name_list *search_start;
   
   long old_written = CPP_WRITTEN (pfile);
 
@@ -2976,17 +2967,7 @@
       && !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning)
     {
       pfile->import_warning = 1;
-      cpp_warning (pfile, "using `#import' is not recommended");
-      fprintf (stderr, "The fact that a certain header file need not be processed more than once\n");
-      fprintf (stderr, "should be indicated in the header file, not where it is used.\n");
-      fprintf (stderr, "The best way to do this is with a conditional of this form:\n\n");
-      fprintf (stderr, "  #ifndef _FOO_H_INCLUDED\n");
-      fprintf (stderr, "  #define _FOO_H_INCLUDED\n");
-      fprintf (stderr, "  ... <real contents of file> ...\n");
-      fprintf (stderr, "  #endif /* Not _FOO_H_INCLUDED */\n\n");
-      fprintf (stderr, "Then users can use `#include' any number of times.\n");
-      fprintf (stderr, "GNU C automatically avoids processing the file more than once\n");
-      fprintf (stderr, "when it is equipped with such a conditional.\n");
+      cpp_warning (pfile, "`#import' is obsolete, use an #ifdef wrapper in the header file");
     }
 
   pfile->parsing_include_directive++;
@@ -2999,71 +2980,17 @@
       fend = CPP_PWRITTEN (pfile) - 1;
       *fend = '\0';
       if (fbeg[-1] == '<')
-	{
 	  angle_brackets = 1;
-	  /* If -I-, start with the first -I dir after the -I-.  */
-	  if (CPP_OPTIONS (pfile)->first_bracket_include)
-	    search_start = CPP_OPTIONS (pfile)->first_bracket_include;
-	}
-      /* If -I- was specified, don't search current dir, only spec'd ones.  */
-      else if (! CPP_OPTIONS (pfile)->ignore_srcdir)
-	{
-	  cpp_buffer *fp = CPP_BUFFER (pfile);
-	  /* We have "filename".  Figure out directory this source
-	     file is coming from and put it on the front of the list.  */
-
-	  for ( ; fp != CPP_NULL_BUFFER (pfile); fp = CPP_PREV_BUFFER (fp))
-	    {
-	      int n;
-	      char *ep,*nam;
-
-	      if ((nam = fp->nominal_fname) != NULL)
-		{
-		  /* Found a named file.  Figure out dir of the file,
-		     and put it in front of the search list.  */
-		  dsp.next = search_start;
-		  search_start = &dsp;
-#ifndef VMS
-		  ep = rindex (nam, '/');
-#else				/* VMS */
-		  ep = rindex (nam, ']');
-		  if (ep == NULL) ep = rindex (nam, '>');
-		  if (ep == NULL) ep = rindex (nam, ':');
-		  if (ep != NULL) ep++;
-#endif				/* VMS */
-		  if (ep != NULL)
-		    {
-		      n = ep - nam;
-		      dsp.fname = (char *) alloca (n + 1);
-		      strncpy (dsp.fname, nam, n);
-		      dsp.fname[n] = '\0';
-		      if (n + INCLUDE_LEN_FUDGE > pfile->max_include_len)
-			pfile->max_include_len = n + INCLUDE_LEN_FUDGE;
-		    }
-		  else
-		    {
-		      dsp.fname = 0; /* Current directory */
-		    }
-		  dsp.got_name_map = 0;
-		  break;
-		}
-	    }
-	}
     }
 #ifdef VMS
   else if (token == CPP_NAME)
     {
-      /*
-       * Support '#include xyz' like VAX-C to allow for easy use of all the
-       * decwindow include files. It defaults to '#include <xyz.h>' (so the
-       * code from case '<' is repeated here) and generates a warning.
-       */
+      /* Support '#include xyz' like VAX-C to allow for easy use of
+       * all the decwindow include files. It defaults to '#include
+       * <xyz.h>' and generates a warning.  */
       cpp_warning (pfile,
 		   "VAX-C-style include specification found, use '#include <filename.h>' !");
       angle_brackets = 1;
-      /* If -I-, start with the first -I dir after the -I-.  */
-      if (CPP_OPTIONS (pfile)->first_bracket_include)
-	search_start = CPP_OPTIONS (pfile)->first_bracket_include;
 
       /* Append the missing `.h' to the name. */
       CPP_PUTS (pfile, ".h", 3)
@@ -3097,15 +3024,21 @@
       for (; fp != CPP_NULL_BUFFER (pfile); fp = CPP_PREV_BUFFER (fp))
 	if (fp->fname != NULL)
 	  {
-	    /* fp->dir is null if the containing file was specified with
-	       an absolute file name.  In that case, don't skip anything.  */
-	    if (fp->dir == SELF_DIR_DUMMY)
-	      search_start = CPP_OPTIONS (pfile)->include;
-	    else if (fp->dir)
-	      search_start = fp->dir->next;
+	    /* Don't skip anything if the containing file was found
+	       by an absolute path. */
+	    if (fp->ihash->foundhere == ABSOLUTE_PATH)
+	      search_start = angle_brackets
+		  ? CPP_OPTIONS (pfile)->bracket_include
+		  : CPP_OPTIONS (pfile)->quote_include;
+	    else
+	      search_start = fp->ihash->foundhere->next;
 	    break;
 	  }
     }
+  else
+    search_start = angle_brackets
+	? CPP_OPTIONS (pfile)->bracket_include
+	: CPP_OPTIONS (pfile)->quote_include;
 
   CPP_SET_WRITTEN (pfile, old_written);
 
@@ -3116,20 +3049,11 @@
       cpp_error (pfile, "empty file name in `#%s'", keyword->name);
       return 0;
     }
-
-  /* Allocate this permanently, because it gets stored in the definitions
-     of macros.  */
-  /* + 2 above for slash and terminating null.  */
-  fname = (char *) xmalloc (pfile->max_include_len + flen + 2);
 
-  fd = find_include_file (pfile, fbeg, flen, fname,
-			  importing, search_start, &foundhere);
+  fd = find_include_file (pfile, fbeg, search_start, &ihash, &before);
 
   if (fd == -2)
-    {
-      free (fname);
-      return 0;
-    }
+    return 0;
   
   if (fd == -1)
     {
@@ -3141,27 +3065,24 @@
 	    deps_output (pfile, fbeg, ' ');
 	  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_OPTIONS (pfile)->first_bracket_include)
-	        ptr = CPP_OPTIONS (pfile)->first_bracket_include;
+	      if (CPP_OPTIONS (pfile)->bracket_include)
+	        ptr = CPP_OPTIONS (pfile)->bracket_include;
 	      else
-		ptr = CPP_OPTIONS (pfile)->include;
-	      for (; ptr; ptr = ptr->next)
-		  if (ptr->fname)
-		    {
-		      char *p;
+	        ptr = CPP_OPTIONS (pfile)->quote_include;
 
-		      if (ptr->fname[0] == 0)
-			continue;
-		      p = (char *) alloca (strlen (ptr->fname)
-					   + strlen (fname) + 2);
-		      strcpy (p, ptr->fname);
-		      strcat (p, "/");
-		      strcat (p, fname);
-		      deps_output (pfile, p, ' ');
-		      break;
-		    }
+	      p = (char *) alloca (strlen (ptr->name)
+				   + strlen (fbeg) + 2);
+	      if (*ptr->name != '\0')
+	        {
+		  strcpy (p, ptr->name);
+		  strcat (p, "/");
+	        }
+	      strcat (p, fbeg);
+	      deps_output (pfile, p, ' ');
 	    }
 	}
       /* If -M was specified, and this header file won't be added to
@@ -3173,40 +3094,19 @@
       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);
+	cpp_warning (pfile, "No include path in which to find %s", fbeg);
       else if (search_start)
-	cpp_error_from_errno (pfile, fname);
+	cpp_error_from_errno (pfile, fbeg);
       else
-	cpp_error (pfile, "No include path in which to find %s", fname);
+	cpp_error (pfile, "No include path in which to find %s", fbeg);
 
-      free (fname);
       return 0;
     }
-
-  /* If we get here, we have a file to process. */
 
-  for (ptr = pfile->all_include_files; ptr; ptr = ptr->next)
-    if (!strcmp (ptr->fname, fname))
-      break;				/* This file was included before.  */
-
-  if (ptr == 0)
-    {
-      /* This is the first time for this file.  */
-      /* Add it to list of files included.  */
-
-      ptr = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
-      ptr->control_macro = 0;
-      ptr->c_system_include_path = 0;
-      ptr->next = pfile->all_include_files;
-      pfile->all_include_files = ptr;
-      ptr->fname = savestring (fname);
-      ptr->got_name_map = 0;
-
-      /* For -M, add this file to the dependencies.  */
-      if (CPP_PRINT_DEPS (pfile)
-	  > (angle_brackets || (pfile->system_include_depth > 0)))
-	deps_output (pfile, fname, ' ');
-    }
+  /* 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_output (pfile, ihash->name, ' ');
 
   /* Handle -H option.  */
   if (CPP_OPTIONS(pfile)->print_include_names)
@@ -3214,68 +3114,32 @@
       cpp_buffer *buf = CPP_BUFFER (pfile);
       while ((buf = CPP_PREV_BUFFER (buf)) != CPP_NULL_BUFFER (pfile))
 	putc ('.', stderr);
-      fprintf (stderr, "%s\n", fname);
+      fprintf (stderr, " %s\n", ihash->name);
     }
 
   /* Actually process the file */
+
+  if (importing)
+    ihash->control_macro = "";
+  
   if (cpp_push_buffer (pfile, NULL, 0) == NULL)
     {
       close (fd);
-      free (fname);
       return 0;
     }
-
+  
   if (angle_brackets)
-    pfile->system_include_depth++;
+    pfile->system_include_depth++;   /* Decremented in file_cleanup. */
 
-  if (finclude (pfile, fd, fname, is_system_include (pfile, fname),
-		foundhere != &dsp ? foundhere : SELF_DIR_DUMMY))
+  if (finclude (pfile, fd, ihash))
     {
       output_line_command (pfile, 0, enter_file);
       pfile->only_seen_white = 2;
     }
-  
-  if (angle_brackets)
-    pfile->system_include_depth--;
 
   return 0;
 }
 
-/* Return nonzero if the given FILENAME is an absolute pathname which
-   designates a file within one of the known "system" include file
-   directories.  We assume here that if the given FILENAME looks like
-   it is the name of a file which resides either directly in a "system"
-   include file directory, or within any subdirectory thereof, then the
-   given file must be a "system" include file.  This function tells us
-   if we should suppress pedantic errors/warnings for the given FILENAME.
-
-   The value is 2 if the file is a C-language system header file
-   for which C++ should (on most systems) assume `extern "C"'.  */
-
-static int
-is_system_include (pfile, filename)
-     cpp_reader *pfile;
-     register char *filename;
-{
-  struct file_name_list *searchptr;
-
-  for (searchptr = CPP_OPTIONS (pfile)->first_system_include; searchptr;
-       searchptr = searchptr->next)
-    if (searchptr->fname) {
-      register char *sys_dir = searchptr->fname;
-      register unsigned length = strlen (sys_dir);
-
-      if (! strncmp (sys_dir, filename, length) && filename[length] == '/')
-	{
-	  if (searchptr->c_system_include_path)
-	    return 2;
-	  else
-	    return 1;
-	}
-    }
-  return 0;
-}
-
 /*
  * Install a name in the assertion hash table.
  *
@@ -3673,7 +3537,6 @@
   if (!strncmp (buf, "once", 4))
     {
       cpp_buffer *ip = NULL;
-      struct file_name_list *new;
 
       /* Allow #pragma once in system headers, since that's not the user's
 	 fault.  */
@@ -3687,39 +3550,33 @@
 	  if (ip->fname != NULL)
 	    break;
 	}
-      
-      new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
-      new->next = pfile->dont_repeat_files;
-      new->fname = savestring (ip->fname);
-      new->control_macro = 0;
-      new->got_name_map = 0;
-      new->c_system_include_path = 0;
-      pfile->dont_repeat_files = new;
-    }
-
-  if (!strncmp (buf, "implementation", 14)) {
-    /* Be quiet about `#pragma implementation' for a file only if it hasn't
-       been included yet.  */
-    struct file_name_list *ptr;
-    U_CHAR *p = buf + 14, *fname, *inc_fname;
-    int fname_len;
-    SKIP_WHITE_SPACE (p);
-    if (*p == '\n' || *p != '\"')
-      return 0;
 
-    fname = p + 1;
-    p = (U_CHAR *) index (fname, '\"');
-    fname_len = p != NULL ? p - fname : strlen (fname);
-    
-    for (ptr = pfile->all_include_files; ptr; ptr = ptr->next) {
-      inc_fname = (U_CHAR *) rindex (ptr->fname, '/');
-      inc_fname = inc_fname ? inc_fname + 1 : (U_CHAR *) ptr->fname;
-      if (inc_fname && !strncmp (inc_fname, fname, fname_len))
-	cpp_warning (pfile,
-	   "`#pragma implementation' for `%s' appears after file is included",
+      if (CPP_PREV_BUFFER (ip) == CPP_NULL_BUFFER (pfile))
+	cpp_warning (pfile, "`#pragma once' outside include file");
+      else
+	ip->ihash->control_macro = "";  /* never repeat */
+    }
+
+  if (!strncmp (buf, "implementation", 14))
+    {
+      /* Be quiet about `#pragma implementation' for a file only if it hasn't
+	 been included yet.  */
+      struct include_hash *ptr;
+      U_CHAR *p = buf + 14, *fname;
+      SKIP_WHITE_SPACE (p);
+      if (*p == '\n' || *p != '\"')
+        return 0;
+
+      fname = p + 1;
+      p = (U_CHAR *) index (fname, '\"');
+      *p = '\0';
+
+      ptr = include_hash (pfile, fname, 0);
+      if (ptr)
+        cpp_warning (pfile,
+	  "`#pragma implementation' for `%s' appears after file is included",
 		     fname);
     }
-  }
 
   return 0;
 }
@@ -4227,31 +4084,15 @@
 
 	  if (c == EOF)
 	    {
-	      /* If we get here, this #endif ends a #ifndef
+	      /* This #endif ends a #ifndef
 		 that contains all of the file (aside from whitespace).
 		 Arrange not to include the file again
-		 if the macro that was tested is defined.
-
-		 Do not do this for the top-level file in a -include or any
-		 file in a -imacros.  */
-#if 0
-FIXME!
-	      if (indepth != 0
-		  && ! (indepth == 1 && pfile->no_record_file)
-		  && ! (pfile->no_record_file && no_output))
-#endif
-		{
-		  struct file_name_list *ifile = pfile->all_include_files;
-		  
-		  for ( ; ifile != NULL; ifile = ifile->next)
-		    {
-		      if (!strcmp (ifile->fname, CPP_BUFFER (pfile)->fname))
-			{
-			  ifile->control_macro = temp->control_macro;
-			  break;
-			}
-		    }
-		}
+		 if the macro that was tested is defined. */
+	      struct cpp_buffer *ip;
+	      for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
+		if (ip->fname != NULL)
+		  break;
+	      ip->ihash->control_macro = temp->control_macro;
 	    }
         }
       free (temp);
@@ -5003,6 +4844,7 @@
   char *p;
   int f;
   cpp_buffer *fp;
+  struct include_hash *ih_fake;
 
   /* The code looks at the defaults through this pointer, rather than through
      the constant structure above.  This pointer gets changed if an environment
@@ -5201,9 +5043,6 @@
     }
   }
 
-  append_include_chain (pfile, opts->before_system, opts->last_before_system);
-  opts->first_system_include = opts->before_system;
-
   /* Unless -fnostdinc,
      tack on the standard include file dirs to the specified list */
   if (!opts->no_standard_includes) {
@@ -5226,19 +5065,14 @@
 	  /* Does this dir start with the prefix?  */
 	  if (!strncmp (p->fname, default_prefix, default_len)) {
 	    /* Yes; change prefix and add to search list.  */
-	    struct file_name_list *new
-	      = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
-	    int this_len = strlen (specd_prefix) + strlen (p->fname) - default_len;
+	    int this_len = strlen (specd_prefix)
+			   + strlen (p->fname) - default_len;
 	    char *str = (char *) xmalloc (this_len + 1);
 	    strcpy (str, specd_prefix);
 	    strcat (str, p->fname + default_len);
-	    new->fname = str;
-	    new->control_macro = 0;
-	    new->c_system_include_path = !p->cxx_aware;
-	    new->got_name_map = 0;
-	    append_include_chain (pfile, new, new);
-	    if (opts->first_system_include == 0)
-	      opts->first_system_include = new;
+
+	    append_include_chain (pfile, &opts->system_include,
+				  fname, !p->cxx_aware);
 	  }
 	}
       }
@@ -5247,32 +5081,23 @@
       /* Some standard dirs are only for C++.  */
       if (!p->cplusplus
 	  || (opts->cplusplus && !opts->no_standard_cplusplus_includes)) {
-	struct file_name_list *new
-	  = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
-	new->control_macro = 0;
-	new->c_system_include_path = !p->cxx_aware;
-	new->fname = update_path (p->fname, p->component);
-	new->got_name_map = 0;
-	append_include_chain (pfile, new, new);
-	if (opts->first_system_include == 0)
-	  opts->first_system_include = new;
+	char *str = update_path (p->fname, p->component);
+	append_include_chain (pfile, &opts->system_include,
+			      str, !p->cxx_aware);
       }
     }
   }
 
-  /* Tack the after_include chain at the end of the include chain.  */
-  append_include_chain (pfile, opts->after_include, opts->last_after_include);
-  if (opts->first_system_include == 0)
-    opts->first_system_include = opts->after_include;
+  merge_include_chains (opts);
 
   /* With -v, print the list of dirs to search.  */
   if (opts->verbose) {
     struct file_name_list *p;
     fprintf (stderr, "#include \"...\" search starts here:\n");
-    for (p = opts->include; p; p = p->next) {
-      if (p == opts->first_bracket_include)
+    for (p = opts->quote_include; p; p = p->next) {
+      if (p == opts->bracket_include)
 	fprintf (stderr, "#include <...> search starts here:\n");
-      fprintf (stderr, " %s\n", p->fname);
+      fprintf (stderr, " %s\n", p->name);
     }
     fprintf (stderr, "End of search list.\n");
   }
@@ -5424,7 +5249,15 @@
   /* Must call finclude() on the main input before processing
      -include switches; otherwise the -included text winds up
      after the main input. */
-  if (!finclude (pfile, f, fname, 0, NULL_PTR))
+  ih_fake = (struct include_hash *) xmalloc (sizeof (struct include_hash));
+  ih_fake->next = 0;
+  ih_fake->next_this_file = 0;
+  ih_fake->foundhere = ABSOLUTE_PATH;  /* well sort of ... */
+  ih_fake->name = fname;
+  ih_fake->control_macro = 0;
+  ih_fake->buf = (char *)-1;
+  ih_fake->limit = 0;
+  if (!finclude (pfile, f, ih_fake))
     return 0;
   output_line_command (pfile, 0, same_file);
   pfile->only_seen_white = 2;
@@ -5437,6 +5270,7 @@
      means the -imacros files have to be done separately and first. */
   
   pfile->no_record_file++;
+  opts->no_output++;
   for (pend = opts->pending; pend; pend = pend->next)
     {
       if (pend->cmd != NULL)
@@ -5451,13 +5285,23 @@
 	        }
 	      if (!cpp_push_buffer (pfile, NULL, 0))
 	        return 0;
-	      opts->no_output++;
-	      if (finclude (pfile, fd, pend->arg, 0, NULL_PTR))
+
+	      ih_fake = (struct include_hash *)
+		  xmalloc (sizeof (struct include_hash));
+	      ih_fake->next = 0;
+	      ih_fake->next_this_file = 0;
+	      ih_fake->foundhere = ABSOLUTE_PATH;  /* well sort of ... */
+	      ih_fake->name = pend->arg;
+	      ih_fake->control_macro = 0;
+	      ih_fake->buf = (char *)-1;
+	      ih_fake->limit = 0;
+	      if (!finclude (pfile, fd, ih_fake))
 		cpp_scan_buffer (pfile);
-	      opts->no_output--;
+	      free (ih_fake);
 	    }
 	}
     }
+  opts->no_output--;
   opts->pending = nreverse_pending (opts->pending);
   for (pend = opts->pending; pend; pend = pend->next)
     {
@@ -5473,7 +5317,17 @@
 	        }
 	      if (!cpp_push_buffer (pfile, NULL, 0))
 	        return 0;
-	      if (finclude (pfile, fd, pend->arg, 0, NULL_PTR))
+
+	      ih_fake = (struct include_hash *)
+		  xmalloc (sizeof (struct include_hash));
+	      ih_fake->next = 0;
+	      ih_fake->next_this_file = 0;
+	      ih_fake->foundhere = ABSOLUTE_PATH;  /* well sort of ... */
+	      ih_fake->name = pend->arg;
+	      ih_fake->control_macro = 0;
+	      ih_fake->buf = (char *)-1;
+	      ih_fake->limit = 0;
+	      if (finclude (pfile, fd, ih_fake))
 	        output_line_command (pfile, 0, enter_file);
 	    }
 	}
@@ -5503,10 +5357,6 @@
   pfile->token_buffer = (U_CHAR *) xmalloc (pfile->token_buffer_size);
   CPP_SET_WRITTEN (pfile, 0);
 
-  pfile->system_include_depth = 0;
-  pfile->dont_repeat_files = 0;
-  pfile->all_include_files = 0;
-  pfile->max_include_len = 0;
   pfile->timebuf = NULL;
   pfile->only_seen_white = 1;
   pfile->buffer = CPP_NULL_BUFFER(pfile);
@@ -5652,131 +5502,121 @@
  	user_label_prefix = "";
       break;
 
+    case 'I':			/* Add directory to path for includes.  */
+      if (!strcmp (argv[i] + 2, "-"))
+        {
+	  if (! opts->ignore_srcdir)
+	    {
+	      opts->ignore_srcdir = 1;
+	      /* Don't use any preceding -I directories for #include <...>. */
+	      opts->quote_include = opts->bracket_include;
+	      opts->bracket_include = 0;
+	    }
+	}
+      else
+	{
+	  char *fname;
+	  if (argv[i][2] != 0)
+	    fname = argv[i] + 2;
+	  else if (i + 1 == argc)
+	    goto missing_dirname;
+	  else
+	    fname = argv[++i];
+	  append_include_chain (pfile, &opts->bracket_include, fname, 0);
+	}
+      break;
+
     case 'i':
-      if (!strcmp (argv[i], "-include")
-	  || !strcmp (argv[i], "-imacros")) {
-	if (i + 1 == argc)
-	  goto missing_filename;
-	else
-	  push_pending (pfile, argv[i], argv[i+1]), i++;
-      }
-      if (!strcmp (argv[i], "-iprefix")) {
-	if (i + 1 == argc)
-	  goto missing_filename;
-	else
-	  opts->include_prefix = argv[++i];
-      }
-      if (!strcmp (argv[i], "-ifoutput")) {
-	opts->output_conditionals = 1;
-      }
-      if (!strcmp (argv[i], "-isystem")) {
-	struct file_name_list *dirtmp;
-	
-	if (i + 1 == argc)
-	  goto missing_filename;
-	
-	dirtmp = (struct file_name_list *)
-	  xmalloc (sizeof (struct file_name_list));
-	dirtmp->next = 0;
-	dirtmp->control_macro = 0;
-	dirtmp->c_system_include_path = 1;
-	dirtmp->fname = (char *) xmalloc (strlen (argv[i+1]) + 1);
-	strcpy (dirtmp->fname, argv[++i]);
-	dirtmp->got_name_map = 0;
-	
-	if (opts->before_system == 0)
-	  opts->before_system = dirtmp;
-	else
-	  opts->last_before_system->next = dirtmp;
-	opts->last_before_system = dirtmp; /* Tail follows the last one */
-      }
+      /* Add directory to beginning of system include path, as a system
+	 include directory. */
+      if (!strcmp (argv[i], "-isystem"))
+        {
+	  if (i + 1 == argc)
+	    goto missing_filename;
+	  append_include_chain (pfile, &opts->system_include, argv[++i], 1);
+	}
       /* Add directory to end of path for includes,
 	 with the default prefix at the front of its name.  */
-      if (!strcmp (argv[i], "-iwithprefix")) {
-	struct file_name_list *dirtmp;
-	char *prefix;
-	
-	if (opts->include_prefix != 0)
-	  prefix = opts->include_prefix;
-	else {
-	  prefix = savestring (GCC_INCLUDE_DIR);
-	  /* Remove the `include' from /usr/local/lib/gcc.../include.  */
-	  if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
-	    prefix[strlen (prefix) - 7] = 0;
-	}
-	
-	dirtmp = (struct file_name_list *)
-	  xmalloc (sizeof (struct file_name_list));
-	dirtmp->next = 0;	/* New one goes on the end */
-	dirtmp->control_macro = 0;
-	dirtmp->c_system_include_path = 0;
-	if (i + 1 == argc)
-	  goto missing_dirname;
-	
-	dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
-					  + strlen (prefix) + 1);
-	strcpy (dirtmp->fname, prefix);
-	strcat (dirtmp->fname, argv[++i]);
-	dirtmp->got_name_map = 0;
-	
-	if (opts->after_include == 0)
-	  opts->after_include = dirtmp;
-	else
-	  opts->last_after_include->next = dirtmp;
-	opts->last_after_include = dirtmp; /* Tail follows the last one */
+      else if (!strcmp (argv[i], "-iwithprefix"))
+        {
+	  char *fname;
+	  if (i + 1 == argc)
+	    goto missing_dirname;
+	  ++i;
+
+	  if (opts->include_prefix != 0)
+	    {
+	      fname = xmalloc (strlen (opts->include_prefix)
+			       + strlen (argv[i]) + 1);
+	      strcpy (fname, opts->include_prefix);
+	      strcat (fname, argv[i]);
+	    }
+	  else
+	    {
+	      fname = xmalloc (strlen (GCC_INCLUDE_DIR)
+			       + strlen (argv[i]) + 1);
+	      strcpy (fname, GCC_INCLUDE_DIR);
+	      /* Remove the `include' from /usr/local/lib/gcc.../include.  */
+	      if (!strcmp (fname + strlen (fname) - 8, "/include"))
+		fname[strlen (fname) - 7] = 0;
+	      strcat (fname, argv[i]);
+	    }
+	  
+	  append_include_chain (pfile, &opts->system_include, fname, 0);
       }
       /* Add directory to main path for includes,
 	 with the default prefix at the front of its name.  */
-      if (!strcmp (argv[i], "-iwithprefixbefore")) {
-	struct file_name_list *dirtmp;
-	char *prefix;
-	
-	if (opts->include_prefix != 0)
-	  prefix = opts->include_prefix;
-	else {
-	  prefix = savestring (GCC_INCLUDE_DIR);
-	  /* Remove the `include' from /usr/local/lib/gcc.../include.  */
-	  if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
-	    prefix[strlen (prefix) - 7] = 0;
-	}
-	
-	dirtmp = (struct file_name_list *)
-	  xmalloc (sizeof (struct file_name_list));
-	dirtmp->next = 0;	/* New one goes on the end */
-	dirtmp->control_macro = 0;
-	dirtmp->c_system_include_path = 0;
-	if (i + 1 == argc)
-	  goto missing_dirname;
-	
-	dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
-					  + strlen (prefix) + 1);
-	strcpy (dirtmp->fname, prefix);
-	strcat (dirtmp->fname, argv[++i]);
-	dirtmp->got_name_map = 0;
-	
-	append_include_chain (pfile, dirtmp, dirtmp);
-      }
+      else if (!strcmp (argv[i], "-iwithprefix"))
+        {
+	  char *fname;
+	  if (i + 1 == argc)
+	    goto missing_dirname;
+	  ++i;
+
+	  if (opts->include_prefix != 0)
+	    {
+	      fname = xmalloc (strlen (opts->include_prefix)
+			       + strlen (argv[i]) + 1);
+	      strcpy (fname, opts->include_prefix);
+	      strcat (fname, argv[i]);
+	    }
+	  else
+	    {
+	      fname = xmalloc (strlen (GCC_INCLUDE_DIR)
+			       + strlen (argv[i]) + 1);
+	      strcpy (fname, GCC_INCLUDE_DIR);
+	      /* Remove the `include' from /usr/local/lib/gcc.../include.  */
+	      if (!strcmp (fname + strlen (fname) - 8, "/include"))
+		fname[strlen (fname) - 7] = 0;
+	      strcat (fname, argv[i]);
+	    }
+	  
+	  append_include_chain (pfile, &opts->bracket_include, fname, 0);
+        }
       /* Add directory to end of path for includes.  */
-      if (!strcmp (argv[i], "-idirafter")) {
-	struct file_name_list *dirtmp;
-	
-	dirtmp = (struct file_name_list *)
-	  xmalloc (sizeof (struct file_name_list));
-	dirtmp->next = 0;	/* New one goes on the end */
-	dirtmp->control_macro = 0;
-	dirtmp->c_system_include_path = 0;
-	if (i + 1 == argc)
-	  goto missing_dirname;
-	else
-	  dirtmp->fname = argv[++i];
-	dirtmp->got_name_map = 0;
-	
-	if (opts->after_include == 0)
-	  opts->after_include = dirtmp;
-	else
-	  opts->last_after_include->next = dirtmp;
-	opts->last_after_include = dirtmp; /* Tail follows the last one */
-      }
+      else if (!strcmp (argv[i], "-idirafter"))
+        {
+	  if (i + 1 == argc)
+	    goto missing_dirname;
+	  append_include_chain (pfile, &opts->after_include, argv[++i], 0);
+	}
+      else if (!strcmp (argv[i], "-include") || !strcmp (argv[i], "-imacros"))
+        {
+	  if (i + 1 == argc)
+	    goto missing_filename;
+	  else
+	    push_pending (pfile, argv[i], argv[i+1]), i++;
+        }
+      else if (!strcmp (argv[i], "-iprefix"))
+        {
+	  if (i + 1 == argc)
+	    goto missing_filename;
+	  else
+	      opts->include_prefix = argv[++i];
+	}
+      else if (!strcmp (argv[i], "-ifoutput"))
+	opts->output_conditionals = 1;
+
       break;
       
     case 'o':
@@ -6059,34 +5899,6 @@
       opts->dollars_in_ident = 0;
       break;
       
-    case 'I':			/* Add directory to path for includes.  */
-      {
-	struct file_name_list *dirtmp;
-	
-	if (! CPP_OPTIONS(pfile)->ignore_srcdir
-	    && !strcmp (argv[i] + 2, "-")) {
-	  CPP_OPTIONS (pfile)->ignore_srcdir = 1;
-	  /* Don't use any preceding -I directories for #include <...>.  */
-	  CPP_OPTIONS (pfile)->first_bracket_include = 0;
-	}
-	else {
-	  dirtmp = (struct file_name_list *)
-	    xmalloc (sizeof (struct file_name_list));
-	  dirtmp->next = 0;		/* New one goes on the end */
-	  dirtmp->control_macro = 0;
-	  dirtmp->c_system_include_path = 0;
-	  if (argv[i][2] != 0)
-	    dirtmp->fname = argv[i] + 2;
-	  else if (i + 1 == argc)
-	    goto missing_dirname;
-	  else
-	    dirtmp->fname = argv[++i];
-	  dirtmp->got_name_map = 0;
-	  append_include_chain (pfile, dirtmp, dirtmp);
-	}
-      }
-    break;
-    
     case 'n':
       if (!strcmp (argv[i], "-nostdinc"))
 	/* -nostdinc causes no default include directories.
@@ -6179,6 +5991,28 @@
 	    }
 	}
     }
+
+#if 0
+  /* Debugging: dump statistics on the include hash table. */
+  {
+      struct include_hash *x;
+      int i, j;
+
+      for(i = 0; i < ALL_INCLUDE_HASHSIZE; i++)
+      {
+	  x = pfile->all_include_files[i];
+	  j = 0;
+	  while(x)
+	  {
+	      j++;
+	      x = x->next;
+	  }
+	  fprintf(stderr, "%d/%d ", i, j);
+      }
+      fputc('\n', stderr);
+  }
+#endif
+  
 }
 
 /* Free resources used by PFILE.
@@ -6211,34 +6045,21 @@
       pfile->if_stack = temp->next;
       free (temp);
     }
-
-  while (pfile->dont_repeat_files)
-    {
-      struct file_name_list *temp = pfile->dont_repeat_files;
-      pfile->dont_repeat_files = temp->next;
-      free (temp->fname);
-      free (temp);
-    }
 
-  while (pfile->all_include_files)
+  for (i = ALL_INCLUDE_HASHSIZE; --i >= 0; )
     {
-      struct file_name_list *temp = pfile->all_include_files;
-      pfile->all_include_files = temp->next;
-      free (temp->fname);
-      free (temp);
-    }
-
-  for (i = IMPORT_HASH_SIZE; --i >= 0; )
-    {
-      register struct import_file *imp = pfile->import_hash_table[i];
+      struct include_hash *imp = pfile->all_include_files[i];
       while (imp)
 	{
-	  struct import_file *next = imp->next;
+	  struct include_hash *next = imp->next;
+#if 0
+	  /* This gets freed elsewhere - I think. */
 	  free (imp->name);
+#endif
 	  free (imp);
 	  imp = next;
 	}
-      pfile->import_hash_table[i] = 0;
+      pfile->all_include_files[i] = 0;
     }
 
   for (i = ASSERTION_HASHSIZE; --i >= 0; )
============================================================
Index: cpplib.h
--- cpplib.h	1998/11/08 15:09:55	1.12
+++ cpplib.h	1998/11/18 04:04:10
@@ -96,17 +96,6 @@
 /* This frees resources used by PFILE. */
 extern void cpp_cleanup PARAMS ((cpp_reader *PFILE));
 
-/* Maintain and search list of included files, for #import.  */
-
-#define IMPORT_HASH_SIZE 31
-
-struct import_file {
-  char *name;
-  ino_t inode;
-  dev_t dev;
-  struct import_file *next;
-};
-
 /* If we have a huge buffer, may need to cache more recent counts */
 #define CPP_LINE_BASE(BUF) ((BUF)->buf + (BUF)->line_base)
 
@@ -121,9 +110,10 @@
   /* Filename specified with #line command.  */
   char *nominal_fname;
 
-  /* Record where in the search path this file was found.
-     For #include_next.  */
-  struct file_name_list *dir;
+  /* Pointer into the include hash table.  Used for include_next and
+     to record control macros.
+     ->fname is an alias to ->ihash->fname. */
+  struct include_hash *ihash;
 
   long line_base;
   long lineno; /* Line number at CPP_LINE_BASE. */
@@ -185,20 +175,13 @@
   /* Current depth in #include directives that use <...>.  */
   int system_include_depth;
 
-  /* List of included files that contained #pragma once.  */
-  struct file_name_list *dont_repeat_files;
+  /* Hash table of other included files.  See cppfiles.c */
+#define ALL_INCLUDE_HASHSIZE 71
+  struct include_hash *all_include_files[ALL_INCLUDE_HASHSIZE];
 
-  /* List of other included files.
-     If ->control_macro if nonzero, the file had a #ifndef
-     around the entire contents, and ->control_macro gives the macro name.  */
-  struct file_name_list *all_include_files;
-
   /* Current maximum length of directory names in the search path
      for include files.  (Altered as we get more of them.)  */
-  int max_include_len;
-
-  /* Hash table of files already included with #include or #import.  */
-  struct import_file *import_hash_table[IMPORT_HASH_SIZE];
+  unsigned int max_include_len;
 
   struct if_stack *if_stack;
 
@@ -441,23 +424,12 @@
 
   char done_initializing;
 
-  struct file_name_list *include;	/* First dir to search */
-  /* First dir to search for <file> */
-  /* This is the first element to use for #include <...>.
-     If it is 0, use the entire chain for such includes.  */
-  struct file_name_list *first_bracket_include;
-  /* This is the first element in the chain that corresponds to
-     a directory of system header files.  */
-  struct file_name_list *first_system_include;
-  struct file_name_list *last_include;	/* Last in chain */
-
-  /* Chain of include directories to put at the end of the other chain.  */
-  struct file_name_list *after_include;
-  struct file_name_list *last_after_include;	/* Last in chain */
-
-  /* Chain to put at the start of the system include files.  */
-  struct file_name_list *before_system;
-  struct file_name_list *last_before_system;	/* Last in chain */
+  /* Search paths for include files.  system_include, after_include are
+     only used during option parsing. */
+  struct file_name_list *quote_include;	 /* First dir to search for "file" */
+  struct file_name_list *bracket_include;/* First dir to search for <file> */
+  struct file_name_list *system_include; /* First dir with system headers  */
+  struct file_name_list *after_include;  /* Headers to search after system */
 
   /* Directory prefix that should replace `/usr' in the standard
      include file directories.  */
@@ -506,22 +478,45 @@
 #define CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic)
 #define CPP_PRINT_DEPS(PFILE) (CPP_OPTIONS (PFILE)->print_deps)
 
+/* List of directories to look for include files in. */
 struct file_name_list
-  {
-    struct file_name_list *next;
-    char *fname;
-    /* If the following is nonzero, it is a macro name.
-       Don't include the file again if that macro is defined.  */
-    U_CHAR *control_macro;
-    /* If the following is nonzero, it is a C-language system include
-       directory.  */
-    int c_system_include_path;
-    /* Mapping of file names for this directory.  */
-    struct file_name_map *name_map;
-    /* Non-zero if name_map is valid.  */
-    int got_name_map;
-  };
+{
+  struct file_name_list *next;
+  char *name;
+  unsigned int nlen;
+  /* We use these to tell if the directory mentioned here is a duplicate
+     of an earlier directory on the search path. */
+  ino_t ino;
+  dev_t dev;
+  /* If the following is nonzero, it is a C-language system include
+     directory.  */
+  int sysp;
+  /* Mapping of file names for this directory.
+     Only used on MS-DOS and related platforms. */
+  struct file_name_map *name_map;
+};
+#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 include_hash
+{
+  struct include_hash *next;
+  /* Next file with the same short name but a
+     different (partial) pathname). */
+  struct include_hash *next_this_file;
+
+  /* Location of the file in the include search path.
+     Used for include_next */
+  struct file_name_list *foundhere;
+  char *name;		/* (partial) pathname of file */
+  char *nshort;		/* name of file as referenced in #include */
+  char *control_macro;	/* macro, if any, preventing reinclusion - see
+			   redundant_include_p */
+  char *buf, *limit;	/* for file content cache, not yet implemented */
+};
+    
 /* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
    via the same directory as the file that #included it.  */
 #define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
@@ -706,15 +701,17 @@
 
 /* In cppfiles.c */
 extern void append_include_chain	PROTO ((cpp_reader *,
-						struct file_name_list *,
-						struct file_name_list *));
-extern int finclude			PROTO ((cpp_reader *, int, char *,
-						int, struct file_name_list *));
+						struct file_name_list **,
+						char *, int));
+extern void merge_include_chains	PROTO ((struct cpp_options *));
 extern int find_include_file		PROTO ((cpp_reader *, char *,
-						unsigned long, char *, int,
 						struct file_name_list *,
-						struct file_name_list **));
+						struct include_hash **,
+						int *));
+extern int finclude			PROTO ((cpp_reader *, int,
+					        struct include_hash *));
 extern void deps_output			PROTO ((cpp_reader *, char *, int));
+extern struct include_hash *include_hash PROTO ((cpp_reader *, char *, int));
 
 /* Bleargh. */
 extern char *savestring			PROTO ((char *));



More information about the Gcc-patches mailing list