aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-incpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-incpath.c')
-rw-r--r--gcc/c-incpath.c195
1 files changed, 193 insertions, 2 deletions
diff --git a/gcc/c-incpath.c b/gcc/c-incpath.c
index 62680bda14a..5896349f679 100644
--- a/gcc/c-incpath.c
+++ b/gcc/c-incpath.c
@@ -29,6 +29,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "intl.h"
#include "c-incpath.h"
#include "cppdefault.h"
+/* APPLE LOCAL headermaps 3871393 */
+#include "errors.h"
/* Windows does not natively support inodes, and neither does MSDOS.
Cygwin's emulation can generate non-unique inodes, so don't use it.
@@ -165,6 +167,168 @@ add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc)
}
}
+
+/* APPLE LOCAL begin headermaps 3871393 */
+/* Private function that hashes the contents of the null-terminated
+ string in a case-insensitive way. For use by headermaps only. */
+
+static inline
+uint32 hmap_hash_string (const char *str)
+{
+ const char *sp;
+ unsigned hash_code = 0;
+
+ for (sp = str; *sp; sp++)
+ hash_code += TOLOWER (*(const unsigned char *)sp) * 13;
+ return hash_code;
+}
+
+/* Private function that case-insensitively compares the null-
+ terminated string STR1 with the null-terminated string STR2.
+ Returns 1 if equal, 0 if not. For use by headermaps only. */
+
+static inline unsigned
+hmap_compare_strings (const char *str1, const char *str2)
+{
+ const char *s1p;
+ const char *s2p;
+
+ for (s1p = str1, s2p = str2; *s1p && *s2p; s1p++, s2p++)
+ {
+ if (TOLOWER (*s1p) != TOLOWER (*s2p))
+ return 0;
+ }
+ return (*s1p == '\0' && *s2p == '\0');
+}
+
+/* Attempts to load a headermap from the file at path FILEPATH, and
+ returns a pointer to the loaded data. Returns NULL if for any
+ reason the headermap cannot be loaded. This function is silent if
+ the given file does not appear to be a headermap; this is useful
+ for checking whether or not it in fact is. */
+
+static struct hmap_header_map *
+hmap_load_header_map (const char *filepath)
+{
+ struct hmap_header_map *headermap = NULL;
+
+ if (filepath != NULL && filepath[0] != '\0')
+ {
+ FILE * f;
+ struct stat f_info;
+
+ /* Try to open the file for reading. */
+ f = fopen (filepath, "rb");
+ if (f != NULL)
+ {
+ /* If it is a regular file and if it is large enough to be a header-
+ map, see if it really is one. */
+ if (fstat (fileno (f), &f_info) == 0 && S_ISREG(f_info.st_mode)
+ && f_info.st_size >= sizeof(struct hmap_header_map))
+ {
+ unsigned headermap_size = f_info.st_size;
+
+ headermap = (struct hmap_header_map *) xmalloc (headermap_size);
+ if (fread (headermap, 1, headermap_size, f) != headermap_size)
+ {
+ /* For some reason we could not read the entire file. */
+ fprintf (stderr,
+ "warning: could not read \"%s\" (%s)\n",
+ filepath, xstrerror (errno));
+ free (headermap);
+ headermap = NULL;
+ }
+ if (headermap->version == 1 && headermap->_reserved == 0)
+ {
+ /* It might be a headermap. */
+ if (headermap->magic == HMAP_OPPOSITE_ENDIANNESS_MAGIC)
+ {
+ /* It's a headermap, but has the wrong endianness. */
+ fprintf (stderr,
+ "warning: headermap \"%s\" has incompatible endianness\n",
+ filepath);
+ free (headermap);
+ headermap = NULL;
+ }
+ else if (headermap->magic != HMAP_SAME_ENDIANNESS_MAGIC)
+ {
+ /* It's not a headermap after all. */
+ free (headermap);
+ headermap = NULL;
+ }
+ }
+ else
+ {
+ /* It's not a headermap after all. */
+ free (headermap);
+ headermap = NULL;
+ }
+ }
+ fclose (f);
+ }
+ }
+ return headermap;
+}
+
+/* Returns a pointer to a malloced string that contains the real pathname
+ to the file, given the DIR that represents the headermap and given the
+ name to be looked up. This function looks in the headermap associated
+ with DIR, if any. If there is no headermap associated with DIR, or if
+ it does not contain FILENAME, this function returns NULL. The CONSTRUCT
+ field of a cpp_dir that represents a headermap points to this function. */
+
+static char *
+hmap_construct_pathname (const char *filename, cpp_dir *dir)
+{
+ if (dir->header_map)
+ {
+ struct hmap_header_map *headermap;
+ const char *strings;
+ struct hmap_bucket *buckets;
+ uint32 bucket_mask;
+ uint32 i;
+ uint32 key_offset;
+
+ headermap = (struct hmap_header_map *)dir->header_map;
+ strings = ((const char *)headermap) + headermap->strings_offset;
+ buckets = headermap->buckets;
+ bucket_mask = headermap->capacity-1;
+ i = hmap_hash_string (filename) & bucket_mask;
+ while ((key_offset = buckets[i].key) != HMAP_NOT_A_KEY)
+ {
+ if (hmap_compare_strings (filename, strings+key_offset))
+ {
+ char *result_path;
+ unsigned prefix_length;
+ unsigned suffix_length;
+
+ if (strcmp (filename, strings+key_offset) != 0)
+ warning ("mismatched case in filenames, wanted \"%s\" but found \"%s\"",
+ filename, strings+key_offset);
+
+ prefix_length = strlen(strings + buckets[i].value.prefix);
+ suffix_length = strlen(strings + buckets[i].value.suffix);
+ result_path = xmalloc(prefix_length + suffix_length + 1);
+ memcpy(result_path,
+ strings + buckets[i].value.prefix,
+ prefix_length);
+ memcpy(result_path + prefix_length,
+ strings + buckets[i].value.suffix,
+ suffix_length);
+ result_path[prefix_length + suffix_length] = '\0';
+ return result_path;
+ }
+ i = (i + 1) & bucket_mask;
+ }
+ /* didn't find header in header map -- return NULL. */
+ return NULL;
+ }
+ else
+ return NULL;
+}
+/* APPLE LOCAL end headermaps 3871393 */
+
+
/* For each duplicate path in chain HEAD, keep just the first one.
Remove each path in chain HEAD that also exists in chain SYSTEM.
Set the NEXT pointer of the last path in the resulting chain to
@@ -201,8 +365,35 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,
}
}
else if (!S_ISDIR (st.st_mode))
- cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,
- "%s: not a directory", cur->name);
+ /* APPLE LOCAL begin headermaps 3871393 */
+ {
+ /* Only check for headermap if this is a regular file and if there
+ is no path-constructor function in CUR. */
+ if (S_ISREG (st.st_mode) && !cur->construct)
+ {
+ /* Try to load the file as a headermap. We will get back NULL
+ if this fails, and there won't be any warnings/errors emitted
+ unless the load function is fairly sure it's dealing with a
+ headermap file that is malformed. */
+ struct hmap_header_map *header_map;
+
+ header_map = hmap_load_header_map (cur->name);
+ if (header_map)
+ {
+ /* Successfully loaded a headermap. Store a pointer to it
+ and set up the construct function pointer in cur. */
+ cur->header_map = header_map;
+ cur->construct = hmap_construct_pathname;
+ pcur = &cur->next;
+ continue;
+ }
+ }
+
+ /* If we fall through to here, it's some other kind of file. */
+ cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,
+ "%s: not a directory", cur->name);
+ }
+ /* APPLE LOCAL end headermaps 3871393 */
else
{
INO_T_COPY (cur->ino, st.st_ino);