This is the mail archive of the gcc@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]
Other format: [Raw text]

#import, #pragma once yadda yadda mumble grumble


This patch is a complete rewrite of cppfiles.c in cpplib.  No function
went unchanged, and many were renamed along with some datatypes.  As a
result I'm not including a diff for cppfiles.c, I'm just copying the
new file verbatim.  I include a diff for other affected files.

Some features:

o Hash table of files and directories, instead of splay tree of paths.

o CPP now works perfectly in the presence of symlinks, hard links etc.
  as it no longer tries to second-guess the filesystem.  In other words,
  cpp_simplify_pathname() RIP.

o Improved caching algorithm that gets an immediate hit if a file has
  been included before.  The old code would still do intermediate lookups
  of all prior search path directories before the successful one, before
  the successful hit.  "" includes with e.g. the current directory preceding
  the <> chain get a hit from the <> chain if whatever proceeded it
  doesn't succeed.  This result is then cached for "" too.

o #import and #pragma once are therefore guaranteed to work as intended,
  and have therefore been undeprecated.  However, you still pay for your
  sins: #include with wrapper headers are generally more efficient and
  therefore still encouraged.  #import is more efficient than #pragma once.
  As a future patch I will contribute a new section in the CPP manual
  discussing these issues and file lookup efficiency.  Having said that,
  the implementation is not dumb and #import is reasonably efficient.
 
o Reduced system calls for the file system.  I've not done and test and
  counted yet (I'll do that over the next week) but because of the design
  I would be very surprised if they are not down substantially (say 20-40%).

o In my biased opinion, the code is cleaner and easier to understand.
  The only dodgy bit is PCH handling, which was dodgy anyway, and I
  think I've preserved semantics.  I intend to try to move most if not all
  PCH handling into the front end.

o Cleanup of -remap handling with bug fixes.  No more nasty linked list data
  structures.

o Fixes PRs 11569 and 11649.

o Half a dozen small bug fixes and I'm sure some new bugs.

However, the advantages of cpp_simplify_pathname have been lost.  It would
enable some cache hits, for e.g. #incldue <a/b> and #include <b> that
the current code cannot do.  It might have also had a beneficial effect
for network file systems since it would remove .. components in the
path.  However, these optimizations are unsafe in general and I don't
believe the minor benefit surpasses the loss of correctness.  I don't
have timings, but I would be surprised if the new code is slower than
the old anyway because of its better cache and reduced syscalls.

This patch also does quite a few xmallocs; maybe more than before.  I'll
try to improve this in future.  Follow-up patches over the next week will
fix documentation, and undeprecate #pragma once and #import in 3.3 branch.

Bootstrapped x86 NetBSD for C, ObjC and C++ with no regressions.

I hope this puts past endless discussions to rest at last.

Neil.

	* Makefile.in (LIBCPP_DEPS): Add HASHTAB_H.
	* cppfiles.c: Completely rewritten.
	* c-incpath.c (free_path, remove_duplicates, heads, tails, add_path):
	struct cpp_path is now struct cpp_dir.
	(remove_duplicates): Don't simplify path names.
	* c-opts.c (c_common_parse_file): cpp_read_next_file renamed
	cpp_stack_file.
	* cpphash.h: Include hashtab.h.
	(_cpp_file): Declare.
	(struct cpp_buffer): struct include_file is now struct _cpp_file,
	and struct cpp_path is now struct cpp_dir.  Rename members.
	(struct cpp_reader): Similarly.  New members once_only_files,
	file_hash, file_hash_entries, quote_ignores_source_dir,
	no_search_path, saw_pragma_once.  Remove all_include_files and
	max_include_len.  Make some members bool.
	(_cpp_mark_only_only): Renamed from _cpp_never_reread.
	(_cpp_stack_file): Renamed from _cpp_read_file.
	(_cpp_stack_include): Renamed from _cpp_execute_include.
	(_cpp_init_files): Renamed from _cpp_init_includes.
	(_cpp_cleanup_files): Renamed from _cpp_cleanup_includes.
	* cppinit.c (cpp_create_reader): Initialize no_search_path.  Update.
	(cpp_read_next_file): Rename and move to cppfiles.c.
	(cpp_read_main_file): Update.
	* cpplib.c (run_directive): Update for renamed members.
	(do_include_common, _cpp_pop_buffer): Update.
	(do_import): Undeprecate #import.
	(do_pragma_once): Undeprecate.  Use _cpp_mark_file_once_only.
	* cpplib.h: Remove file_name_map_list.
	(cpp_options): Remove map_list.
	(cpp_dir): Rename from cpp_path.  New datatype for name_map.
	(cpp_set_include_chains, cpp_stack_file, cpp_included): Update.
testsuite:
	* gcc.dg/cpp/include2.c: Only expect one message.

/* Part of CPP library.  File handling.
   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
   Written by Per Bothner, 1994.
   Based on CCCP program by Paul Rubin, June 1986
   Adapted to ANSI C, Richard Stallman, Jan 1987
   Split out of cpplib.c, Zack Weinberg, Oct 1998
   Reimplemented, Neil Booth, Jul 2003

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "intl.h"
#include "mkdeps.h"
#include <dirent.h>

/* Variable length record files on VMS will have a stat size that includes
   record control characters that won't be included in the read size.  */
#ifdef VMS
# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */
# define STAT_SIZE_RELIABLE(ST) ((ST).st_fab_rfm != FAB_C_VAR)
#else
# define STAT_SIZE_RELIABLE(ST) true
#endif

#ifdef __DJGPP__
  /* For DJGPP redirected input is opened in text mode.  */
#  define set_stdin_to_binary_mode() \
     if (! isatty (0)) setmode (0, O_BINARY)
#else
#  define set_stdin_to_binary_mode() /* Nothing */
#endif

#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef ENOTDIR
# define ENOTDIR 0
#endif

/* This structure represents a file searched for by CPP, whether it
   exists or not.  An instance may be pointed to by more than one
   file_hash_entry; at present no reference count is kept.  */
typedef struct _cpp_file _cpp_file;
struct _cpp_file
{
  /* Filename as given to #include or command line switch.  */
  const char *name;

  /* The full path used to find the file.  */
  const char *path;

  /* The full path of the pch file.  */
  const char *pchname;

  /* The file's path with the basename stripped, malloced.  NULL if it
     hasn't been calculated yet.  */
  const char *dir_name;

  /* Chain through #import-ed files or those  containing #pragma once.  */
  struct _cpp_file *once_only_next;

  /* The contents of NAME after calling read_file().  */
  const uchar *buffer;

  /* The macro, if any, preventing re-inclusion.  */
  const cpp_hashnode *cmacro;

  /* The directory in the search path where FILE was found.  Used for
     #include_next and determining whether a header is a system
     header.  Is NULL if the file was given as an absolute path, or
     opened with read_file.  */
  cpp_dir *dir;

  /* As filled in by stat(2) for the file.  */
  struct stat st;

  /* File descriptor.  Invalid if -1, otherwise open.  */
  int fd;

  /* Zero if this file was successfully opened and stat()-ed,
     otherwise errno obtained from failure.  */
  int err_no;

  /* Number of times the file has been stacked for preprocessing.  */
  unsigned short stack_count;

  /* If opened with #import.  */
  bool import;

  /* If contains #pragma once.  */
  bool pragma_once;

  /* If read() failed before.  */
  bool dont_read;

  /* If this file is the main file.  */
  bool main_file;

  /* If BUFFER above contains the true contents of the file.  */
  bool buffer_valid;

  /* 0: file not known to be a PCH.
     1: file is a PCH (on return from find_include_file).
     2: file is not and never will be a valid precompiled header.
     3: file is always a valid precompiled header.  */
  uchar pch;
};

/* A singly-linked list for all searches for a given file name, with
   its head pointed to by a slot in FILE_HASH.  The file name is what
   appeared between the quotes in a #include directive; it can be
   determined implicity from the hash table location or explicitly
   from FILE->fname.

   FILE is a structure containing details about the file that was
   found with that search, or details of how the search failed.

   START_DIR is the starting location of the search in the include
   chain.  The current directories for "" includes are also hashed in
   the hash table.  Files that are looked up without using a search
   path, such as absolute filenames and file names from the command
   line share a special starting directory so they don't get confused
   with normal include-chain lookups in the cache.

   If START_DIR is NULL then the entry is for a directory, not a file,
   and the directory is in DIR.  Since the starting point in a file
   lookup chain is never NULL, this means that simple pointer
   comparisons against START_DIR can be made to determine cache hits
   in file lookups.
*/
struct file_hash_entry
{
  struct file_hash_entry *next;
  cpp_dir *start_dir;
  union
  {
    _cpp_file *file;
    cpp_dir *dir;
  } u;
};

static bool open_file (_cpp_file *file);
static bool pch_open_file (cpp_reader *pfile, _cpp_file *file);
static bool open_file_in_dir (cpp_reader *pfile, _cpp_file *file);
static _cpp_file *find_file (cpp_reader *, const char *fname,
			     cpp_dir *start_dir, bool fake);
static bool read_file_guts (cpp_reader *pfile, _cpp_file *file);
static bool read_file (cpp_reader *pfile, _cpp_file *file);
static bool stack_file (cpp_reader *, _cpp_file *file, bool import);
static bool once_only_file_p (cpp_reader *, _cpp_file *file, bool import);
static struct cpp_dir *search_path_head (cpp_reader *, const char *fname,
				 int angle_brackets, enum include_type);
static const char *dir_name_of_file (_cpp_file *file);
static void open_file_failed (cpp_reader *pfile, _cpp_file *file);
static struct file_hash_entry *search_cache (struct file_hash_entry *head,
					     const cpp_dir *start_dir);
static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname);
static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp);
static void allocate_file_hash_entries (cpp_reader *pfile);
static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile);
static int report_missing_guard (void **slot, void *b);
static int hash_string_eq (const void *p, const void *q);
static char *read_filename_string (int ch, FILE *f);
static void read_name_map (cpp_dir *dir);
static char *remap_filename (cpp_reader *pfile, _cpp_file *file);
static char *append_file_to_dir (const char *fname, cpp_dir *dir);
static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname);
static bool include_pch_p (_cpp_file *file);

