Wolfgang Thallergcc16 merge934c3885 months agoHistory
2886 lines · 80.6 KB · C++
RawDownload
/* Part of CPP library.  File handling.   Copyright (C) 1986-2026 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 itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong 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;   /* Size for #embed, perhaps smaller than st.st_size.  */  size_t limit;   /* Offset for #embed.  */  off_t offset;   /* 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 : 1;   /* If read() failed before.  */  bool dont_read : 1;   /* If BUFFER above contains the true contents of the file.  */  bool buffer_valid : 1;   /* If this file is implicitly preincluded.  */  bool implicit_preinclude : 1;   /* Set if a header wasn't found with __has_include or __has_include_next     and error should be emitted if it is included normally.  */  bool deferred_error : 1;   /* File loaded from #embed.  */  bool embed : 1;   /* > 0: Known C++ Module header unit, <0: known not.  ==0, unknown  */  int header_unit : 2;}; /* 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;  location_t 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, location_t loc);static bool read_file_guts (cpp_reader *pfile, _cpp_file *file,			    location_t loc, const char *input_charset);static bool read_file (cpp_reader *pfile, _cpp_file *file,		       location_t loc);static const char *dir_name_of_file (_cpp_file *file);static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int,			      location_t);static struct cpp_file_hash_entry *search_cache (struct cpp_file_hash_entry *head,						 const cpp_dir *start_dir,						 bool is_embed);static _cpp_file *make_cpp_file (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);static void _cpp_post_stack_file (cpp_reader *, _cpp_file *, include_type, 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 boolopen_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 boolpch_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 (pfile->main_file == f)      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 boolfind_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch,		  location_t 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 (!file->embed && 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 true iff the missing_header callback found the given HEADER.  */static boolsearch_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.

Lines 1–500 of 2886.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t