mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2015 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2015 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C
		
	
	
	
/* Part of CPP library.  File handling.
 | 
						||
   Copyright (C) 1986-2017 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 3, 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; see the file COPYING3.  If not see
 | 
						||
<http://www.gnu.org/licenses/>.  */
 | 
						||
 | 
						||
#include "config.h"
 | 
						||
#include "system.h"
 | 
						||
#include "cpplib.h"
 | 
						||
#include "internal.h"
 | 
						||
#include "mkdeps.h"
 | 
						||
#include "obstack.h"
 | 
						||
#include "hashtab.h"
 | 
						||
#include "md5.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__
 | 
						||
#include <io.h>
 | 
						||
  /* For DJGPP redirected input is opened in text mode.  */
 | 
						||
#  define set_stdin_to_binary_mode() \
 | 
						||
     if (! isatty (0)) setmode (0, O_BINARY)
 | 
						||
#else
 | 
						||
#  define set_stdin_to_binary_mode() /* Nothing */
 | 
						||
#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
 | 
						||
   cpp_file_hash_entry; at present no reference count is kept.  */
 | 
						||
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.  NULL if it hasn't
 | 
						||
     been calculated yet.  */
 | 
						||
  const char *dir_name;
 | 
						||
 | 
						||
  /* Chain through all files.  */
 | 
						||
  struct _cpp_file *next_file;
 | 
						||
 | 
						||
  /* The contents of NAME after calling read_file().  */
 | 
						||
  const uchar *buffer;
 | 
						||
 | 
						||
  /* Pointer to the real start of BUFFER.  read_file() might increment
 | 
						||
     BUFFER; when freeing, this this pointer must be used instead.  */
 | 
						||
  const uchar *buffer_start;
 | 
						||
 | 
						||
  /* 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.  */
 | 
						||
  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 or contains #pragma once.  */
 | 
						||
  bool once_only;
 | 
						||
 | 
						||
  /* 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;
 | 
						||
 | 
						||
  /* If this file is implicitly preincluded.  */
 | 
						||
  bool implicit_preinclude;
 | 
						||
};
 | 
						||
 | 
						||
/* 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 implicitly from the hash table location or explicitly
 | 
						||
   from FILE->name.
 | 
						||
 | 
						||
   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 and therefore unique.  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 cause cache hits with normal include-chain lookups.
 | 
						||
 | 
						||
   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.
 | 
						||
 | 
						||
   If a cache lookup fails because of e.g. an extra "./" in the path,
 | 
						||
   then nothing will break.  It is just less efficient as CPP will
 | 
						||
   have to do more work re-preprocessing the file, and/or comparing
 | 
						||
   its contents against earlier once-only files.
 | 
						||
*/
 | 
						||
struct cpp_file_hash_entry
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *next;
 | 
						||
  cpp_dir *start_dir;
 | 
						||
  source_location location;
 | 
						||
  union
 | 
						||
  {
 | 
						||
    _cpp_file *file;
 | 
						||
    cpp_dir *dir;
 | 
						||
  } u;
 | 
						||
};
 | 
						||
 | 
						||
/* Number of entries to put in a cpp_file_hash_entry pool.  */
 | 
						||
#define FILE_HASH_POOL_SIZE 127
 | 
						||
 | 
						||
/* A file hash entry pool.  We allocate cpp_file_hash_entry object from
 | 
						||
   one of these.  */
 | 
						||
struct file_hash_entry_pool
 | 
						||
{
 | 
						||
  /* Number of entries used from this pool.  */
 | 
						||
  unsigned int file_hash_entries_used;
 | 
						||
  /* Next pool in the chain; used when freeing.  */
 | 
						||
  struct file_hash_entry_pool *next;
 | 
						||
  /* The memory pool.  */
 | 
						||
  struct cpp_file_hash_entry pool[FILE_HASH_POOL_SIZE];
 | 
						||
};
 | 
						||
 | 
						||
static bool open_file (_cpp_file *file);
 | 
						||
static bool pch_open_file (cpp_reader *pfile, _cpp_file *file,
 | 
						||
			   bool *invalid_pch);
 | 
						||
static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file,
 | 
						||
			      bool *invalid_pch, source_location loc);
 | 
						||
static bool read_file_guts (cpp_reader *pfile, _cpp_file *file,
 | 
						||
			    source_location loc);
 | 
						||
static bool read_file (cpp_reader *pfile, _cpp_file *file,
 | 
						||
		       source_location loc);
 | 
						||
static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import,
 | 
						||
			       source_location loc);
 | 
						||
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, int,
 | 
						||
			      source_location);
 | 
						||
static struct cpp_file_hash_entry *search_cache (struct cpp_file_hash_entry *head,
 | 
						||
					     const cpp_dir *start_dir);
 | 
						||
static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname);
 | 
						||
static void destroy_cpp_file (_cpp_file *);
 | 
						||
static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp);
 | 
						||
static void allocate_file_hash_entries (cpp_reader *pfile);
 | 
						||
static struct cpp_file_hash_entry *new_file_hash_entry (cpp_reader *pfile);
 | 
						||
static int report_missing_guard (void **slot, void *b);
 | 
						||
static hashval_t file_hash_hash (const void *p);
 | 
						||
static int file_hash_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 int pchf_save_compare (const void *e1, const void *e2);
 | 
						||
static int pchf_compare (const void *d_p, const void *e_p);
 | 
						||
static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool);
 | 
						||
 | 
						||
/* 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;
 | 
						||
    }
 | 
						||
#if defined(_WIN32) && !defined(__CYGWIN__)
 | 
						||
  else if (errno == EACCES)
 | 
						||
    {
 | 
						||
      /* On most UNIX systems, open succeeds on a directory.  Above,
 | 
						||
         we check if we have opened a directory and if so, set errno
 | 
						||
         to ENOENT.  However, on Windows, opening a directory
 | 
						||
         fails with EACCES.  We want to return ENOENT in that
 | 
						||
         case too.  */
 | 
						||
      if (stat (file->path, &file->st) == 0
 | 
						||
          && S_ISDIR (file->st.st_mode))
 | 
						||
        errno = ENOENT;
 | 
						||
      else
 | 
						||
	/* The call to stat may have reset errno.  */
 | 
						||
	errno = EACCES;
 | 
						||
    }
 | 
						||
#endif    
 | 
						||
  else if (errno == ENOTDIR)
 | 
						||
    errno = ENOENT;
 | 
						||
 | 
						||
  file->err_no = errno;
 | 
						||
 | 
						||
  return false;
 | 
						||
}
 | 
						||
 | 
						||
/* Temporary PCH intercept of opening a file.  Try to find a PCH file
 | 
						||
   based on FILE->name and FILE->dir, and test those found for
 | 
						||
   validity using PFILE->cb.valid_pch.  Return true iff a valid file is
 | 
						||
   found.  Set *INVALID_PCH if a PCH file is found but wasn't valid.  */
 | 
						||
 | 
						||
static bool
 | 
						||
pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
 | 
						||
{
 | 
						||
  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;
 | 
						||
 | 
						||
  /* If the file is not included as first include from either the toplevel
 | 
						||
     file or the command-line it is not a valid use of PCH.  */
 | 
						||
  for (_cpp_file *f = pfile->all_files; f; f = f->next_file)
 | 
						||
    if (f->implicit_preinclude)
 | 
						||
      continue;
 | 
						||
    else if (f->main_file)
 | 
						||
      break;
 | 
						||
    else
 | 
						||
      return false;
 | 
						||
 | 
						||
  flen = strlen (path);
 | 
						||
  len = flen + sizeof (extension);
 | 
						||
  pchname = XNEWVEC (char, 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 ((strcmp (d->d_name, ".") == 0)
 | 
						||
		  || (strcmp (d->d_name, "..") == 0))
 | 
						||
		continue;
 | 
						||
	      if (dlen + plen > len)
 | 
						||
		{
 | 
						||
		  len += dlen + 64;
 | 
						||
		  pchname = XRESIZEVEC (char, pchname, len);
 | 
						||
		}
 | 
						||
	      memcpy (pchname + plen, d->d_name, dlen);
 | 
						||
	      valid = validate_pch (pfile, file, pchname);
 | 
						||
	      if (valid)
 | 
						||
		break;
 | 
						||
	    }
 | 
						||
	  closedir (pchdir);
 | 
						||
	}
 | 
						||
      if (!valid)
 | 
						||
	*invalid_pch = true;
 | 
						||
    }
 | 
						||
 | 
						||
  if (valid)
 | 
						||
    file->pchname = pchname;
 | 
						||
  else
 | 
						||
    free (pchname);
 | 
						||
 | 
						||
  return valid;
 | 
						||
}
 | 
						||
 | 
						||