/* Given a filename in FILE->PATH, with the empty string interpreted
   as <stdin>, open it.

   On success FILE contains an open file descriptor and stat
   information for the file.  On failure the file descriptor is -1 and
   the appropriate errno is also stored in FILE.  Returns TRUE iff
   successful.

   We used to open files in nonblocking mode, but that caused more
   problems than it solved.  Do take care not to acquire a controlling
   terminal by mistake (this can't happen on sane systems, but
   paranoia is a virtue).

   Use the three-argument form of open even though we aren't
   specifying O_CREAT, to defend against broken system headers.

   O_BINARY tells some runtime libraries (notably DJGPP) not to do
   newline translation; we can handle DOS line breaks just fine
   ourselves.  */
static bool
open_file (_cpp_file *file)
{
  if (file->path[0] == '\0')
    {
      file->fd = 0;
      set_stdin_to_binary_mode ();
    }
  else
    file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);

  if (file->fd != -1)
    {
      if (fstat (file->fd, &file->st) == 0)
	{
	  if (!S_ISDIR (file->st.st_mode))
	    {
	      file->err_no = 0;
	      return true;
	    }

	  /* Ignore a directory and continue the search.  The file we're
	     looking for may be elsewhere in the search path.  */
	  errno = ENOENT;
	}

      close (file->fd);
      file->fd = -1;
    }

  file->err_no = errno;

  return false;
}

/* Temporary PCH intercept of opening a file.  */
static bool
pch_open_file (cpp_reader *pfile, _cpp_file *file)
{
  static const char extension[] = ".gch";
  const char *path = file->path;
  size_t len, flen;
  char *pchname;
  struct stat st;
  bool valid = false;

  /* No PCH on <stdin> or if not requested.  */
  if (file->name[0] == '\0' || !pfile->cb.valid_pch)
    return false;

  flen = strlen (path);
  len = flen + sizeof (extension);
  pchname = xmalloc (len);
  memcpy (pchname, path, flen);
  memcpy (pchname + flen, extension, sizeof (extension));

  if (stat (pchname, &st) == 0)
    {
      DIR *pchdir;
      struct dirent *d;
      size_t dlen, plen = len;

      if (!S_ISDIR (st.st_mode))
	valid = validate_pch (pfile, file, pchname);
      else if ((pchdir = opendir (pchname)) != NULL)
	{
	  pchname[plen - 1] = '/';
	  while ((d = readdir (pchdir)) != NULL)
	    {
	      dlen = strlen (d->d_name) + 1;
	      if (dlen + plen > len)
		{
		  len += dlen + 64;
		  pchname = xrealloc (pchname, len);
		}
	      memcpy (pchname + plen, d->d_name, dlen);
	      valid = validate_pch (pfile, file, pchname);
	      if (valid)
		break;
	    }
	  closedir (pchdir);
	}
    }

  if (valid)
    file->pchname = pchname;
  else
    free (pchname);

  return valid;
}

/* Try to open the path FILE->name appended to FILE->dir.  This is
   where remap and PCH intercept the file lookup process.  */
static bool
open_file_in_dir (cpp_reader *pfile, _cpp_file *file)
{
  char *path;

  if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file)))
    ;
  else
    path = append_file_to_dir (file->name, file->dir);

  file->path = path;
  if (pch_open_file (pfile, file))
    return true;

  if (open_file (file))
    return true;

  free (path);
  file->path = NULL;
  return false;
}

