/* 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. Load more
/* 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 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; /* 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 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 (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 bool find_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 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.