/* Canonicalize the path to FILE.  Return the canonical form if it is
 | 
						||
   shorter, otherwise return NULL.  This function does NOT free the
 | 
						||
   memory pointed by FILE.  */
 | 
						||
 | 
						||
static char *
 | 
						||
maybe_shorter_path (const char * file)
 | 
						||
{
 | 
						||
  char * file2 = lrealpath (file);
 | 
						||
  if (file2 && strlen (file2) < strlen (file))
 | 
						||
    {
 | 
						||
      return file2;
 | 
						||
    }
 | 
						||
  else 
 | 
						||
    {
 | 
						||
      free (file2);
 | 
						||
      return NULL;
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* Try to open the path FILE->name appended to FILE->dir.  This is
 | 
						||
   where remap and PCH intercept the file lookup process.  Return true
 | 
						||
   if the file was found, whether or not the open was successful.
 | 
						||
   Set *INVALID_PCH to true if a PCH file is found but wasn't valid.
 | 
						||
   Use LOC when emitting any diagnostics.  */
 | 
						||
 | 
						||
static bool
 | 
						||
find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch,
 | 
						||
		  source_location loc)
 | 
						||
{
 | 
						||
  char *path;
 | 
						||
 | 
						||
  if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file)))
 | 
						||
    ;
 | 
						||
  else
 | 
						||
    if (file->dir->construct)
 | 
						||
      path = file->dir->construct (file->name, file->dir);
 | 
						||
    else
 | 
						||
      path = append_file_to_dir (file->name, file->dir);
 | 
						||
 | 
						||
  if (path)
 | 
						||
    {
 | 
						||
      hashval_t hv;
 | 
						||
      char *copy;
 | 
						||
      void **pp;
 | 
						||
 | 
						||
      /* We try to canonicalize system headers.  For DOS based file
 | 
						||
       * system, we always try to shorten non-system headers, as DOS
 | 
						||
       * has a tighter constraint on max path length.  */
 | 
						||
      if ((CPP_OPTION (pfile, canonical_system_headers) && file->dir->sysp)
 | 
						||
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
 | 
						||
	  || !file->dir->sysp
 | 
						||
#endif
 | 
						||
	 )
 | 
						||
	{
 | 
						||
	  char * canonical_path = maybe_shorter_path (path);
 | 
						||
	  if (canonical_path)
 | 
						||
	    {
 | 
						||
	      /* The canonical path was newly allocated.  Let's free the
 | 
						||
		 non-canonical one.  */
 | 
						||
	      free (path);
 | 
						||
	      path = canonical_path;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
 | 
						||
      hv = htab_hash_string (path);
 | 
						||
      if (htab_find_with_hash (pfile->nonexistent_file_hash, path, hv) != NULL)
 | 
						||
	{
 | 
						||
	  file->err_no = ENOENT;
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
 | 
						||
      file->path = path;
 | 
						||
      if (pch_open_file (pfile, file, invalid_pch))
 | 
						||
	return true;
 | 
						||
 | 
						||
      if (open_file (file))
 | 
						||
	return true;
 | 
						||
 | 
						||
      if (file->err_no != ENOENT)
 | 
						||
	{
 | 
						||
	  open_file_failed (pfile, file, 0, loc);
 | 
						||
	  return true;
 | 
						||
	}
 | 
						||
 | 
						||
      /* We copy the path name onto an obstack partly so that we don't
 | 
						||
	 leak the memory, but mostly so that we don't fragment the
 | 
						||
	 heap.  */
 | 
						||
      copy = (char *) obstack_copy0 (&pfile->nonexistent_file_ob, path,
 | 
						||
				     strlen (path));
 | 
						||
      free (path);
 | 
						||
      pp = htab_find_slot_with_hash (pfile->nonexistent_file_hash,
 | 
						||
				     copy, hv, INSERT);
 | 
						||
      *pp = copy;
 | 
						||
 | 
						||
      file->path = file->name;
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      file->err_no = ENOENT; 
 | 
						||
      file->path = NULL;
 | 
						||
    }
 | 
						||
 | 
						||
  return false;
 | 
						||
}
 | 
						||
 | 
						||
/* Return tue iff the missing_header callback found the given HEADER.  */
 | 
						||
static bool
 | 
						||
search_path_exhausted (cpp_reader *pfile, const char *header, _cpp_file *file)
 | 
						||
{
 | 
						||
  missing_header_cb func = pfile->cb.missing_header;
 | 
						||
 | 
						||
  /* When the regular search path doesn't work, try context dependent
 | 
						||
     headers search paths.  */
 | 
						||
  if (func
 | 
						||
      && file->dir == NULL)
 | 
						||
    {
 | 
						||
      if ((file->path = func (pfile, header, &file->dir)) != NULL)
 | 
						||
	{
 | 
						||
	  if (open_file (file))
 | 
						||
	    return true;
 | 
						||
	  free ((void *)file->path);
 | 
						||
	}
 | 
						||
      file->path = file->name;
 | 
						||
    }
 | 
						||
 | 
						||
  return false;
 | 
						||
}
 | 
						||
 | 
						||
bool
 | 
						||
_cpp_find_failed (_cpp_file *file)
 | 
						||
{
 | 
						||
  return file->err_no != 0;
 | 
						||
}
 | 
						||
 | 
						||
/* 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_search_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 nonzero 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().
 | 
						||
 | 
						||
   If IMPLICIT_PREINCLUDE then it is OK for the file to be missing.
 | 
						||
   If present, it is OK for a precompiled header to be included after
 | 
						||
   it.
 | 
						||
 | 
						||
   Use LOC as the location for any errors.  */
 | 
						||
 | 
						||
_cpp_file *
 | 
						||
_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
 | 
						||
		bool fake, int angle_brackets, bool implicit_preinclude,
 | 
						||
		source_location loc)
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *entry;
 | 
						||
  void **hash_slot;
 | 
						||
  _cpp_file *file;
 | 
						||
  bool invalid_pch = false;
 | 
						||
  bool saw_bracket_include = false;
 | 
						||
  bool saw_quote_include = false;
 | 
						||
  struct cpp_dir *found_in_cache = NULL;
 | 
						||
 | 
						||
  /* Ensure we get no confusion between cached files and directories.  */
 | 
						||
  if (start_dir == NULL)
 | 
						||
    cpp_error_at (pfile, CPP_DL_ICE, loc, "NULL directory in find_file");
 | 
						||
 | 
						||
  hash_slot
 | 
						||
    = htab_find_slot_with_hash (pfile->file_hash, fname,
 | 
						||
				htab_hash_string (fname), INSERT);
 | 
						||
 | 
						||
  /* First check the cache before we resort to memory allocation.  */
 | 
						||
  entry = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir);
 | 
						||
  if (entry)
 | 
						||
    return entry->u.file;
 | 
						||
 | 
						||
  file = make_cpp_file (pfile, start_dir, fname);
 | 
						||
  file->implicit_preinclude
 | 
						||
    = (implicit_preinclude
 | 
						||
       || (pfile->buffer
 | 
						||
	   && pfile->buffer->file->implicit_preinclude));
 | 
						||
 | 
						||
  /* Try each path in the include chain.  */
 | 
						||
  for (; !fake ;)
 | 
						||
    {
 | 
						||
      if (find_file_in_dir (pfile, file, &invalid_pch, loc))
 | 
						||
	break;
 | 
						||
 | 
						||
      file->dir = file->dir->next;
 | 
						||
      if (file->dir == NULL)
 | 
						||
	{
 | 
						||
	  if (search_path_exhausted (pfile, fname, file))
 | 
						||
	    {
 | 
						||
	      /* Although this file must not go in the cache, because
 | 
						||
		 the file found might depend on things (like the current file)
 | 
						||
		 that aren't represented in the cache, it still has to go in
 | 
						||
		 the list of all files so that #import works.  */
 | 
						||
	      file->next_file = pfile->all_files;
 | 
						||
	      pfile->all_files = file;
 | 
						||
	      if (*hash_slot == NULL)
 | 
						||
		{
 | 
						||
		  /* If *hash_slot is NULL, the above htab_find_slot_with_hash
 | 
						||
		     call just created the slot, but we aren't going to store
 | 
						||
		     there anything, so need to remove the newly created entry.
 | 
						||
		     htab_clear_slot requires that it is non-NULL, so store
 | 
						||
		     there some non-NULL pointer, htab_clear_slot will
 | 
						||
		     overwrite it immediately.  */
 | 
						||
		  *hash_slot = file;
 | 
						||
		  htab_clear_slot (pfile->file_hash, hash_slot);
 | 
						||
		}
 | 
						||
	      return file;
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (invalid_pch)
 | 
						||
	    {
 | 
						||
	      cpp_error (pfile, CPP_DL_ERROR,
 | 
						||
	       "one or more PCH files were found, but they were invalid");
 | 
						||
	      if (!cpp_get_options (pfile)->warn_invalid_pch)
 | 
						||
		cpp_error (pfile, CPP_DL_ERROR,
 | 
						||
			   "use -Winvalid-pch for more information");
 | 
						||
	    }
 | 
						||
	  if (implicit_preinclude)
 | 
						||
	    {
 | 
						||
	      free ((char *) file->name);
 | 
						||
	      free (file);
 | 
						||
	      if (*hash_slot == NULL)
 | 
						||
		{
 | 
						||
		  /* See comment on the above htab_clear_slot call.  */
 | 
						||
		  *hash_slot = file;
 | 
						||
		  htab_clear_slot (pfile->file_hash, hash_slot);
 | 
						||
		}
 | 
						||
	      return NULL;
 | 
						||
	    }
 | 
						||
	  else
 | 
						||
	    open_file_failed (pfile, file, angle_brackets, loc);
 | 
						||
	  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)
 | 
						||
	saw_bracket_include = true;
 | 
						||
      else if (file->dir == pfile->quote_include)
 | 
						||
	saw_quote_include = true;
 | 
						||
      else
 | 
						||
	continue;
 | 
						||
 | 
						||
      entry = search_cache ((struct cpp_file_hash_entry *) *hash_slot, file->dir);
 | 
						||
      if (entry)
 | 
						||
	{
 | 
						||
	  found_in_cache = file->dir;
 | 
						||
	  break;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  if (entry)
 | 
						||
    {
 | 
						||
      /* Cache for START_DIR too, sharing the _cpp_file structure.  */
 | 
						||
      free ((char *) file->name);
 | 
						||
      free (file);
 | 
						||
      file = entry->u.file;
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      /* This is a new file; put it in the list.  */
 | 
						||
      file->next_file = pfile->all_files;
 | 
						||
      pfile->all_files = file;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Store this new result in the hash table.  */
 | 
						||
  entry = new_file_hash_entry (pfile);
 | 
						||
  entry->next = (struct cpp_file_hash_entry *) *hash_slot;
 | 
						||
  entry->start_dir = start_dir;
 | 
						||
  entry->location = pfile->line_table->highest_location;
 | 
						||
  entry->u.file = file;
 | 
						||
  *hash_slot = (void *) entry;
 | 
						||
 | 
						||
  /* If we passed the quote or bracket chain heads, cache them also.
 | 
						||
     This speeds up processing if there are lots of -I options.  */
 | 
						||
  if (saw_bracket_include
 | 
						||
      && pfile->bracket_include != start_dir
 | 
						||
      && found_in_cache != pfile->bracket_include)
 | 
						||
    {
 | 
						||
      entry = new_file_hash_entry (pfile);
 | 
						||
      entry->next = (struct cpp_file_hash_entry *) *hash_slot;
 | 
						||
      entry->start_dir = pfile->bracket_include;
 | 
						||
      entry->location = pfile->line_table->highest_location;
 | 
						||
      entry->u.file = file;
 | 
						||
      *hash_slot = (void *) entry;
 | 
						||
    }
 | 
						||
  if (saw_quote_include
 | 
						||
      && pfile->quote_include != start_dir
 | 
						||
      && found_in_cache != pfile->quote_include)
 | 
						||
    {
 | 
						||
      entry = new_file_hash_entry (pfile);
 | 
						||
      entry->next = (struct cpp_file_hash_entry *) *hash_slot;
 | 
						||
      entry->start_dir = pfile->quote_include;
 | 
						||
      entry->location = pfile->line_table->highest_location;
 | 
						||
      entry->u.file = file;
 | 
						||
      *hash_slot = (void *) 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.
 | 
						||
 | 
						||
   Use LOC for any diagnostics.
 | 
						||
 | 
						||
   FIXME: Flush file cache and try again if we run out of memory.  */
 | 
						||
static bool
 | 
						||
read_file_guts (cpp_reader *pfile, _cpp_file *file, source_location loc)
 | 
						||
{
 | 
						||
  ssize_t size, total, count;
 | 
						||
  uchar *buf;
 | 
						||
  bool regular;
 | 
						||
 | 
						||
  if (S_ISBLK (file->st.st_mode))
 | 
						||
    {
 | 
						||
      cpp_error_at (pfile, CPP_DL_ERROR, loc,
 | 
						||
		    "%s is a block device", file->path);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  regular = S_ISREG (file->st.st_mode) != 0;
 | 
						||
  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_at (pfile, CPP_DL_ERROR, loc,
 | 
						||
			"%s is too large", file->path);
 | 
						||
	  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;
 | 
						||
 | 
						||
  /* The + 16 here is space for the final '\n' and 15 bytes of padding,
 | 
						||
     used to quiet warnings from valgrind or Address Sanitizer, when the
 | 
						||
     optimized lexer accesses aligned 16-byte memory chunks, including
 | 
						||
     the bytes after the malloced, area, and stops lexing on '\n'.  */
 | 
						||
  buf = XNEWVEC (uchar, size + 16);
 | 
						||
  total = 0;
 | 
						||
  while ((count = read (file->fd, buf + total, size - total)) > 0)
 | 
						||
    {
 | 
						||
      total += count;
 | 
						||
 | 
						||
      if (total == size)
 | 
						||
	{
 | 
						||
	  if (regular)
 | 
						||
	    break;
 | 
						||
	  size *= 2;
 | 
						||
	  buf = XRESIZEVEC (uchar, buf, size + 16);
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  if (count < 0)
 | 
						||
    {
 | 
						||
      cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, loc);
 | 
						||
      free (buf);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  if (regular && total != size && STAT_SIZE_RELIABLE (file->st))
 | 
						||
    cpp_error_at (pfile, CPP_DL_WARNING, loc,
 | 
						||
	       "%s is shorter than expected", file->path);
 | 
						||
 | 
						||
  file->buffer = _cpp_convert_input (pfile,
 | 
						||
				     CPP_OPTION (pfile, input_charset),
 | 
						||
				     buf, size + 16, total,
 | 
						||
				     &file->buffer_start,
 | 
						||
				     &file->st.st_size);
 | 
						||
  file->buffer_valid = true;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Convenience wrapper around read_file_guts that opens the file if
 | 
						||
   necessary and closes the file descriptor after reading.  FILE must
 | 
						||
   have been passed through find_file() at some stage.  Use LOC for
 | 
						||
   any diagnostics.  */
 | 
						||
static bool
 | 
						||
read_file (cpp_reader *pfile, _cpp_file *file, source_location loc)
 | 
						||
{
 | 
						||
  /* 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, 0, loc);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  file->dont_read = !read_file_guts (pfile, file, loc);
 | 
						||
  close (file->fd);
 | 
						||
  file->fd = -1;
 | 
						||
 | 
						||
  return !file->dont_read;
 | 
						||
}
 | 
						||
 | 
						||
/* Returns TRUE if FILE's contents have been successfully placed in
 | 
						||
   FILE->buffer and the file should be stacked, otherwise false.
 | 
						||
   Use LOC for any diagnostics.  */
 | 
						||
static bool
 | 
						||
should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import,
 | 
						||
		   source_location loc)
 | 
						||
{
 | 
						||
  _cpp_file *f;
 | 
						||
 | 
						||
  /* Skip once-only files.  */
 | 
						||
  if (file->once_only)
 | 
						||
    return false;
 | 
						||
 | 
						||
  /* We must mark the file once-only if #import now, before header
 | 
						||
     guard checks.  Otherwise, undefining the header guard might
 | 
						||
     cause the file to be re-stacked.  */
 | 
						||
  if (import)
 | 
						||
    {
 | 
						||
      _cpp_mark_file_once_only (pfile, file);
 | 
						||
 | 
						||
      /* Don't stack files that have been stacked before.  */
 | 
						||
      if (file->stack_count)
 | 
						||
	return false;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Skip if the file had a header guard and the macro is defined.
 | 
						||
     PCH relies on this appearing before the PCH handler below.  */
 | 
						||
  if (file->cmacro && file->cmacro->type == NT_MACRO)
 | 
						||
    return false;
 | 
						||
 | 
						||
  /* Handle PCH files immediately; don't stack them.  */
 | 
						||
  if (file->pchname)
 | 
						||
    {
 | 
						||
      pfile->cb.read_pch (pfile, file->pchname, file->fd, file->path);
 | 
						||
      file->fd = -1;
 | 
						||
      free ((void *) file->pchname);
 | 
						||
      file->pchname = NULL;
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  if (!read_file (pfile, file, loc))
 | 
						||
    return false;
 | 
						||
 | 
						||
  /* Check the file against the PCH file.  This is done before
 | 
						||
     checking against files we've already seen, since it may save on
 | 
						||
     I/O.  */
 | 
						||
  if (check_file_against_entries (pfile, file, import))
 | 
						||
    {
 | 
						||
      /* If this isn't a #import, but yet we can't include the file,
 | 
						||
	 that means that it was #import-ed in the PCH file,
 | 
						||
	 so we can never include it again.  */
 | 
						||
      if (! import)
 | 
						||
	_cpp_mark_file_once_only (pfile, file);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Now we've read the file's contents, we can stack it if there
 | 
						||
     are no once-only files.  */
 | 
						||
  if (!pfile->seen_once_only)
 | 
						||
    return true;
 | 
						||
 | 
						||
  /* We may have read the file under a different name.  Look
 | 
						||
     for likely candidates and compare file contents to be sure.  */
 | 
						||
  for (f = pfile->all_files; f; f = f->next_file)
 | 
						||
    {
 | 
						||
      if (f == file)
 | 
						||
	continue;
 | 
						||
 | 
						||
      if ((import || f->once_only)
 | 
						||
	  && f->err_no == 0
 | 
						||
	  && f->st.st_mtime == file->st.st_mtime
 | 
						||
	  && f->st.st_size == file->st.st_size)
 | 
						||
	{
 | 
						||
	  _cpp_file *ref_file;
 | 
						||
	  bool same_file_p = false;
 | 
						||
 | 
						||
	  if (f->buffer && !f->buffer_valid)
 | 
						||
	    {
 | 
						||
	      /* We already have a buffer but it is not valid, because
 | 
						||
		 the file is still stacked.  Make a new one.  */
 | 
						||
	      ref_file = make_cpp_file (pfile, f->dir, f->name);
 | 
						||
	      ref_file->path = f->path;
 | 
						||
	    }
 | 
						||
	  else
 | 
						||
	    /* The file is not stacked anymore.  We can reuse it.  */
 | 
						||
	    ref_file = f;
 | 
						||
 | 
						||
	  same_file_p = read_file (pfile, ref_file, loc)
 | 
						||
			/* Size might have changed in read_file().  */
 | 
						||
			&& ref_file->st.st_size == file->st.st_size
 | 
						||
			&& !memcmp (ref_file->buffer,
 | 
						||
				    file->buffer,
 | 
						||
				    file->st.st_size);
 | 
						||
 | 
						||
	  if (f->buffer && !f->buffer_valid)
 | 
						||
	    {
 | 
						||
	      ref_file->path = 0;
 | 
						||
	      destroy_cpp_file (ref_file);
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (same_file_p)
 | 
						||
	    break;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  return f == NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* 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.  Use LOC for any diagnostics.  */
 | 
						||
bool
 | 
						||
_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import,
 | 
						||
		 source_location loc)
 | 
						||
{
 | 
						||
  cpp_buffer *buffer;
 | 
						||
  int sysp;
 | 
						||
 | 
						||
  if (!should_stack_file (pfile, file, import, loc))
 | 
						||
      return false;
 | 
						||
 | 
						||
  if (pfile->buffer == NULL || file->dir == NULL)
 | 
						||
    sysp = 0;
 | 
						||
  else
 | 
						||
    sysp = MAX (pfile->buffer->sysp,  file->dir->sysp);
 | 
						||
 | 
						||
  /* 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->path);
 | 
						||
    }
 | 
						||
 | 
						||
  /* 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)
 | 
						||
			    && !CPP_OPTION (pfile, directives_only));
 | 
						||
  buffer->file = file;
 | 
						||
  buffer->sysp = sysp;
 | 
						||
  buffer->to_free = file->buffer_start;
 | 
						||
 | 
						||
  /* Initialize controlling macro state.  */
 | 
						||
  pfile->mi_valid = true;
 | 
						||
  pfile->mi_cmacro = 0;
 | 
						||
 | 
						||
  /* Generate the call back.  */
 | 
						||
  _cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp);
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Mark FILE to be included once only.  */
 | 
						||
void
 | 
						||
_cpp_mark_file_once_only (cpp_reader *pfile, _cpp_file *file)
 | 
						||
{
 | 
						||
  pfile->seen_once_only = true;
 | 
						||
  file->once_only = true;
 | 
						||
}
 | 
						||
 | 
						||
/* Return the directory from which searching for FNAME should start,
 | 
						||
   considering 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;
 | 
						||
 | 
						||
  /* pfile->buffer is NULL when processing an -include command-line flag.  */
 | 
						||
  file = pfile->buffer == NULL ? pfile->main_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
 | 
						||
      && file->dir != &pfile->no_search_path)
 | 
						||
    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->buffer ? pfile->buffer->sysp : 0);
 | 
						||
 | 
						||
  if (dir == NULL)
 | 
						||
    cpp_error (pfile, CPP_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 nonzero 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 = XNEWVEC (char, len + 1);
 | 
						||
 | 
						||
      memcpy (dir_name, file->path, len);
 | 
						||
      dir_name[len] = '\0';
 | 
						||
      file->dir_name = dir_name;
 | 
						||
    }
 | 
						||
 | 
						||
  return file->dir_name;
 | 
						||
}
 | 
						||
 | 
						||
/* 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, source_location loc)
 | 
						||
{
 | 
						||
  struct cpp_dir *dir;
 | 
						||
  _cpp_file *file;
 | 
						||
  bool stacked;
 | 
						||
 | 
						||
  /* For -include command-line flags we have type == IT_CMDLINE.
 | 
						||
     When the first -include file is processed we have the case, where
 | 
						||
     pfile->cur_token == pfile->cur_run->base, we are directly called up
 | 
						||
     by the front end.  However in the case of the second -include file,
 | 
						||
     we are called from _cpp_lex_token -> _cpp_get_fresh_line ->
 | 
						||
     cpp_push_include, with pfile->cur_token != pfile->cur_run->base,
 | 
						||
     and pfile->cur_token[-1].src_loc not (yet) initialized.
 | 
						||
     However, when the include file cannot be found, we need src_loc to
 | 
						||
     be initialized to some safe value: 0 means UNKNOWN_LOCATION.  */
 | 
						||
  if (type == IT_CMDLINE && pfile->cur_token != pfile->cur_run->base)
 | 
						||
    pfile->cur_token[-1].src_loc = 0;
 | 
						||
 | 
						||
  dir = search_path_head (pfile, fname, angle_brackets, type);
 | 
						||
  if (!dir)
 | 
						||
    return false;
 | 
						||
 | 
						||
  file = _cpp_find_file (pfile, fname, dir, false, angle_brackets,
 | 
						||
			 type == IT_DEFAULT, loc);
 | 
						||
  if (type == IT_DEFAULT && file == NULL)
 | 
						||
    return false;
 | 
						||
 | 
						||
  /* Compensate for the increment in linemap_add that occurs if
 | 
						||
      _cpp_stack_file actually stacks the file.  In the case of a
 | 
						||
     normal #include, we're currently at the start of the line
 | 
						||
     *following* the #include.  A separate source_location for this
 | 
						||
     location makes no sense (until we do the LC_LEAVE), and
 | 
						||
     complicates LAST_SOURCE_LINE_LOCATION.  This does not apply if we
 | 
						||
     found a PCH file (in which case linemap_add is not called) or we
 | 
						||
     were included from the command-line.  */
 | 
						||
  if (file->pchname == NULL && file->err_no == 0
 | 
						||
      && type != IT_CMDLINE && type != IT_DEFAULT)
 | 
						||
    pfile->line_table->highest_location--;
 | 
						||
 | 
						||
  stacked = _cpp_stack_file (pfile, file, type == IT_IMPORT, loc);
 | 
						||
 | 
						||
  if (!stacked)
 | 
						||
    /* _cpp_stack_file didn't stack the file, so let's rollback the
 | 
						||
       compensation dance we performed above.  */
 | 
						||
    pfile->line_table->highest_location++;
 | 
						||
 | 
						||
  return stacked;
 | 
						||
}
 | 
						||
 | 
						||
/* Could not open FILE.  The complication is dependency output.  */
 | 
						||
static void
 | 
						||
open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets,
 | 
						||
		  source_location loc)
 | 
						||
{
 | 
						||
  int sysp = pfile->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->sysp : 0;
 | 
						||
  bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp);
 | 
						||
 | 
						||
  if (pfile->state.in__has_include__)
 | 
						||
    return;
 | 
						||
 | 
						||
  errno = file->err_no;
 | 
						||
  if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
 | 
						||
    {
 | 
						||
      deps_add_dep (pfile->deps, file->name);
 | 
						||
      /* If the preprocessor output (other than dependency information) is
 | 
						||
         being used, we must also flag an error.  */
 | 
						||
      if (CPP_OPTION (pfile, deps.need_preprocessor_output))
 | 
						||
	cpp_errno_filename (pfile, CPP_DL_FATAL,
 | 
						||
			    file->path ? file->path : file->name,
 | 
						||
			    loc);
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      /* If we are not outputting dependencies, or if we are and dependencies
 | 
						||
         were requested for this file, or if preprocessor output is needed
 | 
						||
         in addition to dependency information, this is an error.
 | 
						||
 | 
						||
         Otherwise (outputting dependencies but not for this file, and not
 | 
						||
         using the preprocessor output), we can still produce correct output
 | 
						||
         so it's only a warning.  */
 | 
						||
      if (CPP_OPTION (pfile, deps.style) == DEPS_NONE
 | 
						||
          || print_dep
 | 
						||
          || CPP_OPTION (pfile, deps.need_preprocessor_output))
 | 
						||
	cpp_errno_filename (pfile, CPP_DL_FATAL,
 | 
						||
			    file->path ? file->path : file->name,
 | 
						||
			    loc);
 | 
						||
      else
 | 
						||
	cpp_errno_filename (pfile, CPP_DL_WARNING,
 | 
						||
			    file->path ? file->path : file->name,
 | 
						||
			    loc);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* Search in the chain beginning at HEAD for a file whose search path
 | 
						||
   started at START_DIR != NULL.  */
 | 
						||
static struct cpp_file_hash_entry *
 | 
						||
search_cache (struct cpp_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 = XCNEW (_cpp_file);
 | 
						||
  file->main_file = !pfile->buffer;
 | 
						||
  file->fd = -1;
 | 
						||
  file->dir = dir;
 | 
						||
  file->name = xstrdup (fname);
 | 
						||
 | 
						||
  return file;
 | 
						||
}
 | 
						||
 | 
						||
/* Release a _cpp_file structure.  */
 | 
						||
static void
 | 
						||
destroy_cpp_file (_cpp_file *file)
 | 
						||
{
 | 
						||
  free ((void *) file->buffer_start);
 | 
						||
  free ((void *) file->name);
 | 
						||
  free ((void *) file->path);
 | 
						||
  free (file);
 | 
						||
}
 | 
						||
 | 
						||
/* Release all the files allocated by this reader.  */
 | 
						||
static void
 | 
						||
destroy_all_cpp_files (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  _cpp_file *iter = pfile->all_files;
 | 
						||
  while (iter)
 | 
						||
    {
 | 
						||
      _cpp_file *next = iter->next_file;
 | 
						||
      destroy_cpp_file (iter);
 | 
						||
      iter = next;
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* 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 cpp_file_hash_entry *entry, **hash_slot;
 | 
						||
  cpp_dir *dir;
 | 
						||
 | 
						||
  hash_slot = (struct cpp_file_hash_entry **)
 | 
						||
    htab_find_slot_with_hash (pfile->dir_hash, dir_name,
 | 
						||
			      htab_hash_string (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 = XCNEW (cpp_dir);
 | 
						||
  dir->next = pfile->quote_include;
 | 
						||
  dir->name = (char *) dir_name;
 | 
						||
  dir->len = strlen (dir_name);
 | 
						||
  dir->sysp = sysp;
 | 
						||
  dir->construct = 0;
 | 
						||
 | 
						||
  /* Store this new result in the hash table.  */
 | 
						||
  entry = new_file_hash_entry (pfile);
 | 
						||
  entry->next = *hash_slot;
 | 
						||
  entry->start_dir = NULL;
 | 
						||
  entry->location = pfile->line_table->highest_location;
 | 
						||
  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)
 | 
						||
{
 | 
						||
  struct file_hash_entry_pool *pool = XNEW (struct file_hash_entry_pool);
 | 
						||
  pool->file_hash_entries_used = 0;
 | 
						||
  pool->next = pfile->file_hash_entries;
 | 
						||
  pfile->file_hash_entries = pool;
 | 
						||
}
 | 
						||
 | 
						||
/* Return a new file hash entry.  */
 | 
						||
static struct cpp_file_hash_entry *
 | 
						||
new_file_hash_entry (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  unsigned int idx;
 | 
						||
  if (pfile->file_hash_entries->file_hash_entries_used == FILE_HASH_POOL_SIZE)
 | 
						||
    allocate_file_hash_entries (pfile);
 | 
						||
 | 
						||
  idx = pfile->file_hash_entries->file_hash_entries_used++;
 | 
						||
  return &pfile->file_hash_entries->pool[idx];
 | 
						||
}
 | 
						||
 | 
						||
/* Free the file hash entry pools.  */
 | 
						||
static void
 | 
						||
free_file_hash_entries (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  struct file_hash_entry_pool *iter = pfile->file_hash_entries;
 | 
						||
  while (iter)
 | 
						||
    {
 | 
						||
      struct file_hash_entry_pool *next = iter->next;
 | 
						||
      free (iter);
 | 
						||
      iter = next;
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* 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 cpp_file_hash_entry *entry;
 | 
						||
 | 
						||
  entry = (struct cpp_file_hash_entry *)
 | 
						||
     htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname));
 | 
						||
 | 
						||
  while (entry && (entry->start_dir == NULL || entry->u.file->err_no))
 | 
						||
    entry = entry->next;
 | 
						||
 | 
						||
  return entry != NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* Returns TRUE if a file FNAME has ever been successfully opened
 | 
						||
   before LOCATION.  This routine is not intended to correctly handle
 | 
						||
   filenames aliased by links or redundant . or .. traversals etc.  */
 | 
						||
bool
 | 
						||
cpp_included_before (cpp_reader *pfile, const char *fname,
 | 
						||
		     source_location location)
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *entry
 | 
						||
    = (struct cpp_file_hash_entry *)
 | 
						||
      htab_find_with_hash (pfile->file_hash, fname, htab_hash_string (fname));
 | 
						||
 | 
						||
  if (IS_ADHOC_LOC (location))
 | 
						||
    location = get_location_from_adhoc_loc (pfile->line_table, location);
 | 
						||
 | 
						||
  while (entry && (entry->start_dir == NULL || entry->u.file->err_no
 | 
						||
		   || entry->location > location))
 | 
						||
    entry = entry->next;
 | 
						||
 | 
						||
  return entry != NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* Calculate the hash value of a file hash entry P.  */
 | 
						||
 | 
						||
static hashval_t
 | 
						||
file_hash_hash (const void *p)
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *entry = (struct cpp_file_hash_entry *) p;
 | 
						||
  const char *hname;
 | 
						||
  if (entry->start_dir)
 | 
						||
    hname = entry->u.file->name;
 | 
						||
  else
 | 
						||
    hname = entry->u.dir->name;
 | 
						||
 | 
						||
  return htab_hash_string (hname);
 | 
						||
}
 | 
						||
 | 
						||
/* Compare a string Q against a file hash entry P.  */
 | 
						||
static int
 | 
						||
file_hash_eq (const void *p, const void *q)
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *entry = (struct cpp_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 filename_cmp (hname, fname) == 0;
 | 
						||
}
 | 
						||
 | 
						||
/* Compare entries in the nonexistent file hash table.  These are just
 | 
						||
   strings.  */
 | 
						||
static int
 | 
						||
nonexistent_file_hash_eq (const void *p, const void *q)
 | 
						||
{
 | 
						||
  return filename_cmp ((const char *) p, (const char *) q) == 0;
 | 
						||
}
 | 
						||
 | 
						||
/* Initialize everything in this source file.  */
 | 
						||
void
 | 
						||
_cpp_init_files (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  pfile->file_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq,
 | 
						||
					NULL, xcalloc, free);
 | 
						||
  pfile->dir_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq,
 | 
						||
					NULL, xcalloc, free);
 | 
						||
  allocate_file_hash_entries (pfile);
 | 
						||
  pfile->nonexistent_file_hash = htab_create_alloc (127, htab_hash_string,
 | 
						||
						    nonexistent_file_hash_eq,
 | 
						||
						    NULL, xcalloc, free);
 | 
						||
  obstack_specify_allocation (&pfile->nonexistent_file_ob, 0, 0,
 | 
						||
			      xmalloc, free);
 | 
						||
}
 | 
						||
 | 
						||
/* Finalize everything in this source file.  */
 | 
						||
void
 | 
						||
_cpp_cleanup_files (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  htab_delete (pfile->file_hash);
 | 
						||
  htab_delete (pfile->dir_hash);
 | 
						||
  htab_delete (pfile->nonexistent_file_hash);
 | 
						||
  obstack_free (&pfile->nonexistent_file_ob, 0);
 | 
						||
  free_file_hash_entries (pfile);
 | 
						||
  destroy_all_cpp_files (pfile);
 | 
						||
}
 | 
						||
 | 
						||
/* Make the parser forget about files it has seen.  This can be useful
 | 
						||
   for resetting the parser to start another run.  */
 | 
						||
void
 | 
						||
cpp_clear_file_cache (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  _cpp_cleanup_files (pfile);
 | 
						||
  pfile->file_hash_entries = NULL;
 | 
						||
  pfile->all_files = NULL;
 | 
						||
  _cpp_init_files (pfile);
 | 
						||
}
 | 
						||
 | 
						||
/* Enter a file name in the hash for the sake of cpp_included.  */
 | 
						||
void
 | 
						||
_cpp_fake_include (cpp_reader *pfile, const char *fname)
 | 
						||
{
 | 
						||
  _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0, false, 0);
 | 
						||
}
 | 
						||
 | 
						||
/* 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;
 | 
						||
  const struct line_maps *line_table = pfile->line_table;
 | 
						||
  const line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (line_table);
 | 
						||
  /* 1 = system header, 2 = system header to be treated as C.  */
 | 
						||
  if (syshdr)
 | 
						||
    flags = 1 + (externc != 0);
 | 
						||
  pfile->buffer->sysp = flags;
 | 
						||
  _cpp_do_file_change (pfile, LC_RENAME, ORDINARY_MAP_FILE_NAME (map),
 | 
						||
		       SOURCE_LINE (map, pfile->line_table->highest_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);
 | 
						||
}
 | 
						||
 | 
						||
struct report_missing_guard_data
 | 
						||
{
 | 
						||
  const char **paths;
 | 
						||
  size_t count;
 | 
						||
};
 | 
						||
 | 
						||
/* Callback function for htab_traverse.  */
 | 
						||
static int
 | 
						||
report_missing_guard (void **slot, void *d)
 | 
						||
{
 | 
						||
  struct cpp_file_hash_entry *entry = (struct cpp_file_hash_entry *) *slot;
 | 
						||
  struct report_missing_guard_data *data
 | 
						||
    = (struct report_missing_guard_data *) d;
 | 
						||
 | 
						||
  /* 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->once_only && file->cmacro == NULL
 | 
						||
	  && file->stack_count == 1 && !file->main_file)
 | 
						||
	{
 | 
						||
	  if (data->paths == NULL)
 | 
						||
	    {
 | 
						||
	      data->paths = XCNEWVEC (const char *, data->count);
 | 
						||
	      data->count = 0;
 | 
						||
	    }
 | 
						||
 | 
						||
	  data->paths[data->count++] = file->path;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  /* Keep traversing the hash table.  */
 | 
						||
  return 1;
 | 
						||
}
 | 
						||
 | 
						||
/* Comparison function for qsort.  */
 | 
						||
static int
 | 
						||
report_missing_guard_cmp (const void *p1, const void *p2)
 | 
						||
{
 | 
						||
  return strcmp (*(const char *const *) p1, *(const char *const *) p2);
 | 
						||
}
 | 
						||
 | 
						||
/* Report on all files that might benefit from a multiple include guard.
 | 
						||
   Triggered by -H.  */
 | 
						||
void
 | 
						||
_cpp_report_missing_guards (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  struct report_missing_guard_data data;
 | 
						||
 | 
						||
  data.paths = NULL;
 | 
						||
  data.count = htab_elements (pfile->file_hash);
 | 
						||
  htab_traverse (pfile->file_hash, report_missing_guard, &data);
 | 
						||
 | 
						||
  if (data.paths != NULL)
 | 
						||
    {
 | 
						||
      size_t i;
 | 
						||
 | 
						||
      /* Sort the paths to avoid outputting them in hash table
 | 
						||
	 order.  */
 | 
						||
      qsort (data.paths, data.count, sizeof (const char *),
 | 
						||
	     report_missing_guard_cmp);
 | 
						||
      fputs (_("Multiple include guards may be useful for:\n"),
 | 
						||
	     stderr);
 | 
						||
      for (i = 0; i < data.count; i++)
 | 
						||
	{
 | 
						||
	  fputs (data.paths[i], stderr);
 | 
						||
	  putc ('\n', stderr);
 | 
						||
	}
 | 
						||
      free (data.paths);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* 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 = _cpp_find_file (pfile, fname, dir, false, angle_brackets, false, 0);
 | 
						||
  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)
 | 
						||
{
 | 
						||
  return _cpp_stack_include (pfile, fname, false, IT_CMDLINE, 0);
 | 
						||
}
 | 
						||
 | 
						||
/* Pushes the given file, implicitly included at the start of a
 | 
						||
   compilation, onto the buffer stack but without any errors if the
 | 
						||
   file is not found.  Returns nonzero if successful.  */
 | 
						||
bool
 | 
						||
cpp_push_default_include (cpp_reader *pfile, const char *fname)
 | 
						||
{
 | 
						||
  return _cpp_stack_include (pfile, fname, true, IT_DEFAULT, 0);
 | 
						||
}
 | 
						||
 | 
						||
/* 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,
 | 
						||
		      const unsigned char *to_free)
 | 
						||
{
 | 
						||
  /* 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 (to_free)
 | 
						||
    {
 | 
						||
      if (to_free == file->buffer_start)
 | 
						||
	{
 | 
						||
	  file->buffer_start = NULL;
 | 
						||
	  file->buffer = NULL;
 | 
						||
	  file->buffer_valid = false;
 | 
						||
	}
 | 
						||
      free ((void *) to_free);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* Return the file name associated with FILE.  */
 | 
						||
const char *
 | 
						||
_cpp_get_file_name (_cpp_file *file)
 | 
						||
{
 | 
						||
  return file->name;
 | 
						||
}
 | 
						||
 | 
						||
/* Inteface to file statistics record in _cpp_file structure. */
 | 
						||
struct stat *
 | 
						||
_cpp_get_file_stat (_cpp_file *file)
 | 
						||
{
 | 
						||
    return &file->st;
 | 
						||
}
 | 
						||
 | 
						||
/* Set the include chain for "" to QUOTE, for <> to BRACKET.  If
 | 
						||
   QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the
 | 
						||
   directory of the including file.
 | 
						||
 | 
						||
   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 = XNEWVEC (char, dlen + 1 + flen + 1);
 | 
						||
  memcpy (path, dir->name, dlen);
 | 
						||
  if (dlen && !IS_DIR_SEPARATOR (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 = XNEWVEC (char, len + 1);
 | 
						||
  if (! is_space (ch))
 | 
						||
    {
 | 
						||
      *set++ = ch;
 | 
						||
      while ((ch = getc (f)) != EOF && ! is_space (ch))
 | 
						||
	{
 | 
						||
	  if (set - alloc == len)
 | 
						||
	    {
 | 
						||
	      len *= 2;
 | 
						||
	      alloc = XRESIZEVEC (char, 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 = (char *) alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1);
 | 
						||
  memcpy (name, dir->name, len);
 | 
						||
  if (len && !IS_DIR_SEPARATOR (name[len - 1]))
 | 
						||
    name[len++] = '/';
 | 
						||
  strcpy (name + len, FILE_NAME_MAP_FILE);
 | 
						||
  f = fopen (name, "r");
 | 
						||
 | 
						||
  dir->name_map = XNEWVEC (const char *, room);
 | 
						||
 | 
						||
  /* 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 = XRESIZEVEC (const char *, dir->name_map, room);
 | 
						||
	    }
 | 
						||
 | 
						||
	  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, *p3;
 | 
						||
  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 (!filename_cmp (dir->name_map[index], fname))
 | 
						||
	    return xstrdup (dir->name_map[index + 1]);
 | 
						||
      if (IS_ABSOLUTE_PATH (fname))
 | 
						||
	return NULL;
 | 
						||
      p = strchr (fname, '/');
 | 
						||
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
 | 
						||
      {
 | 
						||
	char *p2 = strchr (fname, '\\');
 | 
						||
	if (!p || (p > p2))
 | 
						||
	  p = p2;
 | 
						||
      }
 | 
						||
#endif
 | 
						||
      if (!p || p == fname)
 | 
						||
	return NULL;
 | 
						||
 | 
						||
      len = dir->len + (p - fname + 1);
 | 
						||
      new_dir = XNEWVEC (char, len + 2);
 | 
						||
      p3 = new_dir + dir->len;
 | 
						||
      memcpy (new_dir, dir->name, dir->len);
 | 
						||
      if (dir->len && !IS_DIR_SEPARATOR (dir->name[dir->len - 1]))
 | 
						||
	{
 | 
						||
	  *p3++ = '/';
 | 
						||
	  len++;
 | 
						||
	}
 | 
						||
      memcpy (p3, fname, p - fname + 1);
 | 
						||
      new_dir[len] = '\0';
 | 
						||
 | 
						||
      dir = make_cpp_dir (pfile, new_dir, dir->sysp);
 | 
						||
      fname = p + 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;
 | 
						||
  bool valid = false;
 | 
						||
 | 
						||
  file->path = pchname;
 | 
						||
  if (open_file (file))
 | 
						||
    {
 | 
						||
      valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);
 | 
						||
 | 
						||
      if (!valid)
 | 
						||
	{
 | 
						||
	  close (file->fd);
 | 
						||
	  file->fd = -1;
 | 
						||
	}
 | 
						||
 | 
						||
      if (CPP_OPTION (pfile, print_include_names))
 | 
						||
	{
 | 
						||
	  unsigned int i;
 | 
						||
	  for (i = 1; i < pfile->line_table->depth; i++)
 | 
						||
	    putc ('.', stderr);
 | 
						||
	  fprintf (stderr, "%c %s\n",
 | 
						||
		   valid ? '!' : 'x', pchname);
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  file->path = saved_path;
 | 
						||
  return valid;
 | 
						||
}
 | 
						||
 | 
						||
/* Get the path associated with the _cpp_file F.  The path includes
 | 
						||
   the base name from the include directive and the directory it was
 | 
						||
   found in via the search path.  */
 | 
						||
 | 
						||
const char *
 | 
						||
cpp_get_path (struct _cpp_file *f)
 | 
						||
{
 | 
						||
  return f->path;
 | 
						||
}
 | 
						||
 | 
						||
/* Get the directory associated with the _cpp_file F.  */
 | 
						||
 | 
						||
cpp_dir *
 | 
						||
cpp_get_dir (struct _cpp_file *f)
 | 
						||
{
 | 
						||
  return f->dir;
 | 
						||
}
 | 
						||
 | 
						||
/* Get the cpp_buffer currently associated with the cpp_reader
 | 
						||
   PFILE.  */
 | 
						||
 | 
						||
cpp_buffer *
 | 
						||
cpp_get_buffer (cpp_reader *pfile)
 | 
						||
{
 | 
						||
  return pfile->buffer;
 | 
						||
}
 | 
						||
 | 
						||
/* Get the _cpp_file associated with the cpp_buffer B.  */
 | 
						||
 | 
						||
_cpp_file *
 | 
						||
cpp_get_file (cpp_buffer *b)
 | 
						||
{
 | 
						||
  return b->file;
 | 
						||
}
 | 
						||
 | 
						||
/* Get the previous cpp_buffer given a cpp_buffer B.  The previous
 | 
						||
   buffer is the buffer that included the given buffer.  */
 | 
						||
 | 
						||
cpp_buffer *
 | 
						||
cpp_get_prev (cpp_buffer *b)
 | 
						||
{
 | 
						||
  return b->prev;
 | 
						||
}
 | 
						||
 | 
						||
/* This data structure holds the list of header files that were seen
 | 
						||
   while the PCH was being built.  The 'entries' field is kept sorted
 | 
						||
   in memcmp() order; yes, this means that on little-endian systems,
 | 
						||
   it's sorted initially by the least-significant byte of 'size', but
 | 
						||
   that's OK.  The code does rely on having entries with the same size
 | 
						||
   next to each other.  */
 | 
						||
 | 
						||
struct pchf_entry {
 | 
						||
  /* The size of this file.  This is used to save running a MD5 checksum
 | 
						||
     if the sizes don't match.  */
 | 
						||
  off_t size;
 | 
						||
  /* The MD5 checksum of this file.  */
 | 
						||
  unsigned char sum[16];
 | 
						||
  /* Is this file to be included only once?  */
 | 
						||
  bool once_only;
 | 
						||
};
 | 
						||
 | 
						||
struct pchf_data {
 | 
						||
  /* Number of pchf_entry structures.  */
 | 
						||
  size_t count;
 | 
						||
 | 
						||
  /* Are there any values with once_only set?
 | 
						||
     This is used as an optimisation, it means we don't have to search
 | 
						||
     the structure if we're processing a regular #include.  */
 | 
						||
  bool have_once_only;
 | 
						||
 | 
						||
  struct pchf_entry entries[1];
 | 
						||
};
 | 
						||
 | 
						||
static struct pchf_data *pchf;
 | 
						||
 | 
						||
/* A qsort ordering function for pchf_entry structures.  */
 | 
						||
 | 
						||
static int
 | 
						||
pchf_save_compare (const void *e1, const void *e2)
 | 
						||
{
 | 
						||
  return memcmp (e1, e2, sizeof (struct pchf_entry));
 | 
						||
}
 | 
						||
 | 
						||
/* Create and write to F a pchf_data structure.  */
 | 
						||
 | 
						||
bool
 | 
						||
_cpp_save_file_entries (cpp_reader *pfile, FILE *fp)
 | 
						||
{
 | 
						||
  size_t count = 0;
 | 
						||
  struct pchf_data *result;
 | 
						||
  size_t result_size;
 | 
						||
  _cpp_file *f;
 | 
						||
  bool ret;
 | 
						||
 | 
						||
  for (f = pfile->all_files; f; f = f->next_file)
 | 
						||
    ++count;
 | 
						||
 | 
						||
  result_size = (sizeof (struct pchf_data)
 | 
						||
		 + sizeof (struct pchf_entry) * (count - 1));
 | 
						||
  result = XCNEWVAR (struct pchf_data, result_size);
 | 
						||
 | 
						||
  result->count = 0;
 | 
						||
  result->have_once_only = false;
 | 
						||
 | 
						||
  for (f = pfile->all_files; f; f = f->next_file)
 | 
						||
    {
 | 
						||
      size_t count;
 | 
						||
 | 
						||
      /* This should probably never happen, since if a read error occurred
 | 
						||
	 the PCH file shouldn't be written...  */
 | 
						||
      if (f->dont_read || f->err_no)
 | 
						||
	continue;
 | 
						||
 | 
						||
      if (f->stack_count == 0)
 | 
						||
	continue;
 | 
						||
 | 
						||
      count = result->count++;
 | 
						||
 | 
						||
      result->entries[count].once_only = f->once_only;
 | 
						||
      /* |= is avoided in the next line because of an HP C compiler bug */
 | 
						||
      result->have_once_only = result->have_once_only | f->once_only;
 | 
						||
      if (f->buffer_valid)
 | 
						||
	md5_buffer ((const char *)f->buffer,
 | 
						||
		    f->st.st_size, result->entries[count].sum);
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  FILE *ff;
 | 
						||
	  int oldfd = f->fd;
 | 
						||
 | 
						||
	  if (!open_file (f))
 | 
						||
	    {
 | 
						||
	      open_file_failed (pfile, f, 0, 0);
 | 
						||
	      free (result);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
	  ff = fdopen (f->fd, "rb");
 | 
						||
	  md5_stream (ff, result->entries[count].sum);
 | 
						||
	  fclose (ff);
 | 
						||
	  f->fd = oldfd;
 | 
						||
	}
 | 
						||
      result->entries[count].size = f->st.st_size;
 | 
						||
    }
 | 
						||
 | 
						||
  result_size = (sizeof (struct pchf_data)
 | 
						||
                 + sizeof (struct pchf_entry) * (result->count - 1));
 | 
						||
 | 
						||
  qsort (result->entries, result->count, sizeof (struct pchf_entry),
 | 
						||
	 pchf_save_compare);
 | 
						||
 | 
						||
  ret = fwrite (result, result_size, 1, fp) == 1;
 | 
						||
  free (result);
 | 
						||
  return ret;
 | 
						||
}
 | 
						||
 | 
						||
/* Read the pchf_data structure from F.  */
 | 
						||
 | 
						||
bool
 | 
						||
_cpp_read_file_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, FILE *f)
 | 
						||
{
 | 
						||
  struct pchf_data d;
 | 
						||
 | 
						||
  if (fread (&d, sizeof (struct pchf_data) - sizeof (struct pchf_entry), 1, f)
 | 
						||
       != 1)
 | 
						||
    return false;
 | 
						||
 | 
						||
  pchf = XNEWVAR (struct pchf_data, sizeof (struct pchf_data)
 | 
						||
		  + sizeof (struct pchf_entry) * (d.count - 1));
 | 
						||
  memcpy (pchf, &d, sizeof (struct pchf_data) - sizeof (struct pchf_entry));
 | 
						||
  if (fread (pchf->entries, sizeof (struct pchf_entry), d.count, f)
 | 
						||
      != d.count)
 | 
						||
    return false;
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* The parameters for pchf_compare.  */
 | 
						||
 | 
						||
struct pchf_compare_data
 | 
						||
{
 | 
						||
  /* The size of the file we're looking for.  */
 | 
						||
  off_t size;
 | 
						||
 | 
						||
  /* The MD5 checksum of the file, if it's been computed.  */
 | 
						||
  unsigned char sum[16];
 | 
						||
 | 
						||
  /* Is SUM valid?  */
 | 
						||
  bool sum_computed;
 | 
						||
 | 
						||
  /* Do we need to worry about entries that don't have ONCE_ONLY set?  */
 | 
						||
  bool check_included;
 | 
						||
 | 
						||
  /* The file that we're searching for.  */
 | 
						||
  _cpp_file *f;
 | 
						||
};
 | 
						||
 | 
						||
/* bsearch comparison function; look for D_P in E_P.  */
 | 
						||
 | 
						||
static int
 | 
						||
pchf_compare (const void *d_p, const void *e_p)
 | 
						||
{
 | 
						||
  const struct pchf_entry *e = (const struct pchf_entry *)e_p;
 | 
						||
  struct pchf_compare_data *d = (struct pchf_compare_data *)d_p;
 | 
						||
  int result;
 | 
						||
 | 
						||
  result = memcmp (&d->size, &e->size, sizeof (off_t));
 | 
						||
  if (result != 0)
 | 
						||
    return result;
 | 
						||
 | 
						||
  if (! d->sum_computed)
 | 
						||
    {
 | 
						||
      _cpp_file *const f = d->f;
 | 
						||
 | 
						||
      md5_buffer ((const char *)f->buffer, f->st.st_size, d->sum);
 | 
						||
      d->sum_computed = true;
 | 
						||
    }
 | 
						||
 | 
						||
  result = memcmp (d->sum, e->sum, 16);
 | 
						||
  if (result != 0)
 | 
						||
    return result;
 | 
						||
 | 
						||
  if (d->check_included || e->once_only)
 | 
						||
    return 0;
 | 
						||
  else
 | 
						||
    return 1;
 | 
						||
}
 | 
						||
 | 
						||
/* Check that F is not in a list read from a PCH file (if any).
 | 
						||
   Assumes that f->buffer_valid is true.  Return TRUE if the file
 | 
						||
   should not be read.  */
 | 
						||
 | 
						||
static bool
 | 
						||
check_file_against_entries (cpp_reader *pfile ATTRIBUTE_UNUSED,
 | 
						||
			    _cpp_file *f,
 | 
						||
			    bool check_included)
 | 
						||
{
 | 
						||
  struct pchf_compare_data d;
 | 
						||
 | 
						||
  if (pchf == NULL
 | 
						||
      || (! check_included && ! pchf->have_once_only))
 | 
						||
    return false;
 | 
						||
 | 
						||
  d.size = f->st.st_size;
 | 
						||
  d.sum_computed = false;
 | 
						||
  d.f = f;
 | 
						||
  d.check_included = check_included;
 | 
						||
  return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
 | 
						||
		  pchf_compare) != NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* Return true if the file FNAME is found in the appropriate include file path
 | 
						||
   as indicated by ANGLE_BRACKETS.  */
 | 
						||
 | 
						||
bool
 | 
						||
_cpp_has_header (cpp_reader *pfile, const char *fname, int angle_brackets,
 | 
						||
		 enum include_type type)
 | 
						||
{
 | 
						||
  cpp_dir *start_dir = search_path_head (pfile, fname, angle_brackets, type);
 | 
						||
  _cpp_file *file = _cpp_find_file (pfile, fname, start_dir,
 | 
						||
				    /*fake=*/false, angle_brackets,
 | 
						||
				    /*implicit_preinclude=*/false, 0);
 | 
						||
  return file->err_no != ENOENT;
 | 
						||
}
 | 
						||
 |