/* Given a filename FNAME search for such a file in the include path
   starting from START_DIR.  If FNAME is the empty string it is
   interpreted as STDIN if START_DIR is PFILE->no_seach_path.

   If the file is not found in the file cache fall back to the O/S and
   add the result to our cache.

   If the file was not found in the filesystem, or there was an error
   opening it, then ERR_NO is non-zero and FD is -1.  If the file was
   found, then ERR_NO is zero and FD could be -1 or an open file
   descriptor.  FD can be -1 if the file was found in the cache and
   had previously been closed.  To open it again pass the return value
   to open_file().
*/
static _cpp_file *
find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake)
{
  struct file_hash_entry *entry, **hash_slot;
  _cpp_file *file;

  /* Ensure we get no confusion between cached files and directories.  */
  if (start_dir == NULL)
    cpp_error (pfile, DL_ICE, "NULL directory in find_file");

  hash_slot = (struct file_hash_entry **)
    htab_find_slot (pfile->file_hash, fname, INSERT);

  /* First check the cache before we resort to memory allocation.  */
  entry = search_cache (*hash_slot, start_dir);
  if (entry)
    return entry->u.file;

  file = make_cpp_file (pfile, start_dir, fname);

  /* Try each path in the include chain.  */
  for (; !fake ;)
    {
      if (open_file_in_dir (pfile, file))
	break;

      if (file->err_no != ENOENT || (file->dir = file->dir->next) == NULL)
	{
	  open_file_failed (pfile, file);
	  break;
	}

      /* Only check the cache for the starting location (done above)
	 and the quote and bracket chain heads because there are no
	 other possible starting points for searches.  */
      if (file->dir != pfile->bracket_include
	  && file->dir != pfile->quote_include)
	continue;

      entry = search_cache (*hash_slot, file->dir);
      if (entry)
	{
	  /* Cache for START_DIR too, sharing the _cpp_file structure.  */
	  free ((char *) file->name);
	  free (file);
	  file = entry->u.file;
	  break;
	}
    }

  /* Store this new result in the hash table.  */
  entry = new_file_hash_entry (pfile);
  entry->next = *hash_slot;
  entry->start_dir = start_dir;
  entry->u.file = file;
  *hash_slot = entry;

  return file;
}

/* Read a file into FILE->buffer, returning true on success.

   If FILE->fd is something weird, like a block device, we don't want
   to read it at all.  Don't even try to figure out what something is,
   except for plain files and block devices, since there is no
   reliable portable way of doing this.

   FIXME: Flush file cache and try again if we run out of memory.  */
static bool
read_file_guts (cpp_reader *pfile, _cpp_file *file)
{
  ssize_t size, total, count;
  uchar *buf;
  bool regular;
  
  if (S_ISBLK (file->st.st_mode))
    {
      cpp_error (pfile, DL_ERROR, "%s is a block device", file->name);
      return false;
    }

  regular = S_ISREG (file->st.st_mode);
  if (regular)
    {
      /* off_t might have a wider range than ssize_t - in other words,
	 the max size of a file might be bigger than the address
	 space.  We can't handle a file that large.  (Anyone with
	 a single source file bigger than 2GB needs to rethink
	 their coding style.)  Some systems (e.g. AIX 4.1) define
	 SSIZE_MAX to be much smaller than the actual range of the
	 type.  Use INTTYPE_MAXIMUM unconditionally to ensure this
	 does not bite us.  */
      if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t))
	{
	  cpp_error (pfile, DL_ERROR, "%s is too large", file->name);
	  return false;
	}

      size = file->st.st_size;
    }
  else
    /* 8 kilobytes is a sensible starting size.  It ought to be bigger
       than the kernel pipe buffer, and it's definitely bigger than
       the majority of C source files.  */
    size = 8 * 1024;

  buf = xmalloc (size + 1);
  total = 0;
  while ((count = read (file->fd, buf + total, size - total)) > 0)
    {
      total += count;

      if (total == size)
	{
	  if (regular)
	    break;
	  size *= 2;
	  buf = xrealloc (buf, size + 1);
	}
    }

  if (count < 0)
    {
      cpp_errno (pfile, DL_ERROR, file->name);
      return false;
    }

  if (regular && total != size && STAT_SIZE_RELIABLE (file->st))
    cpp_error (pfile, DL_WARNING, "%s is shorter than expected", file->name);

  /* Shrink buffer if we allocated substantially too much.  */
  if (total + 4096 < size)
    buf = xrealloc (buf, total + 1);

  /* The lexer requires that the buffer be \n-terminated.  */
  buf[total] = '\n';

  file->buffer = buf;
  file->st.st_size = total;
  file->buffer_valid = true;

  return true;
}

/* Convenience wrapper around read_file_guts that opens the file if
   necessary and closes the file desciptor after reading.  FILE must
   have been passed through find_file() at some stage.  */
static bool
read_file (cpp_reader *pfile, _cpp_file *file)
{
  /* Skip if the file had a header guard and the macro is defined.  */
  if (file->cmacro && file->cmacro->type == NT_MACRO)
    return false;

  /* PCH files get dealt with immediately.  */
  if (include_pch_p (file))
    {
      pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname);
      close (file->fd);
      file->fd = -1;
      return false;
    }

  /* If we already have its contents in memory, succeed immediately.  */
  if (file->buffer_valid)
    return true;

  /* If an earlier read failed for some reason don't try again.  */
  if (file->dont_read || file->err_no)
    return false;

  if (file->fd == -1 && !open_file (file))
    {
      open_file_failed (pfile, file);
      return false;
    }

  file->dont_read = !read_file_guts (pfile, file);
  close (file->fd);
  file->fd = -1;

  return !file->dont_read;
}

/* Place the file referenced by FILE into a new buffer on the buffer
   stack if possible.  IMPORT is true if this stacking attempt is
   because of a #import directive.  Returns true if a buffer is
   stacked.  */
static bool
stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
{
  cpp_buffer *buffer;
  int sysp;
  const char *fname;

  if (once_only_file_p (pfile, file, import))
      return false;

  sysp = MAX ((pfile->map ? pfile->map->sysp : 0),
	      (file->dir ? file->dir->sysp : 0));

  /* Add the file to the dependencies on its first inclusion.  */
  if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count)
    {
      if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file))
	deps_add_dep (pfile->deps, file->name);
    }

  if (!read_file (pfile, file))
    return false;

  /* Clear buffer_valid since _cpp_clean_line messes it up.  */
  file->buffer_valid = false;
  file->stack_count++;

  /* Stack the buffer.  */
  buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
			    CPP_OPTION (pfile, preprocessed), 0);
  buffer->file = file;

  /* Initialize controlling macro state.  */
  pfile->mi_valid = true;
  pfile->mi_cmacro = 0;

  /* Generate the call back.  */
  fname = file->name;
  if (*fname == '\0')
    fname = "<stdin>";
  _cpp_do_file_change (pfile, LC_ENTER, fname, 1, sysp);

  return true;
}

/* Returns TRUE if FILE has been previously read and should not be
   read again.  */
static bool
once_only_file_p (cpp_reader *pfile, _cpp_file *file, bool import)
{
  _cpp_file *f;

  /* Nothing to check if this isn't #import and there haven't been any
     #pragma_once directives.  */
  if (!import && !pfile->saw_pragma_once)
    return false;

  /* Did this file contain #pragma once?  */
  if (file->pragma_once)
    return true;

  /* Are we #import-ing a previously #import-ed file?  */
  if (import)
    {
      if (file->import)
	return true;
      _cpp_mark_file_once_only (pfile, file, true);
    }

  /* Read the file contents now.  stack_file would do it later, and
     we're smart enough to not do it twice, so this is no loss.  */
  if (!read_file (pfile, file))
    return false;

  /* We may have #imported it under a different name, though.  Look
     for likely candidates and compare file contents to be sure.  */
  for (f = pfile->once_only_files; f; f = f->once_only_next)
    {
      if (f == file)
	continue;

      if (!f->pragma_once && !(f->import && import))
	continue;

      if (f->err_no == 0
	  && f->st.st_mtime == file->st.st_mtime
	  && f->st.st_size == file->st.st_size
	  && read_file (pfile, f)
	  /* Size might have changed in read_file().  */
	  && f->st.st_size == file->st.st_size
	  && !memcmp (f->buffer, file->buffer, f->st.st_size))
	return true;
    }

  return false;
}

