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]

cpplib: rewrite of include file handling, take two



This patch fixes a large number of bugs and crocks in the previous
version.  I can now bootstrap the compiler with all languages enabled
and --enable-cpplib.  I will be running a glibc compile tonight, but I
think it will work, so I'm sending this out now.

There are some regressions in the test suite for ix86-pc-linux-gnu:

- gcc.dg/cpp-mi.c:  The new redundant include handling scheme
doesn't work for "" includes found in the current directory.
Run this file through the preprocessor once with no special options,
and once with `-I. -I-'.  You'll see that it works in the second case,
and not the first.  I'm open to suggestions how to fix it - it's not
easy.

- g++.old-deja/various (test for excess errors): #include_next
generates a pedwarn when not in a system include directory.  System
include directories are only activated when the target is not marked
C++ aware.  linux-gnu is marked C++ aware, and egcs' limits.h uses
#include_next.  The fix for this is to separate the concepts of `C++
aware' and `system headers' - one for implicit extern "C", the other
for turning off pedwarns.  That would take big structural changes
though.  (Or we could just fix limits.h.)

Note that I have NOT tested with --enable-c-cpplib.  IMHO
--enable-c-cpplib is broken anyway, and I want to fix cpplib-as-cpp
first.

zw

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

	* cpplib.h: Delete struct import_file.  Add ihash element to
	struct cpp_buffer.  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): Remove all calls and #if 0
	out the definition.  It was being called incorrectly and at
	the wrong times.  Until a VMSie can look at this, it's better
	to not pretend to support 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/24 02:20:46
@@ -28,333 +28,447 @@
 #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 *));
 
+#if 0
+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;
-
-  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 (spacer
-      && pfile->deps_column > 0
-      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
+  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)
     {
-      deps_output (pfile, " \\\n  ", 0);
-      pfile->deps_column = 0;
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
     }
+  quote = prev;
 
-  if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
+  prev = 0;
+  for (cur = btail; 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);
+      next = cur->next;
+      cur->next = prev;
+      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;
-}
+  brack = prev;
 
-static int
-file_cleanup (pbuf, pfile)
-     cpp_buffer *pbuf;
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-{
-  if (pbuf->buf)
+  prev = 0;
+  for (cur = stail; cur; cur = next)
     {
-      free (pbuf->buf);
-      pbuf->buf = 0;
+      next = cur->next;
+      cur->next = prev;
+      prev = cur;
     }
-  return 0;
-}
+  systm = prev;
 
-int
-find_include_file (pfile, fbeg, flen, fname,
-		   importing, search_start, foundhere)
-     cpp_reader *pfile;
-     char *fbeg;
-     unsigned long flen;
-     char *fname;
-     int importing;
-     struct file_name_list *search_start;
-     struct file_name_list **foundhere;
-{
-  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.  */
-
-    for (searchptr = search_start; searchptr; searchptr = searchptr->next)
+  prev = 0;
+  for (cur = atail; cur; cur = next)
     {
-      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;
+      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;
 
-	l = strlen (searchptr->fname);
+  /* 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. */
 
-	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))
-	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;
+  for (cur = quote; cur; cur = cur->next)
+    {
+      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 (f < 0)
+  for (cur = brack; cur; cur = cur->next)
     {
-      /* A file that was not found.  */
-      bcopy (fbeg, fname, flen);
-      fname[flen] = 0;
-
-      return -1;
+      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;
     }
-  else
-    {
-      /* Check to see if this include file is a once-only include file.
-	 If so, give up.  */
-
-      struct file_name_list *ptr;
 
-      for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next)
-	  if (!strcmp (ptr->fname, fname))
+  if (quote)
+    {
+      if (INO_T_EQ (qtail->ino, brack->ino) && qtail->dev == brack->dev)
+        {
+	  if (quote == qtail)
 	    {
-	      close (f);
-	      return -2;		/* This file was once'd.  */
+	      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;
     }
-
-    /* Record file on "seen" list for #import.  */
-    add_import (pfile, f, fname);
-
-    *foundhere = searchptr;
-    return f;
-}
+  else
+      quote = brack;
 
-/* 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.  */
+  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. */
 
-static int
-redundant_include_p (pfile, name)
+struct include_hash *
+include_hash (pfile, fname, add)
      cpp_reader *pfile;
-     char *name;
+     char *fname;
+     int add;
 {
-  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;
+  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.
+
+   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"
 
-/* Maintain and search list of included files, for #import.  */
+   a/a.h:
+   #include "../b/b.h"
 
-/* Hash a file name for import_hash_table.  */
+   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 int 
-import_hash (f)
-     char *f;
+static struct include_hash *
+redundant_include_p (pfile, ihash, ilist)
+     cpp_reader *pfile;
+     struct include_hash *ihash;
+     struct file_name_list *ilist;
 {
-  int val = 0;
+  struct file_name_list *l;
+  struct include_hash *i;
 
-  while (*f) val += *f++;
-  return (val%IMPORT_HASH_SIZE);
-}
+  if (! ihash->foundhere)
+    return 0;
 
-/* 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.  */
+  for (i = ihash; i; i = i->next_this_file)
+    for (l = ilist; l; l = l->next)
+       if (i->foundhere == l)
+	 /* 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
-lookup_import (pfile, filename, searchptr)
+file_cleanup (pbuf, pfile)
+     cpp_buffer *pbuf;
      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 */
-      }
-      i = i->next;
+  if (pbuf->buf)
+    {
+      free (pbuf->buf);
+      pbuf->buf = 0;
     }
-  }
-  return fd;			/* Not found, return open file */
+  if (pfile->system_include_depth)
+    pfile->system_include_depth--;
+  return 0;
 }
 