/* Mark FILE to be included once only.  IMPORT is true if because of
   #import, otherwise it is assumed to be #pragma once.  */
void
_cpp_mark_file_once_only (cpp_reader *pfile, _cpp_file *file, bool import)
{
  if (import)
    file->import = true;
  else
    {
      pfile->saw_pragma_once = true;
      file->pragma_once = true;
    }

  /* Put it on the once-only list if it's not on there already (an
     earlier #include with a #pragma once might have put it on there
     already).  */
  if (file->once_only_next == NULL)
    {
      file->once_only_next = pfile->once_only_files;
      pfile->once_only_files = file;
    }
}

/* Return the directory from which searching for FNAME should start,
   condiering the directive TYPE and ANGLE_BRACKETS.  If there is
   nothing left in the path, returns NULL.  */
static struct cpp_dir *
search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets,
		  enum include_type type)
{
  cpp_dir *dir;
  _cpp_file *file;

  if (IS_ABSOLUTE_PATH (fname))
    return &pfile->no_search_path;

  file = pfile->buffer->file;

  /* For #include_next, skip in the search path past the dir in which
     the current file was found, but if it was found via an absolute
     path use the normal search logic.  */
  if (type == IT_INCLUDE_NEXT && file->dir)
    dir = file->dir->next;
  else if (angle_brackets)
    dir = pfile->bracket_include;
  else if (type == IT_CMDLINE)
    /* -include and -imacros use the #include "" chain with the
       preprocessor's cwd prepended.  */
    return make_cpp_dir (pfile, "./", false);
  else if (pfile->quote_ignores_source_dir)
    dir = pfile->quote_include;
  else
    return make_cpp_dir (pfile, dir_name_of_file (file), pfile->map->sysp);

  if (dir == NULL)
    cpp_error (pfile, DL_ERROR,
	       "no include path in which to search for %s", fname);

  return dir;
}

/* Strip the basename from the file's path.  It ends with a slash if
   of non-zero length.  Note that this procedure also works for
   <stdin>, which is represented by the empty string.  */
static const char *
dir_name_of_file (_cpp_file *file)
{
  if (!file->dir_name)
    {
      size_t len = lbasename (file->path) - file->path;
      char *dir_name = xmalloc (len + 1);

      memcpy (dir_name, file->path, len);
      dir_name[len] = '\0';
      file->dir_name = dir_name;
    }

  return file->dir_name;
}

/* Push an input buffer with the contents of FNAME, the empty string
   for standard input.  Return true if a buffer was stacked.  */
bool
cpp_stack_file (cpp_reader *pfile, const char *fname)
{
  struct cpp_dir *dir = &pfile->no_search_path;

  return stack_file (pfile, find_file (pfile, fname, dir, false), false);
}

/* Handles #include-family directives (distinguished by TYPE),
   including HEADER, and the command line -imacros and -include.
   Returns true if a buffer was stacked.  */
bool
_cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets,
		    enum include_type type)
{
  struct cpp_dir *dir;

  dir = search_path_head (pfile, fname, angle_brackets, type);
  if (!dir)
    return false;

  return stack_file (pfile, find_file (pfile, fname, dir, false),
		     type == IT_IMPORT);
}

/* Could not open FILE.  The complication is dependency output.  */
static void
open_file_failed (cpp_reader *pfile, _cpp_file *file)
{
  int sysp = pfile->map ? pfile->map->sysp: 0;
  bool print_dep = CPP_OPTION (pfile, deps.style) > !!sysp;

  errno = file->err_no;
  if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
    deps_add_dep (pfile->deps, file->name);
  else
    {
      /* If we are outputting dependencies but not for this file then
	 don't error because we can still produce correct output.  */
      if (CPP_OPTION (pfile, deps.style) && ! print_dep)
	cpp_errno (pfile, DL_WARNING, file->name);
      else
	cpp_errno (pfile, DL_ERROR, file->name);
    }
}

/* Search in the chain beginning at HEAD for a file whose search path
   started at START_DIR != NULL.  */
static struct file_hash_entry *
search_cache (struct file_hash_entry *head, const cpp_dir *start_dir)
{
  while (head && head->start_dir != start_dir)
    head = head->next;

  return head;
}

/* Allocate a new _cpp_file structure.  */
static _cpp_file *
make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname)
{
  _cpp_file *file;

  file = xcalloc (1, sizeof (_cpp_file));
  file->main_file = !pfile->buffer;
  file->fd = -1;
  file->dir = dir;
  file->name = xstrdup (fname);

  return file;
}

/* A hash of directory names.  The directory names are the path names
   of files which contain a #include "", the included file name is
   appended to this directories.

   To avoid duplicate entries we follow the convention that all
   non-empty directory names should end in a '/'.  DIR_NAME must be
   stored in permanently allocated memory.  */
static cpp_dir *
make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp)
{
  struct file_hash_entry *entry, **hash_slot;
  cpp_dir *dir;

  hash_slot = (struct file_hash_entry **)
    htab_find_slot (pfile->file_hash, dir_name, INSERT);

  /* Have we already hashed this directory?  */
  for (entry = *hash_slot; entry; entry = entry->next)
    if (entry->start_dir == NULL)
      return entry->u.dir;

  dir = xcalloc (1, sizeof (cpp_dir));
  dir->next = pfile->quote_include;
  dir->name = (char *) dir_name;
  dir->len = strlen (dir_name);
  dir->sysp = sysp;

  /* Store this new result in the hash table.  */
  entry = new_file_hash_entry (pfile);
  entry->next = *hash_slot;
  entry->start_dir = NULL;
  entry->u.dir = dir;
  *hash_slot = entry;

  return dir;
}

/* Create a new block of memory for file hash entries.  */
static void
allocate_file_hash_entries (cpp_reader *pfile)
{
  pfile->file_hash_entries_used = 0;
  pfile->file_hash_entries_allocated = 127;
  pfile->file_hash_entries = xmalloc
    (pfile->file_hash_entries_allocated * sizeof (struct file_hash_entry));
}

/* Return a new file hash entry.  */
static struct file_hash_entry *
new_file_hash_entry (cpp_reader *pfile)
{
  if (pfile->file_hash_entries_used == pfile->file_hash_entries_allocated)
    allocate_file_hash_entries (pfile);

  return &pfile->file_hash_entries[pfile->file_hash_entries_used++];
}

/* Returns TRUE if a file FNAME has ever been successfully opened.
   This routine is not intended to correctly handle filenames aliased
   by links or redundant . or .. traversals etc.  */
bool
cpp_included (cpp_reader *pfile, const char *fname)
{
  struct file_hash_entry *entry;

  entry = htab_find (pfile->file_hash, fname);

  while (entry && (entry->start_dir == NULL || entry->u.file->err_no))
    entry = entry->next;

  return entry != NULL;
}

/* Compare a string Q against a file hash entry P.  */
static int
hash_string_eq (const void *p, const void *q)
{
  struct file_hash_entry *entry = (struct file_hash_entry *) p;
  const char *fname = (const char *) q;
  const char *hname;

  if (entry->start_dir)
    hname = entry->u.file->name;
  else
    hname = entry->u.dir->name;

  return strcmp (hname, fname) == 0;
}