-/* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
-
-static void
-add_import (pfile, fd, fname)
+/* 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, fname, search_start, ihash, before)
      cpp_reader *pfile;
-     int fd;
      char *fname;
+     struct file_name_list *search_start;
+     struct include_hash **ihash;
+     int *before;
 {
-  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;
+  struct file_name_list *l;
+  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);
+
+  if (jh != 0)
+    {
+      *before = 1;
+      *ihash = jh;
+
+      if (jh == (struct include_hash *)-1)
+	return -2;
+      else
+	return open (jh->name, O_RDONLY, 0666);
+    }
+
+  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. */
+    {
+      jh = (struct include_hash *)xmalloc (sizeof (struct include_hash));
+      while (ih->next_this_file) ih = ih->next_this_file;
+
+      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 (fname[0] == '/')
+    {
+      ih->foundhere = ABSOLUTE_PATH;
+      ih->name = ih->nshort;
+      return open (ih->name, O_RDONLY, 0666);
+    }
+
+  /* Search directory path, trying to open the file. */
+
+  /* The first entry in the search list may be a buffer-specific entry,
+     and its directory name may be longer than max_include_len.  Adjust
+     as appropriate. */
+ if (pfile->max_include_len < search_start->nlen)
+    pfile->max_include_len = search_start->nlen;
+  len = strlen (fname);
+  name = xmalloc (len + pfile->max_include_len + 2 + INCLUDE_LEN_FUDGE);
+
+  for (l = search_start; l; l = l->next)
+    {
+      bcopy (l->name, name, l->nlen);
+      name[l->nlen] = '/';
+      strcpy (&name[l->nlen+1], fname);
+      simplify_pathname (name);
+      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_error(pfile, "included file `%s' exists but is not readable",
+		    name);
+	  return -1;
+	}
+#endif
+
+      if (f >= 0)
+        {
+	  ih->foundhere = l;
+	  ih->name = xrealloc (name, strlen (name)+1);
+	  return f;
+        }
+    }
+  
+    if (jh)
+      {
+	jh->next_this_file = NULL;
+	free (ih);
+      }
+    free (name);
+    *ihash = (struct include_hash *)-1;
+    return -1;
 }
 
 /* The file_name_map structure holds a mapping of file names for a
@@ -434,7 +548,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 +556,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 +606,192 @@
   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);
+  /* The ->dir field is only used when ignore_srcdir is not in effect;
+     see do_include */
+  if (!CPP_OPTIONS (pfile)->ignore_srcdir)
+    {
+      char *last_slash;
+      fp->dir = savestring (fp->fname);
+      last_slash = rindex (fp->dir, '/');
+      if (last_slash)
+        {
+	  if (last_slash == fp->dir)
+	    {
+	      fp->dlen = 1;
+	      last_slash[1] = '\0';
+	    }
+	  else
+	    {
+	      fp->dlen = last_slash - fp->dir;
+	      *last_slash = '\0';
+	    }
+	}
+      else
+        {
+	  fp->dir[0] = '.';
+	  fp->dir[1] = '\0';
+	  fp->dlen = 1;
+	}
     }
-    fp->cur = fp->buf;
-    length = st_size;
-  }
 
+  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;
+    }
+  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 +800,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;
@@ -747,7 +832,194 @@
   return len - left;
 }
 
-#ifdef VMS
+/* 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;
+
+  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;
+
+#if defined _WIN32 || defined __MSDOS__
+    /* Convert all backslashes to slashes. */
+    for (from = path; *from; from++)
+	if (*from == '\\') *from = '/';
+    
+    /* Skip over leading drive letter if present. */
+    if (ISALPHA (path[0]) && path[1] == ':')
+	from = to = &path[2];
+    else
+	from = to = path;
+#else
+    from = to = path;
+#endif
+    
+    /* 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;
+}
+
+/* It is not clear when this should be used if at all, so I've
+   disabled it until someone who understands VMS can look at it. */
+#if 0
 
 /* Under VMS we need to fix up the "include" specification filename.
 
============================================================
Index: cpplib.c
--- cpplib.c	1998/11/23 09:20:32	1.44
+++ cpplib.c	1998/11/24 02:20:48
@@ -206,7 +206,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 *));
@@ -585,7 +584,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++;
@@ -601,14 +599,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;
@@ -2940,16 +2932,16 @@
   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;
+  struct file_name_list *srcdir = 0;  /* for "" includes */
 
   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);
 