/* Initialize everything in this source file.  */
void
_cpp_init_files (cpp_reader *pfile)
{
  pfile->file_hash = htab_create_alloc (127, htab_hash_string, hash_string_eq,
					NULL, xcalloc, free);
  allocate_file_hash_entries (pfile);
}

/* Finalize everything in this source file.  */
void
_cpp_cleanup_files (cpp_reader *pfile)
{
  htab_delete (pfile->file_hash);
}

/* Enter a file name in the hash for the sake of cpp_included.  */
void
_cpp_fake_include (cpp_reader *pfile, const char *fname)
{
  find_file (pfile, fname, pfile->buffer->file->dir, true);
}

/* Not everyone who wants to set system-header-ness on a buffer can
   see the details of a buffer.  This is an exported interface because
   fix-header needs it.  */
void
cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc)
{
  int flags = 0;

  /* 1 = system header, 2 = system header to be treated as C.  */
  if (syshdr)
    flags = 1 + (externc != 0);
  _cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file,
		       SOURCE_LINE (pfile->map, pfile->line), flags);
}

/* Allow the client to change the current file.  Used by the front end
   to achieve pseudo-file names like <built-in>.
   If REASON is LC_LEAVE, then NEW_NAME must be NULL.  */
void
cpp_change_file (cpp_reader *pfile, enum lc_reason reason,
		 const char *new_name)
{
  _cpp_do_file_change (pfile, reason, new_name, 1, 0);
}

/* Callback function for htab_traverse.  */
static int
report_missing_guard (void **slot, void *b)
{
  struct file_hash_entry *entry = (struct file_hash_entry *) *slot;
  int *bannerp = (int *) b;

  /* Skip directories.  */
  if (entry->start_dir != NULL)
    {
      _cpp_file *file = entry->u.file;

      /* We don't want MI guard advice for the main file.  */
      if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file)
	{
	  if (*bannerp == 0)
	    {
	      fputs (_("Multiple include guards may be useful for:\n"),
		     stderr);
	      *bannerp = 1;
	    }

	  fputs (entry->u.file->path, stderr);
	  putc ('\n', stderr);
	}
    }

  return 0;
}

/* Report on all files that might benefit from a multiple include guard.
   Triggered by -H.  */
void
_cpp_report_missing_guards (cpp_reader *pfile)
{
  int banner = 0;

  htab_traverse (pfile->file_hash, report_missing_guard, &banner);
}

/* Locate HEADER, and determine whether it is newer than the current
   file.  If it cannot be located or dated, return -1, if it is
   newer, return 1, otherwise 0.  */
int
_cpp_compare_file_date (cpp_reader *pfile, const char *fname,
			int angle_brackets)
{
  _cpp_file *file;
  struct cpp_dir *dir;

  dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
  if (!dir)
    return -1;

  file = find_file (pfile, fname, dir, false);
  if (file->err_no)
    return -1;

  if (file->fd != -1)
    {
      close (file->fd);
      file->fd = -1;
    }

  return file->st.st_mtime > pfile->buffer->file->st.st_mtime;
}

/* Pushes the given file onto the buffer stack.  Returns nonzero if
   successful.  */
bool
cpp_push_include (cpp_reader *pfile, const char *fname)
{
  /* Make the command line directive take up a line.  */
  pfile->line++;
  return _cpp_stack_include (pfile, fname, false, IT_CMDLINE);
}

/* Do appropriate cleanup when a file INC's buffer is popped off the
   input stack.  */
void
_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file)
{
  /* Record the inclusion-preventing macro, which could be NULL
     meaning no controlling macro.  */
  if (pfile->mi_valid && file->cmacro == NULL)
    file->cmacro = pfile->mi_cmacro;

  /* Invalidate control macros in the #including file.  */
  pfile->mi_valid = false;

  if (file->buffer)
    {
      free ((void *) file->buffer);
      file->buffer = NULL;
    }
}

/* Set the include chain for "" to QUOTE, for <> to BRACKET.  If
   QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the
   directory of the including file.

   If BRACKET does not lie in the QUOTE chain, it is set to QUOTE.  */
void
cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket,
			int quote_ignores_source_dir)
{
  pfile->quote_include = quote;
  pfile->bracket_include = quote;
  pfile->quote_ignores_source_dir = quote_ignores_source_dir;

  for (; quote; quote = quote->next)
    {
      quote->name_map = NULL;
      quote->len = strlen (quote->name);
      if (quote == bracket)
	pfile->bracket_include = bracket;
    }
}

/* Append the file name to the directory to create the path, but don't
   turn / into // or // into ///; // may be a namespace escape.  */
static char *
append_file_to_dir (const char *fname, cpp_dir *dir)
{
  size_t dlen, flen;
  char *path;

  dlen = dir->len;
  flen = strlen (fname);
  path = xmalloc (dlen + 1 + flen + 1);
  memcpy (path, dir->name, dlen);
  if (dlen && path[dlen - 1] != '/')
    path[dlen++] = '/';
  memcpy (&path[dlen], fname, flen + 1);

  return path;
}

/* Read a space delimited string of unlimited length from a stdio
   file F.  */
static char *
read_filename_string (int ch, FILE *f)
{
  char *alloc, *set;
  int len;

  len = 20;
  set = alloc = xmalloc (len + 1);
  if (! is_space (ch))
    {
      *set++ = ch;
      while ((ch = getc (f)) != EOF && ! is_space (ch))
	{
	  if (set - alloc == len)
	    {
	      len *= 2;
	      alloc = xrealloc (alloc, len + 1);
	      set = alloc + len / 2;
	    }
	  *set++ = ch;
	}
    }
  *set = '\0';
  ungetc (ch, f);
  return alloc;
}

/* Read the file name map file for DIR.  */
static void
read_name_map (cpp_dir *dir)
{
  static const char FILE_NAME_MAP_FILE[] = "header.gcc";
  char *name;
  FILE *f;
  size_t len, count = 0, room = 9;

  len = dir->len;
  name = alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1);
  memcpy (name, dir->name, len);
  if (len && name[len - 1] != '/')
    name[len++] = '/';
  strcpy (name + len, FILE_NAME_MAP_FILE);
  f = fopen (name, "r");

  dir->name_map = xmalloc (room * sizeof (char *));

  /* Silently return NULL if we cannot open.  */
  if (f)
    {
      int ch;

      while ((ch = getc (f)) != EOF)
	{
	  char *to;

	  if (is_space (ch))
	    continue;

	  if (count + 2 > room)
	    {
	      room += 8;
	      dir->name_map = xrealloc (dir->name_map, room * sizeof (char *));
	    }

	  dir->name_map[count] = read_filename_string (ch, f);
	  while ((ch = getc (f)) != EOF && is_hspace (ch))
	    ;

	  to = read_filename_string (ch, f);
	  if (IS_ABSOLUTE_PATH (to))
	    dir->name_map[count + 1] = to;
	  else
	    {
	      dir->name_map[count + 1] = append_file_to_dir (to, dir);
	      free (to);
	    }

	  count += 2;
	  while ((ch = getc (f)) != '\n')
	    if (ch == EOF)
	      break;
	}

      fclose (f);
    }

  /* Terminate the list of maps.  */
  dir->name_map[count] = NULL;
}

/* Remap a FILE's name based on the file_name_map, if any, for
   FILE->dir.  If the file name has any directory separators,
   recursively check those directories too.  */
static char *
remap_filename (cpp_reader *pfile, _cpp_file *file)
{
  const char *fname, *p;
  char *new_dir;
  cpp_dir *dir;
  size_t index, len;

  dir = file->dir;
  fname = file->name;

  for (;;)
    {
      if (!dir->name_map)
	read_name_map (dir);

      for (index = 0; dir->name_map[index]; index += 2)
	if (!strcmp (dir->name_map[index], fname))
	    return xstrdup (dir->name_map[index + 1]);

      p = strchr (fname, '/');
      if (!p || p == fname)
	return NULL;

      len = dir->len + (p - fname + 1);
      new_dir = xmalloc (len + 1);
      memcpy (new_dir, dir->name, dir->len);
      memcpy (new_dir + dir->len, fname, p - fname + 1);
      new_dir[len] = '\0';

      dir = make_cpp_dir (pfile, new_dir, dir->sysp);
      fname = p + 1;
    }
}

/* Return true if FILE is usable by PCH.  */
static bool
include_pch_p (_cpp_file *file)
{
  return file->pch & 1;
}

/* Returns true if PCHNAME is a valid PCH file for FILE.  */
static bool
validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
{
  const char *saved_path = file->path;

  file->path = pchname;
  if (open_file (file))
    {
      if ((file->pch & 2) == 0)
	file->pch = pfile->cb.valid_pch (pfile, pchname, file->fd);

      if (!include_pch_p (file))
	{
	  close (file->fd);
	  file->fd = -1;
	}

      if (CPP_OPTION (pfile, print_include_names))
	{
	  unsigned int i;
	  for (i = 1; i < pfile->line_maps.depth; i++)
	    putc ('.', stderr);
	  fprintf (stderr, "%c %s\n",
		   include_pch_p (file) ? '!' : 'x', pchname);
	}
    }
  else
    file->pch = 2;

  file->path = saved_path;
  return include_pch_p (file);
}
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1128
diff -u -p -r1.1128 Makefile.in
--- Makefile.in	29 Jul 2003 19:49:51 -0000	1.1128
+++ Makefile.in	29 Jul 2003 20:37:05 -0000
@@ -2348,7 +2348,7 @@ LIBCPP_OBJS =	cpplib.o cpplex.o cppmacro
 		hashtable.o line-map.o mkdeps.o cpppch.o
 
 LIBCPP_DEPS =	$(CPPLIB_H) cpphash.h line-map.h hashtable.h intl.h \
-		$(OBSTACK_H) $(CONFIG_H) $(SYSTEM_H)
+		$(HASHTAB_H) $(OBSTACK_H) $(CONFIG_H) $(SYSTEM_H)
 
 # Most of the other archives built/used by this makefile are for
 # targets.  This one is strictly for the host.
Index: c-incpath.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-incpath.c,v
retrieving revision 1.8
diff -u -p -r1.8 c-incpath.c
--- c-incpath.c	19 Jul 2003 14:47:00 -0000	1.8
+++ c-incpath.c	29 Jul 2003 20:37:05 -0000
@@ -45,21 +45,21 @@ Foundation, 59 Temple Place - Suite 330,
 
 static void add_env_var_paths (const char *, int);
 static void add_standard_paths (const char *, const char *, int);
-static void free_path (struct cpp_path *, int);
+static void free_path (struct cpp_dir *, int);
 static void merge_include_chains (cpp_reader *, int);
-static struct cpp_path *remove_duplicates (cpp_reader *, struct cpp_path *,
-					   struct cpp_path *,
-					   struct cpp_path *, int);
+static struct cpp_dir *remove_duplicates (cpp_reader *, struct cpp_dir *,
+					   struct cpp_dir *,
+					   struct cpp_dir *, int);
 
 /* Include chains heads and tails.  */
-static struct cpp_path *heads[4];
-static struct cpp_path *tails[4];
+static struct cpp_dir *heads[4];
+static struct cpp_dir *tails[4];
 static bool quote_ignores_source_dir;
 enum { REASON_QUIET = 0, REASON_NOENT, REASON_DUP, REASON_DUP_SYS };
 
 /* Free an element of the include chain, possibly giving a reason.  */
 static void