@@ -2968,17 +2960,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++;
@@ -2991,71 +2973,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)
@@ -3081,6 +3009,16 @@
       skip_rest_of_line (pfile);
     }
 
+  CPP_SET_WRITTEN (pfile, old_written);
+
+  flen = fend - fbeg;
+
+  if (flen == 0)
+    {
+      cpp_error (pfile, "empty file name in `#%s'", keyword->name);
+      return 0;
+    }
+  
   /* For #include_next, skip in the search path
      past the dir in which the containing file was found.  */
   if (skip_dirs)
@@ -3089,39 +3027,55 @@
       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;
 	  }
     }
-
-  CPP_SET_WRITTEN (pfile, old_written);
+  else
+    search_start = angle_brackets
+	? CPP_OPTIONS (pfile)->bracket_include
+	: CPP_OPTIONS (pfile)->quote_include;
+
+  /* For "" includes when ignore_srcdir is off, tack the actual directory
+     of the current file onto the beginning of the search path.
+     The block must be permanently allocated since it may wind up
+     in the include hash. */
+  if (!angle_brackets 
+      && search_start == CPP_OPTIONS (pfile)->quote_include
+      && !CPP_OPTIONS (pfile)->ignore_srcdir)
+    {
+      srcdir = (struct file_name_list *)
+	  xmalloc (sizeof (struct file_name_list));
+      srcdir->next = CPP_OPTIONS (pfile)->quote_include;
+      srcdir->name = CPP_BUFFER (pfile)->dir;
+      srcdir->nlen = CPP_BUFFER (pfile)->dlen;
+      srcdir->sysp = 0;
+      srcdir->name_map = NULL;
 
-  flen = fend - fbeg;
+      search_start = srcdir;
+    }
 
-  if (flen == 0)
+  if (!search_start)
     {
-      cpp_error (pfile, "empty file name in `#%s'", keyword->name);
+      cpp_error (pfile, "No include path in which to find %s", fbeg);
       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 (srcdir
+      && (ihash == (struct include_hash *)-1 || srcdir != ihash->foundhere))
+    free (srcdir);
+  
   if (fd == -2)
-    {
-      free (fname);
-      return 0;
-    }
+    return 0;
   
   if (fd == -1)
     {
@@ -3133,27 +3087,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
@@ -3165,106 +3116,47 @@
       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 if (search_start)
-	cpp_error_from_errno (pfile, fname);
+	cpp_warning (pfile, "No include path in which to find %s", fbeg);
       else
-	cpp_error (pfile, "No include path in which to find %s", fname);
+	cpp_error_from_errno (pfile, fbeg);
 
-      free (fname);
       return 0;
     }
 
-  /* If we get here, we have a file to process. */
+  /* 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, ' ');
 
-  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, ' ');
-    }
-
   /* Handle -H option.  */
   if (CPP_OPTIONS(pfile)->print_include_names)
     {
       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;
 }
 
@@ -3665,7 +3557,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.  */
@@ -3679,40 +3570,37 @@
 	  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",
-		     fname);
+      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, *fcopy;
+      SKIP_WHITE_SPACE (p);
+      if (*p == '\n' || *p != '\"')
+        return 0;
+
+      fname = p + 1;
+      p = (U_CHAR *) index (fname, '\"');
+
+      fcopy = alloca (p - fname + 1);
+      bcopy (fname, fcopy, p - fname);
+      fcopy[p-fname] = '\0';
+
+      ptr = include_hash (pfile, fcopy, 0);
+      if (ptr)
+        cpp_warning (pfile,
+	  "`#pragma implementation' for `%s' appears after file is included",
+		     fcopy);
+    }
+
   return 0;
 }
 
@@ -4219,31 +4107,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);
@@ -4995,6 +4867,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
@@ -5193,9 +5066,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) {
@@ -5218,19 +5088,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);
 	  }
 	}
       }
@@ -5239,32 +5104,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");
   }
@@ -5416,7 +5272,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;
@@ -5429,6 +5293,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)
@@ -5443,13 +5308,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)
     {
@@ -5465,7 +5340,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);
 	    }
 	}
@@ -5495,10 +5380,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);
@@ -5644,131 +5525,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':
@@ -6051,34 +5922,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.
@@ -6171,6 +6014,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.
@@ -6203,34 +6068,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/24 02:20:48
@@ -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)
 
@@ -120,10 +109,14 @@
   char *fname;
   /* 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;
+  /* Actual directory of this file, used only for "" includes */
+  char *dir;
+  size_t dlen;
+
+  /* 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 +178,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 +427,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 +481,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 +704,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 *));


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