-free_path (struct cpp_path *path, int reason)
+free_path (struct cpp_dir *path, int reason)
 {
   switch (reason)
     {
@@ -169,12 +169,12 @@ add_standard_paths (const char *sysroot,
    JOIN, unless it duplicates JOIN in which case the last path is
    removed.  Return the head of the resulting chain.  Any of HEAD,
    JOIN and SYSTEM can be NULL.  */
-static struct cpp_path *
-remove_duplicates (cpp_reader *pfile, struct cpp_path *head,
-		   struct cpp_path *system, struct cpp_path *join,
+static struct cpp_dir *
+remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,
+		   struct cpp_dir *system, struct cpp_dir *join,
 		   int verbose)
 {
-  struct cpp_path **pcur, *tmp, *cur;
+  struct cpp_dir **pcur, *tmp, *cur;
   struct stat st;
 
   for (pcur = &head; *pcur; )
@@ -182,7 +182,6 @@ remove_duplicates (cpp_reader *pfile, st
       int reason = REASON_QUIET;
 
       cur = *pcur;
-      cpp_simplify_path (cur->name);
 
       if (stat (cur->name, &st))
 	{
@@ -269,7 +268,7 @@ merge_include_chains (cpp_reader *pfile,
   /* If verbose, print the list of dirs to search.  */
   if (verbose)
     {
-      struct cpp_path *p;
+      struct cpp_dir *p;
 
       fprintf (stderr, _("#include \"...\" search starts here:\n"));
       for (p = heads[QUOTE];; p = p->next)
@@ -304,9 +303,9 @@ split_quote_chain (void)
 void
 add_path (char *path, int chain, int cxx_aware)
 {
-  struct cpp_path *p;
+  struct cpp_dir *p;
 
-  p = xmalloc (sizeof (struct cpp_path));
+  p = xmalloc (sizeof (struct cpp_dir));
   p->next = NULL;
   p->name = path;
   if (chain == SYSTEM || chain == AFTER)
Index: c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.80
diff -u -p -r1.80 c-opts.c
--- c-opts.c	28 Jul 2003 20:03:25 -0000	1.80
+++ c-opts.c	29 Jul 2003 20:37:05 -0000
@@ -1206,7 +1206,7 @@ c_common_parse_file (int set_yydebug ATT
 
 	  /* Reset cpplib's macros and start a new file.  */
 	  cpp_undef_all (parse_in);
-	  cpp_read_next_file (parse_in, in_fnames[file_index]);
+	  cpp_stack_file (parse_in, in_fnames[file_index]);
 	}
 
       finish_options(in_fnames[file_index]);
Index: cpphash.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpphash.h,v
retrieving revision 1.194
diff -u -p -r1.194 cpphash.h
--- cpphash.h	13 Jul 2003 17:34:17 -0000	1.194
+++ cpphash.h	29 Jul 2003 20:37:06 -0000
@@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330,
 #define GCC_CPPHASH_H
 
 #include "hashtable.h"
+#include "hashtab.h"
 
 #ifdef HAVE_ICONV
 #include <iconv.h>
@@ -36,6 +37,7 @@ struct directive;		/* Deliberately incom
 struct pending_option;
 struct op;
 struct strbuf;
+struct _cpp_file;
 
 typedef bool (*convert_f) (iconv_t, const unsigned char *, size_t,
 			   struct strbuf *);
@@ -281,9 +283,9 @@ struct cpp_buffer
 
   struct cpp_buffer *prev;
 
-  /* Pointer into the include table; non-NULL if this is a file
-     buffer.  Used for include_next and to record control macros.  */
-  struct include_file *inc;
+  /* Pointer into the file table; non-NULL if this is a file buffer.
+     Used for include_next and to record control macros.  */
+  struct _cpp_file *file;
 
   /* Value of if_stack at start of this file.
      Used to prohibit unmatched #endif (etc) in an include file.  */
@@ -314,7 +316,7 @@ struct cpp_buffer
 
   /* The directory of the this buffer's file.  Its NAME member is not
      allocated, so we don't need to worry about freeing it.  */
-  struct cpp_path dir;
+  struct cpp_dir dir;
 
   /* Used for buffer overlays by cpptrad.c.  */
   const uchar *saved_cur, *saved_rlimit;
@@ -355,8 +357,24 @@ struct cpp_reader
   const struct directive *directive;
 
   /* Search paths for include files.  */
-  struct cpp_path *quote_include;	/* "" */
-  struct cpp_path *bracket_include;	/* <> */
+  struct cpp_dir *quote_include;	/* "" */
+  struct cpp_dir *bracket_include;	/* <> */
+  struct cpp_dir no_search_path;	/* No path.  */
+
+  /* Chain of files that were #import-ed or contain #pragma once.  */
+  struct _cpp_file *once_only_files;
+
+  /* File and directory hash table.  */
+  htab_t file_hash;
+  struct file_hash_entry *file_hash_entries;
+  unsigned int file_hash_entries_allocated, file_hash_entries_used;
+
+  /* Nonzero means don't look for #include "foo" the source-file
+     directory.  */
+  bool quote_ignores_source_dir;
+
+  /* Non-zero if any file has contained #pragma once.  */
+  bool saw_pragma_once;
 
   /* Multiple include optimization.  */
   const cpp_hashnode *mi_cmacro;
@@ -386,13 +404,6 @@ struct cpp_reader
      wide execution character set.  */
   struct cset_converter wide_cset_desc;
 
-  /* Tree of other included files.  See cppfiles.c.  */
-  struct splay_tree_s *all_include_files;
-
-  /* Current maximum length of directory names in the search path
-     for include files.  (Altered as we get more of them.)  */
-  unsigned int max_include_len;
-
   /* Date and time text.  Calculated together if either is requested.  */
   const uchar *date;
   const uchar *time;
@@ -432,12 +443,8 @@ struct cpp_reader
      preprocessor.  */
   struct spec_nodes spec_nodes;
 
-  /* Nonzero means don't look for #include "foo" the source-file
-     directory.  */
-  unsigned char quote_ignores_source_dir;
-
   /* Whether cpplib owns the hashtable.  */
-  unsigned char our_hashtable;
+  bool our_hashtable;
 
   /* Traditional preprocessing output buffer (a logical line).  */
   struct
@@ -509,16 +516,16 @@ extern void _cpp_init_hashtable (cpp_rea
 extern void _cpp_destroy_hashtable (cpp_reader *);
 
 /* In cppfiles.c */
+extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *, bool);
 extern void _cpp_fake_include (cpp_reader *, const char *);
-extern void _cpp_never_reread (struct include_file *);
-extern bool _cpp_read_file (cpp_reader *, const char *);
-extern bool _cpp_execute_include (cpp_reader *, const char *, int,
-				  enum include_type);
+extern bool _cpp_stack_file (cpp_reader *, const char *);
+extern bool _cpp_stack_include (cpp_reader *, const char *, int,
+				enum include_type);
 extern int _cpp_compare_file_date (cpp_reader *, const char *, int);
 extern void _cpp_report_missing_guards (cpp_reader *);
-extern void _cpp_init_includes (cpp_reader *);
-extern void _cpp_cleanup_includes (cpp_reader *);
-extern void _cpp_pop_file_buffer (cpp_reader *, struct include_file *);
+extern void _cpp_init_files (cpp_reader *);
+extern void _cpp_cleanup_files (cpp_reader *);
+extern void _cpp_pop_file_buffer (cpp_reader *, struct _cpp_file *);
 
 /* In cppexp.c */
 extern bool _cpp_parse_expr (cpp_reader *);
Index: cppinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppinit.c,v
retrieving revision 1.289
diff -u -p -r1.289 cppinit.c
--- cppinit.c	22 Jul 2003 16:24:53 -0000	1.289
+++ cppinit.c	29 Jul 2003 20:37:06 -0000
@@ -161,6 +161,12 @@ cpp_create_reader (enum c_lang lang, has
   CPP_OPTION (pfile, narrow_charset) = 0;
   CPP_OPTION (pfile, wide_charset) = 0;
 
+  /* A fake empty "directory" used as the starting point for files
+     looked up without a search path.  Name cannot be '/' because we
+     don't want to prepend anything at all to filenames using it.  All
+     other entries are correct zero-initialized.  */
+  pfile->no_search_path.name = (char *) "";
+
   /* Initialize the line map.  Start at logical line 1, so we can use
      a line number of zero for special states.  */
   linemap_init (&pfile->line_maps);
@@ -196,7 +202,7 @@ cpp_create_reader (enum c_lang lang, has
 		  (void *(*) (long)) xmalloc,
 		  (void (*) (void *)) free);
 
-  _cpp_init_includes (pfile);
+  _cpp_init_files (pfile);
 
   _cpp_init_hashtable (pfile, table);
 
@@ -231,7 +237,7 @@ cpp_destroy (cpp_reader *pfile)
   obstack_free (&pfile->buffer_ob, 0);
 
   _cpp_destroy_hashtable (pfile);
-  _cpp_cleanup_includes (pfile);
+  _cpp_cleanup_files (pfile);
   _cpp_destroy_iconv (pfile);
 
   _cpp_free_buff (pfile->a_buff);
@@ -427,15 +433,6 @@ cpp_add_dependency_target (cpp_reader *p
   deps_add_target (pfile->deps, target, quote);
 }
 
-/* This sets up for processing input from the file FNAME.  
-   It returns false on error.  */
-bool
-cpp_read_next_file (cpp_reader *pfile, const char *fname)
-{
-  /* Open the main input file.  */
-  return _cpp_read_file (pfile, fname);
-}
-
 /* This is called after options have been parsed, and partially
    processed.  Setup for processing input from the file named FNAME,
    or stdin if it is the empty string.  Return the original filename
@@ -461,7 +458,7 @@ cpp_read_main_file (cpp_reader *pfile, c
     }
 
   pfile->line = 1;
-  if (!cpp_read_next_file (pfile, fname))
+  if (!cpp_stack_file (pfile, fname))
     return NULL;
 
   /* Set this here so the client can change the option if it wishes,
Index: cpplib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.c,v
retrieving revision 1.348
diff -u -p -r1.348 cpplib.c
--- cpplib.c	22 Jul 2003 23:15:25 -0000	1.348
+++ cpplib.c	29 Jul 2003 20:37:06 -0000
@@ -441,7 +441,7 @@ run_directive (cpp_reader *pfile, int di
 		   /* from_stage3 */ true, 1);
   /* Disgusting hack.  */
   if (dir_no == T_PRAGMA)
-    pfile->buffer->inc = pfile->buffer->prev->inc;
+    pfile->buffer->file = pfile->buffer->prev->file;
   start_directive (pfile);
 
   /* This is a short-term fix to prevent a leading '#' being
@@ -454,7 +454,7 @@ run_directive (cpp_reader *pfile, int di
   pfile->directive->handler (pfile);
   end_directive (pfile, 1);
   if (dir_no == T_PRAGMA)
-    pfile->buffer->inc = NULL;
+    pfile->buffer->file = NULL;
   _cpp_pop_buffer (pfile);
 }
 
@@ -684,7 +684,7 @@ do_include_common (cpp_reader *pfile, en
 	pfile->cb.include (pfile, pfile->directive_line,
 			   pfile->directive->name, fname, angle_brackets);
 
-      _cpp_execute_include (pfile, fname, angle_brackets, type);
+      _cpp_stack_include (pfile, fname, angle_brackets, type);
     }
 
   free ((void *) fname);
@@ -699,13 +699,6 @@ do_include (cpp_reader *pfile)
 static void
 do_import (cpp_reader *pfile)
 {
-  if (CPP_OPTION (pfile, warn_import))
-    {
-      CPP_OPTION (pfile, warn_import) = 0;
-      cpp_error (pfile, DL_WARNING,
-   "#import is obsolete, use an #ifndef wrapper in the header file");
-    }
-
   do_include_common (pfile, IT_IMPORT);
 }
 
@@ -1170,15 +1163,11 @@ do_pragma (cpp_reader *pfile)
 static void
 do_pragma_once (cpp_reader *pfile)
 {
-  if (CPP_OPTION (pfile, warn_deprecated))
-    cpp_error (pfile, DL_WARNING, "#pragma once is obsolete");
-
   if (pfile->buffer->prev == NULL)
     cpp_error (pfile, DL_WARNING, "#pragma once in main file");
-  else
-    _cpp_never_reread (pfile->buffer->inc);
 
   check_eol (pfile);
+  _cpp_mark_file_once_only (pfile, pfile->buffer->file, false);
 }
 
 /* Handle #pragma GCC poison, to poison one or more identifiers so
@@ -1944,7 +1933,7 @@ void
 _cpp_pop_buffer (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
-  struct include_file *inc = buffer->inc;
+  struct _cpp_file *inc = buffer->file;
   struct if_stack *ifs;
 
   /* Walk back up the conditional stack till we reach its level at
Index: cpplib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.h,v
retrieving revision 1.261
diff -u -p -r1.261 cpplib.h
--- cpplib.h	13 Jul 2003 17:34:18 -0000	1.261
+++ cpplib.h	29 Jul 2003 20:37:07 -0000
@@ -39,10 +39,9 @@ typedef struct cpp_string cpp_string;
 typedef struct cpp_hashnode cpp_hashnode;
 typedef struct cpp_macro cpp_macro;
 typedef struct cpp_callbacks cpp_callbacks;
-typedef struct cpp_path cpp_path;
+typedef struct cpp_dir cpp_dir;
 
 struct answer;
-struct file_name_map_list;
 
 /* The first three groups, apart from '=', can appear in preprocessor
    expressions (+= and -= are used to indicate unary + and - resp.).
@@ -214,10 +213,6 @@ struct cpp_options
   /* Characters between tab stops.  */
   unsigned int tabstop;
 
-  /* Map between header names and file names, used only on DOS where
-     file names are limited in length.  */
-  struct file_name_map_list *map_list;
-
   /* The language we're preprocessing.  */
   enum c_lang lang;
 
@@ -397,12 +392,12 @@ struct cpp_callbacks
 };
 
 /* Chain of directories to look for include files in.  */
-struct cpp_path
+struct cpp_dir
 {
   /* NULL-terminated singly-linked list.  */
-  struct cpp_path *next;
+  struct cpp_dir *next;
 
-  /* NAME need not be NUL-terminated once inside cpplib.  */
+  /* NAME of the directory, NUL-terminated.  */
   char *name;
   unsigned int len;
 
@@ -410,9 +405,9 @@ struct cpp_path
      "C" guards for C++.  */
   unsigned char sysp;
 
-  /* Mapping of file names for this directory for MS-DOS and
-     related platforms.  */
-  struct file_name_map *name_map;
+  /* Mapping of file names for this directory for MS-DOS and related
+     platforms.  A NULL-terminated array of (from, to) pairs.  */
+  const char **name_map;
     
   /* The C front end uses these to recognize duplicated
      directories in the search path.  */
@@ -516,7 +511,7 @@ extern void cpp_set_lang (cpp_reader *, 
 extern void cpp_add_dependency_target (cpp_reader *, const char *, int);
 
 /* Set the include paths.  */
-extern void cpp_set_include_chains (cpp_reader *, cpp_path *, cpp_path *, int);
+extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int);
 
 /* Call these to get pointers to the options and callback structures
    for a given reader.  These pointers are good until you call
@@ -535,9 +530,9 @@ extern void cpp_set_callbacks (cpp_reade
    too.  If there was an error opening the file, it returns NULL.  */
 extern const char *cpp_read_main_file (cpp_reader *, const char *);
 
-/* This continues processing to a new file.  It will return false if
-   there was an error opening the file.  */
-extern bool cpp_read_next_file (cpp_reader *, const char *);
+/* Stacks a new file.  It will return false if there was an error
+   opening the file.  */
+extern bool cpp_stack_file (cpp_reader *, const char *);
 
 /* Set up built-ins like __FILE__.  */
 extern void cpp_init_builtins (cpp_reader *, int);
@@ -715,7 +710,7 @@ extern unsigned char *cpp_quote_string (
 					unsigned int);
 
 /* In cppfiles.c */
-extern int cpp_included (cpp_reader *, const char *);
+extern bool cpp_included (cpp_reader *, const char *);
 extern void cpp_make_system_header (cpp_reader *, int, int);
 extern void cpp_simplify_path (char *);
 extern bool cpp_push_include (cpp_reader *, const char *);
Index: testsuite/gcc.dg/cpp/include2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cpp/include2.c,v
retrieving revision 1.3
diff -u -p -r1.3 include2.c
--- testsuite/gcc.dg/cpp/include2.c	23 Apr 2003 22:44:05 -0000	1.3
+++ testsuite/gcc.dg/cpp/include2.c	29 Jul 2003 20:37:09 -0000
@@ -10,7 +10,7 @@
 #include <silly\>>  /* { dg-warning "extra tokens" "" } */
 #include "silly\""  /* { dg-warning "extra tokens" "" } */
 
-/* These first 2 errors are No such file or directory.  However, this
+/* These error is No such file or directory, just once.  However, this
    message is locale-dependent, so don't test for it.  */
 /* { dg-error "silly" "" { target *-*-* } 10 } */
-/* { dg-error "silly" "" { target *-*-* } 11 } */
+


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