#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "intl.h"
#include "mkdeps.h"
#include "splay-tree.h"
#include "timevar.h"
#ifdef PFE
#include "pfe/pfe.h"
#include "pfe/pfe-header.h"
#endif
#include "genindex.h"
#ifdef HAVE_MMAP_FILE
# include <sys/mman.h>
# ifndef MMAP_THRESHOLD
# define MMAP_THRESHOLD 3
# endif
# if MMAP_THRESHOLD
# define TEST_THRESHOLD(size, pagesize) \
(size / pagesize >= MMAP_THRESHOLD && (size % pagesize) != 0)
# ifndef __CYGWIN__
# define SHOULD_MMAP(size, pagesize) TEST_THRESHOLD (size, pagesize)
# else
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# define SHOULD_MMAP(size, pagesize) ((GetVersion() & 0x80000000) \
? 0 : TEST_THRESHOLD (size, pagesize))
# endif
# endif
#else
# undef MMAP_THRESHOLD
# define MMAP_THRESHOLD 0
#endif
#ifndef USING_DARWIN_MMAP
#define USING_DARWIN_MMAP 0
#endif
#if MMAP_THRESHOLD && USING_DARWIN_MMAP
#include <mach/mach_host.h>
static kernel_version_t darwin_kernel_version;
static int darwin_mmap_allowed = 1;
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef ENOENT
# define ENOENT 0
#endif
#ifndef ENOTDIR
# define ENOTDIR 0
#endif
#undef strcmp
struct include_file
{
const char *name;
const cpp_hashnode *cmacro;
const struct search_path *foundhere;
const unsigned char *buffer;
struct stat st;
int fd;
int err_no;
unsigned short include_count;
unsigned short refcnt;
unsigned char mapped;
};
#ifdef VMS
# define FAB_C_VAR 2
# define STAT_SIZE_TOO_BIG(ST) ((ST).st_fab_rfm == FAB_C_VAR)
#else
# define STAT_SIZE_TOO_BIG(ST) 0
#endif
#define NEVER_REREAD ((const cpp_hashnode *)-1)
#define DO_NOT_REREAD(inc) \
((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
|| (inc)->cmacro->type == NT_MACRO))
#define NO_INCLUDE_PATH ((struct include_file *) -1)
static struct file_name_map *read_name_map
PARAMS ((cpp_reader *, const char *));
static char *read_filename_string PARAMS ((int, FILE *));
static char *remap_filename PARAMS ((cpp_reader *, char *,
struct search_path *));
static struct search_path *search_from PARAMS ((cpp_reader *,
enum include_type));
#ifdef FRAMEWORK_HEADERS
struct framework_header {const char * dirName; int dirNameLen; };
static struct framework_header framework_header_dirs[] = {
{ "PrivateHeaders", 14 },
{ "Headers", 7 },
{ NULL, 0 }
};
static struct include_file *
find_subframework_file PARAMS ((cpp_reader *, const cpp_token *,
struct search_path *));
static struct include_file *
find_framework_file PARAMS ((cpp_reader *, const cpp_token *,
enum include_type));
#endif
static struct include_file *
find_include_file_in_hashtable PARAMS ((cpp_reader *, const char *, char *,
enum include_type, struct search_path *));
static struct include_file *
find_include_file PARAMS ((cpp_reader *, const cpp_token *,
enum include_type));
static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
static int read_include_file PARAMS ((cpp_reader *, struct include_file *));
static bool stack_include_file PARAMS ((cpp_reader *, struct include_file *));
static void purge_cache PARAMS ((struct include_file *));
static void destroy_node PARAMS ((splay_tree_value));
static int report_missing_guard PARAMS ((splay_tree_node, void *));
static splay_tree_node find_or_create_entry PARAMS ((cpp_reader *,
const char *));
static void handle_missing_header PARAMS ((cpp_reader *, const char *, int));
static int remove_component_p PARAMS ((const char *));
void
_cpp_init_includes (pfile)
cpp_reader *pfile;
{
pfile->all_include_files
= splay_tree_new ((splay_tree_compare_fn) strcmp,
(splay_tree_delete_key_fn) free,
destroy_node);
}
void
_cpp_cleanup_includes (pfile)
cpp_reader *pfile;
{
splay_tree_delete (pfile->all_include_files);
}
static void
destroy_node (v)
splay_tree_value v;
{
struct include_file *f = (struct include_file *)v;
if (f)
{
purge_cache (f);
free (f);
}
}
void
_cpp_never_reread (file)
struct include_file *file;
{
file->cmacro = NEVER_REREAD;
}
static splay_tree_node
find_or_create_entry (pfile, fname)
cpp_reader *pfile;
const char *fname;
{
splay_tree_node node;
struct include_file *file;
char *name = xstrdup (fname);
_cpp_simplify_pathname (name);
node = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
if (node)
free (name);
else
{
file = xcnew (struct include_file);
file->name = name;
file->err_no = errno;
node = splay_tree_insert (pfile->all_include_files,
(splay_tree_key) file->name,
(splay_tree_value) file);
}
return node;
}
void
_cpp_fake_include (pfile, fname)
cpp_reader *pfile;
const char *fname;
{
find_or_create_entry (pfile, fname);
}
static ino_t new_inode;
static dev_t new_device;
static struct include_file *repl_file;
static int inode_finder PARAMS ((splay_tree_node, void *data));
static int
inode_finder (x, data)
splay_tree_node x;
void *data ATTRIBUTE_UNUSED;
{
ino_t inode = 0;
dev_t device = 0;
if ((repl_file = (struct include_file *)x->value))
{
inode = repl_file->st.st_ino;
device = repl_file->st.st_dev;
if (inode == new_inode && device == new_device && DO_NOT_REREAD (repl_file))
return 1;
}
return 0;
}
static struct include_file *
open_file (pfile, filename)
cpp_reader *pfile;
const char *filename;
{
splay_tree_node nd = find_or_create_entry (pfile, filename);
struct include_file *file = (struct include_file *) nd->value;
if (file->err_no)
{
errno = file->err_no;
return 0;
}
if (DO_NOT_REREAD (file))
return file;
if (file->buffer != NULL)
return file;
if (filename[0] == '\0')
file->fd = 0;
else
file->fd = open (file->name, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
{
new_inode = file->st.st_ino;
new_device = file->st.st_dev;
if (splay_tree_foreach (pfile->all_include_files, inode_finder, 0))
{
close (file->fd);
file->fd = -1;
return repl_file;
}
if (!S_ISDIR (file->st.st_mode))
return file;
errno = ENOENT;
close (file->fd);
file->fd = -1;
}
file->err_no = errno;
return 0;
}
static bool
stack_include_file (pfile, inc)
cpp_reader *pfile;
struct include_file *inc;
{
cpp_buffer *fp;
int sysp;
const char *filename;
if (DO_NOT_REREAD (inc))
return false;
sysp = MAX ((pfile->map ? pfile->map->sysp : 0),
(inc->foundhere ? inc->foundhere->sysp : 0));
if (CPP_OPTION (pfile, print_deps) > sysp && !inc->include_count)
deps_add_dep (pfile->deps, inc->name);
if (! inc->buffer)
{
if (read_include_file (pfile, inc))
{
_cpp_never_reread (inc);
return false;
}
if (S_ISREG (inc->st.st_mode) && inc->st.st_size == 0)
_cpp_never_reread (inc);
close (inc->fd);
inc->fd = -1;
}
if (pfile->buffer)
inc->include_count++;
fp = cpp_push_buffer (pfile, inc->buffer, inc->st.st_size,
CPP_OPTION (pfile, preprocessed), 0);
fp->inc = inc;
fp->inc->refcnt++;
pfile->mi_valid = true;
pfile->mi_cmacro = 0;
filename = inc->name;
if (*filename == '\0')
filename = "<stdin>";
_cpp_do_file_change (pfile, LC_ENTER, filename, 1, sysp);
return true;
}
static int
read_include_file (pfile, inc)
cpp_reader *pfile;
struct include_file *inc;
{
ssize_t size, offset, count;
U_CHAR *buf;
#if MMAP_THRESHOLD
static int pagesize = -1;
#endif
if (S_ISREG (inc->st.st_mode))
{
if (inc->st.st_size > INTTYPE_MAXIMUM (ssize_t))
{
cpp_error (pfile, "%s is too large", inc->name);
goto fail;
}
size = inc->st.st_size;
inc->mapped = 0;
#if MMAP_THRESHOLD
#if USING_DARWIN_MMAP
if (pagesize == -1)
{
pagesize = getpagesize ();
if (host_kernel_version (mach_host_self (), darwin_kernel_version))
darwin_mmap_allowed = 0;
else
{
char *s = strchr(darwin_kernel_version, '.');
if (s && *(s-2) == ' ' && *(s-1) < '6')
darwin_mmap_allowed = 0;
else
darwin_mmap_allowed = 1;
}
}
if (darwin_mmap_allowed &&
size / pagesize >= MMAP_THRESHOLD
&& (size % pagesize) != 0)
{
buf = (U_CHAR *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
if (buf == (U_CHAR *)-1)
goto perror_fail;
inc->mapped = 1;
}
else
#else
if (pagesize == -1)
pagesize = getpagesize ();
if (SHOULD_MMAP (size, pagesize))
{
buf = (U_CHAR *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
if (buf == (U_CHAR *)-1)
goto perror_fail;
inc->mapped = 1;
}
else
#endif
#endif
{
buf = (U_CHAR *) xmalloc (size + 1);
offset = 0;
while (offset < size)
{
count = read (inc->fd, buf + offset, size - offset);
if (count < 0)
goto perror_fail;
if (count == 0)
{
if (!STAT_SIZE_TOO_BIG (inc->st))
cpp_warning
(pfile, "%s is shorter than expected", inc->name);
size = offset;
buf = xrealloc (buf, size + 1);
inc->st.st_size = size;
break;
}
offset += count;
}
buf[size] = '\0';
}
}
else if (S_ISBLK (inc->st.st_mode))
{
cpp_error (pfile, "%s is a block device", inc->name);
goto fail;
}
else
{
size = 8 * 1024;
buf = (U_CHAR *) xmalloc (size + 1);
offset = 0;
while ((count = read (inc->fd, buf + offset, size - offset)) > 0)
{
offset += count;
if (offset == size)
{
size *= 2;
buf = xrealloc (buf, size + 1);
}
}
if (count < 0)
goto perror_fail;
if (offset + 1 < size)
buf = xrealloc (buf, offset + 1);
buf[offset] = '\0';
inc->st.st_size = offset;
}
inc->buffer = buf;
return 0;
perror_fail:
cpp_error_from_errno (pfile, inc->name);
fail:
return 1;
}
static void
purge_cache (inc)
struct include_file *inc;
{
if (inc->buffer)
{
#if MMAP_THRESHOLD
if (inc->mapped)
munmap ((PTR) inc->buffer, inc->st.st_size);
else
#endif
free ((PTR) inc->buffer);
inc->buffer = NULL;
}
}
int
cpp_included (pfile, fname)
cpp_reader *pfile;
const char *fname;
{
struct search_path *path;
char *name, *n;
splay_tree_node nd;
if (IS_ABSOLUTE_PATHNAME (fname))
{
nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname);
return (nd && nd->value);
}
name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2);
for (path = CPP_OPTION (pfile, quote_include); path; path = path->next)
{
memcpy (name, path->name, path->len);
name[path->len] = '/';
strcpy (&name[path->len + 1], fname);
if (CPP_OPTION (pfile, remap))
n = remap_filename (pfile, name, path);
else
n = name;
nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) n);
if (nd && nd->value)
return 1;
}
return 0;
}
static struct include_file *
find_include_file (pfile, header, type)
cpp_reader *pfile;
const cpp_token *header;
enum include_type type;
{
const char *fname = (const char *) header->val.str.text;
struct search_path *path;
struct search_path *saved_path;
struct include_file *file;
char *name, *n;
if (IS_ABSOLUTE_PATHNAME (fname))
return open_file (pfile, fname);
if (type == IT_INCLUDE_NEXT && pfile->buffer->inc->foundhere)
path = pfile->buffer->inc->foundhere->next;
else if (header->type == CPP_HEADER_NAME)
path = CPP_OPTION (pfile, bracket_include);
else
path = search_from (pfile, type);
if (path == NULL)
{
cpp_error (pfile, "no include path in which to find %s", fname);
return NO_INCLUDE_PATH;
}
name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2 + 500);
if ((type != IT_INCLUDE_NEXT) &&
(CPP_OPTION (pfile, bracket_include) == CPP_OPTION (pfile, quote_include)))
{
if ((file = find_include_file_in_hashtable (pfile, fname, name, header->type, path)))
return file;
}
for (; path; path = path->next)
{
saved_path = path;
if (path == CPP_OPTION (pfile, bracket_include)
&& CPP_OPTION (pfile, header_map))
path = hmap_lookup_path (pfile, &fname);
{
int len = path->len;
memcpy (name, path->name, len);
if (name[len-1] == '/')
len--;
name[len] = '/';
strcpy (&name[len + 1], fname);
}
if (CPP_OPTION (pfile, remap))
n = remap_filename (pfile, name, path);
else
n = name;
file = open_file (pfile, n);
if (file)
{
file->foundhere = path;
return file;
}
else
{
if (saved_path == CPP_OPTION (pfile, bracket_include)
&& CPP_OPTION (pfile, header_map))
{
path = saved_path;
}
}
}
return 0;
}
#ifdef FRAMEWORK_HEADERS
static struct include_file *
find_framework_file (pfile, header, type)
cpp_reader *pfile;
const cpp_token *header;
enum include_type type ATTRIBUTE_UNUSED;
{
struct include_file *inc = NULL;
const char *fname = (const char *) header->val.str.text;
struct search_path *path;
struct include_file *file;
char *n, *frname;
U_CHAR *bufptr;
int frname_len, position, slash_position, index;
if (fname == NULL)
return 0;
path = NULL;
path = CPP_OPTION (pfile, framework_include);
if (path == NULL)
{
cpp_error (pfile, "No include path in which to find %s", fname);
return NO_INCLUDE_PATH;
}
bufptr = NULL;
slash_position = -1;
position = 0;
for (bufptr = (U_CHAR *) fname; bufptr != NULL; bufptr++)
{
if (position > strlen(fname))
break;
if (*bufptr == '/')
{
slash_position = position;
break;
}
position++;
}
if (slash_position == -1)
return 0;
frname = (char *) alloca (strlen (fname) + pfile->max_include_len + 2 + 25);
for (; path; path = path->next)
{
strncpy (&frname[0], path->name, path->len);
frname[path->len] = '/';
frname_len = path->len + 1;
strncpy (&frname[frname_len], fname, slash_position);
frname_len += slash_position;
strncpy (&frname[frname_len], ".framework/", 11);
frname_len += 11;
for (index = 0; framework_header_dirs[index].dirName; index++)
{
strncpy (&frname[frname_len],
framework_header_dirs[index].dirName,
framework_header_dirs[index].dirNameLen);
strcpy (&frname[frname_len + framework_header_dirs[index].dirNameLen],
&fname[slash_position]);
if (CPP_OPTION (pfile, remap))
n = remap_filename (pfile, frname, path);
else
n = frname;
file = open_file (pfile, n);
if (file)
{
file->foundhere = path;
return file;
}
}
}
path = CPP_OPTION (pfile, framework_include);
for (; path; path = path->next)
{
inc = find_subframework_file (pfile, header, path);
if (inc)
return inc;
}
return 0;
}
static struct include_file *
find_subframework_file (pfile, header, path)
cpp_reader *pfile;
const cpp_token *header;
struct search_path *path;
{
const char *fname = (const char *) header->val.str.text;
const char *pname;
struct include_file *file;
char *n, *sfrname;
const char *dot_framework = ".framework/";
char *bufptr;
int sfrname_len, position, index;
struct cpp_buffer *b;
for (b = pfile->buffer; b && b->inc && b->inc->name; b = b->prev)
{
pname = b->inc->name;
bufptr = NULL;
position = 0;
for (bufptr = (char *) fname; bufptr != NULL; bufptr++)
{
if (*bufptr == '/')
break;
position++;
}
if (position == 0)
return 0;
bufptr = NULL;
bufptr = strstr (pname, dot_framework);
if (!bufptr)
return 0;
sfrname = (char *) alloca (strlen (pname) + strlen (fname) + 2 + 36);
bufptr += strlen (dot_framework);
sfrname_len = bufptr - pname;
strncpy (&sfrname[0], pname, sfrname_len);
strncpy (&sfrname[sfrname_len], "Frameworks/", 11);
sfrname_len += 11;
strncpy (&sfrname[sfrname_len], fname, position);
sfrname_len += position;
strncpy (&sfrname[sfrname_len], ".framework/", 11);
sfrname_len += 11;
for (index = 0; framework_header_dirs[index].dirName; index++)
{
strncpy (&sfrname[sfrname_len],
framework_header_dirs[index].dirName,
framework_header_dirs[index].dirNameLen);
strcpy (&sfrname[sfrname_len + framework_header_dirs[index].dirNameLen],
&fname[position]);
if (CPP_OPTION (pfile, remap))
n = remap_filename (pfile, sfrname, path);
else
n = sfrname;
file = open_file (pfile, n);
if (file)
{
file->foundhere = path;
return file;
}
}
}
return 0;
}
#endif
void
cpp_make_system_header (pfile, syshdr, externc)
cpp_reader *pfile;
int syshdr, externc;
{
int flags = 0;
if (syshdr)
flags = 1 + (externc != 0);
_cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file,
SOURCE_LINE (pfile->map, pfile->line), flags);
}
void
_cpp_report_missing_guards (pfile)
cpp_reader *pfile;
{
int banner = 0;
splay_tree_foreach (pfile->all_include_files, report_missing_guard,
(PTR) &banner);
}
static int
report_missing_guard (n, b)
splay_tree_node n;
void *b;
{
struct include_file *f = (struct include_file *) n->value;
int *bannerp = (int *)b;
if (f && f->cmacro == 0 && f->include_count == 1)
{
if (*bannerp == 0)
{
fputs (_("Multiple include guards may be useful for:\n"), stderr);
*bannerp = 1;
}
fputs (f->name, stderr);
putc ('\n', stderr);
}
return 0;
}
static void
handle_missing_header (pfile, fname, angle_brackets)
cpp_reader *pfile;
const char *fname;
int angle_brackets;
{
int print_dep = CPP_PRINT_DEPS(pfile) > (angle_brackets || pfile->map->sysp);
if (CPP_OPTION (pfile, print_deps_missing_files) && print_dep)
{
if (!angle_brackets || IS_ABSOLUTE_PATHNAME (fname))
deps_add_dep (pfile->deps, fname);
else
{
struct search_path *ptr = CPP_OPTION (pfile, bracket_include);
char *p;
int len = 0, fname_len = strlen (fname);
if (ptr)
len = ptr->len;
p = (char *) alloca (len + fname_len + 2);
if (len)
{
memcpy (p, ptr->name, len);
p[len++] = '/';
}
memcpy (p + len, fname, fname_len + 1);
deps_add_dep (pfile->deps, p);
}
}
else if (CPP_PRINT_DEPS (pfile) && ! print_dep)
cpp_warning (pfile, "%s: %s", fname, xstrerror (errno));
else
cpp_error_from_errno (pfile, fname);
}
bool
_cpp_execute_include (pfile, header, type)
cpp_reader *pfile;
const cpp_token *header;
enum include_type type;
{
bool stacked = false;
struct include_file *inc = find_include_file (pfile, header, type);
#ifdef FRAMEWORK_HEADERS
if (inc == 0)
inc = find_framework_file (pfile, header, type);
#endif
if (inc == 0)
handle_missing_header (pfile, (const char *) header->val.str.text,
header->type == CPP_HEADER_NAME);
if (inc && inc != NO_INCLUDE_PATH)
{
if (type == IT_IMPORT && inc->include_count)
_cpp_never_reread (inc);
#ifdef PFE
if (pfe_operation == PFE_LOAD)
{
if (pfe_check_header (inc->name, inc->st.st_mtime,
inc->st.st_ino))
{
close (inc->fd);
inc->fd = -1;
return 0;
}
}
else if (pfe_operation == PFE_DUMP)
{
pfe_add_header_name (inc->name, inc->st.st_mtime,
inc->st.st_ino);
}
#endif
stacked = stack_include_file (pfile, inc);
if (type == IT_IMPORT)
_cpp_never_reread (inc);
}
if (stacked && flag_gen_index_original)
process_header_indexing ((char *)inc->name, PB_INDEX_BEGIN);
return stacked;
}
int
_cpp_compare_file_date (pfile, header)
cpp_reader *pfile;
const cpp_token *header;
{
struct include_file *inc = find_include_file (pfile, header, 0);
if (inc == NULL || inc == NO_INCLUDE_PATH)
return -1;
if (inc->fd > 0)
{
close (inc->fd);
inc->fd = -1;
}
return inc->st.st_mtime > pfile->buffer->inc->st.st_mtime;
}
bool
_cpp_read_file (pfile, fname)
cpp_reader *pfile;
const char *fname;
{
struct include_file *f = open_file (pfile, fname);
if (f == NULL)
{
cpp_error_from_errno (pfile, fname);
return false;
}
return stack_include_file (pfile, f);
}
bool
_cpp_pop_file_buffer (pfile, inc)
cpp_reader *pfile;
struct include_file *inc;
{
bool pushed = false;
if (pfile->mi_valid && inc->cmacro == NULL)
inc->cmacro = pfile->mi_cmacro;
pfile->mi_valid = false;
inc->refcnt--;
if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
purge_cache (inc);
if (pfile->buffer)
{
_cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
if (!pfile->buffer->prev)
pushed = _cpp_push_next_buffer (pfile);
}
return pushed;
}
static struct search_path *
search_from (pfile, type)
cpp_reader *pfile;
enum include_type type;
{
cpp_buffer *buffer = pfile->buffer;
unsigned int dlen;
if (type == IT_CMDLINE)
goto use_cwd;
if (CPP_OPTION (pfile, ignore_srcdir))
return CPP_OPTION (pfile, quote_include);
if (! buffer->search_cached)
{
buffer->search_cached = 1;
dlen = lbasename (buffer->inc->name) - buffer->inc->name;
if (dlen)
{
buffer->dir.name = buffer->inc->name;
if (dlen > 1)
dlen--;
}
else
{
use_cwd:
buffer->dir.name = ".";
dlen = 1;
}
if (dlen > pfile->max_include_len)
pfile->max_include_len = dlen;
buffer->dir.len = dlen;
buffer->dir.next = CPP_OPTION (pfile, quote_include);
buffer->dir.sysp = pfile->map->sysp;
}
return &buffer->dir;
}
struct file_name_map
{
struct file_name_map *map_next;
char *map_from;
char *map_to;
};
#define FILE_NAME_MAP_FILE "header.gcc"
static char *
read_filename_string (ch, f)
int ch;
FILE *f;
{
char *alloc, *set;
int len;
len = 20;
set = alloc = xmalloc (len + 1);
if (! is_space(ch))
{
*set++ = ch;
while ((ch = getc (f)) != EOF && ! is_space(ch))
{
if (set - alloc == len)
{
len *= 2;
alloc = xrealloc (alloc, len + 1);
set = alloc + len / 2;
}
*set++ = ch;
}
}
*set = '\0';
ungetc (ch, f);
return alloc;
}
struct file_name_map_list
{
struct file_name_map_list *map_list_next;
char *map_list_name;
struct file_name_map *map_list_map;
};
static struct file_name_map *
read_name_map (pfile, dirname)
cpp_reader *pfile;
const char *dirname;
{
struct file_name_map_list *map_list_ptr;
char *name;
FILE *f;
for (map_list_ptr = CPP_OPTION (pfile, map_list); map_list_ptr;
map_list_ptr = map_list_ptr->map_list_next)
if (! strcmp (map_list_ptr->map_list_name, dirname))
return map_list_ptr->map_list_map;
map_list_ptr = ((struct file_name_map_list *)
xmalloc (sizeof (struct file_name_map_list)));
map_list_ptr->map_list_name = xstrdup (dirname);
map_list_ptr->map_list_map = NULL;
name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
strcpy (name, dirname);
if (*dirname)
strcat (name, "/");
strcat (name, FILE_NAME_MAP_FILE);
f = fopen (name, "r");
if (f)
{
int ch;
int dirlen = strlen (dirname);
while ((ch = getc (f)) != EOF)
{
char *from, *to;
struct file_name_map *ptr;
if (is_space(ch))
continue;
from = read_filename_string (ch, f);
while ((ch = getc (f)) != EOF && is_hspace(ch))
;
to = read_filename_string (ch, f);
ptr = ((struct file_name_map *)
xmalloc (sizeof (struct file_name_map)));
ptr->map_from = from;
if (IS_ABSOLUTE_PATHNAME (to))
ptr->map_to = to;
else
{
ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
strcpy (ptr->map_to, dirname);
ptr->map_to[dirlen] = '/';
strcpy (ptr->map_to + dirlen + 1, to);
free (to);
}
ptr->map_next = map_list_ptr->map_list_map;
map_list_ptr->map_list_map = ptr;
while ((ch = getc (f)) != '\n')
if (ch == EOF)
break;
}
fclose (f);
}
map_list_ptr->map_list_next = CPP_OPTION (pfile, map_list);
CPP_OPTION (pfile, map_list) = map_list_ptr;
return map_list_ptr->map_list_map;
}
static char *
remap_filename (pfile, name, loc)
cpp_reader *pfile;
char *name;
struct search_path *loc;
{
struct file_name_map *map;
const char *from, *p;
char *dir;
if (! loc->name_map)
{
char *dname = alloca (loc->len + 1);
memcpy (dname, loc->name, loc->len);
dname[loc->len] = '\0';
loc->name_map = read_name_map (pfile, dname);
if (! loc->name_map)
return name;
}
from = name + loc->len + 1;
for (map = loc->name_map; map; map = map->map_next)
if (!strcmp (map->map_from, from))
return map->map_to;
p = strrchr (name, '/');
if (!p)
return name;
if (p == name)
cpp_ice (pfile, "absolute file name in remap_filename");
dir = (char *) alloca (p - name + 1);
memcpy (dir, name, p - name);
dir[p - name] = '\0';
from = p + 1;
for (map = read_name_map (pfile, dir); map; map = map->map_next)
if (! strcmp (map->map_from, from))
return map->map_to;
return name;
}
static int
remove_component_p (path)
const char *path;
{
struct stat s;
int result;
#ifdef HAVE_LSTAT
result = lstat (path, &s);
#else
result = stat (path, &s);
#endif
if (result == 0)
errno = 0;
return result == 0 && S_ISDIR (s.st_mode);
}
char *
_cpp_simplify_pathname (path)
char *path;
{
#ifndef VMS
char *from, *to;
char *base, *orig_base;
int absolute = 0;
errno = 0;
if (*path == '\0')
return path;
#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
for (from = path; *from; from++)
if (*from == '\\') *from = '/';
if (ISALPHA (path[0]) && path[1] == ':')
from = to = &path[2];
else
from = to = path;
#else
from = to = path;
#endif
if (*from == '/')
{
absolute = 1;
to++;
from++;
if (*from == '/')
{
if (*++from == '/')
while (*++from == '/');
else
to++;
}
}
base = orig_base = to;
for (;;)
{
int move_base = 0;
while (*from == '/')
from++;
if (*from == '\0')
break;
if (*from == '.')
{
if (from[1] == '\0')
break;
if (from[1] == '/')
{
from += 2;
continue;
}
else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
{
if (absolute && orig_base == to)
{
from += 2;
continue;
}
if (base != to && errno == 0)
{
*to = '\0';
if (remove_component_p (path))
{
while (to > base && *to != '/')
to--;
from += 2;
continue;
}
}
move_base = 1;
}
}
if (to > orig_base)
*to++ = '/';
while (*from != '\0' && *from != '/')
*to++ = *from++;
if (move_base)
base = to;
}
if (to == path)
*to++ = '.';
*to = '\0';
return path;
#else
errno = 0;
return path;
#endif
}
#include <dirent.h>
#include "hashtab.h"
static htab_t header_htab = 0;
struct hashed_attribute
{
struct search_path *include_directory;
struct hashed_attribute *next;
};
struct hashed_entry
{
char file_name[MAXNAMLEN + 1];
struct search_path *include_directory;
struct hashed_attribute *list;
};
static hashval_t hashed_entry_hash PARAMS ((const void *x));
static int hashed_entry_eq PARAMS ((const void *x, const void *y));
static void hash_enter PARAMS ((struct hashed_entry **, const char *, struct search_path *));
static void hash_add_attr PARAMS ((struct hashed_entry *, struct search_path *));
static void _load_include_headers PARAMS ((cpp_reader *, htab_t, char *));
static void _load_framework_directories PARAMS ((cpp_reader *, htab_t, char *));
static hashval_t
hashed_entry_hash (p)
const PTR p;
{
const struct hashed_entry *old = p;
return htab_hash_string (old->file_name);
}
static int
hashed_entry_eq (p1, p2)
const PTR p1;
const PTR p2;
{
const struct hashed_entry *old = p1;
const char *new = p2;
return strcmp (old->file_name, new) == 0;
}
static void
hash_enter (slot, file_name, include_directory)
struct hashed_entry **slot;
const char *file_name;
struct search_path *include_directory;
{
struct hashed_entry *obj = (struct hashed_entry *) xmalloc (sizeof (struct hashed_entry));
*slot = obj;
obj->list = 0;
strcpy(obj->file_name, file_name);
obj->include_directory = include_directory;
}
static void
hash_add_attr (entry, value)
struct hashed_entry * entry;
struct search_path *value;
{
struct hashed_attribute *obj = (struct hashed_attribute *) xmalloc (sizeof (struct hashed_attribute));
struct hashed_attribute *list = entry->list;
obj->include_directory = value;
obj->next = 0;
if (list)
{
while (list->next) list = list->next;
list->next = obj;
}
else
entry->list = obj;
}
static void
_load_include_headers (pfile, includehash, name)
cpp_reader *pfile;
htab_t includehash;
char *name;
{
struct search_path *path = CPP_OPTION (pfile, bracket_include);
for (; path; path = path->next)
{
DIR *directory;
struct dirent *directory_entry;
memcpy (name, path->name, path->len);
name[path->len] = 0;
directory = opendir(name);
while ((directory_entry = readdir(directory)) != NULL)
{
if (directory_entry->d_name[0] == '.') continue;
else if (directory_entry->d_type == DT_REG || directory_entry->d_type == DT_DIR ||
directory_entry->d_type == DT_UNKNOWN)
{
struct hashed_entry **slot, *entry;
slot = (struct hashed_entry **)htab_find_slot_with_hash (includehash, directory_entry->d_name,
htab_hash_string (directory_entry->d_name), INSERT);
entry = *slot;
if (!entry)
hash_enter (slot, directory_entry->d_name, path);
else
hash_add_attr (entry, path);
}
}
closedir(directory);
}
}
static void
_load_framework_directories (pfile, frameworkhash, name)
cpp_reader *pfile;
htab_t frameworkhash;
char *name;
{
struct search_path *path;
path = CPP_OPTION (pfile, framework_include);
if (path)
{
for (; path; path = path->next)
{
DIR *directory;
struct dirent *directory_entry;
memcpy (name, path->name, path->len);
name[path->len] = 0;
directory = opendir(name);
while ((directory_entry = readdir(directory)) != NULL)
{
if (directory_entry->d_name[0] == '.') continue;
else if (directory_entry->d_type == DT_DIR) {
struct hashed_entry **slot, *entry;
slot = (struct hashed_entry **)htab_find_slot_with_hash (frameworkhash, directory_entry->d_name,
htab_hash_string (directory_entry->d_name), INSERT);
entry = *slot;
if (!entry)
hash_enter (slot, directory_entry->d_name, path);
else
hash_add_attr (entry, path);
}
}
closedir(directory);
} }
}
static void
_init_include_hash(pfile, name)
cpp_reader *pfile;
char *name;
{
header_htab = htab_create (2039, hashed_entry_hash, hashed_entry_eq, NULL);
_load_include_headers(pfile, header_htab, name);
_load_framework_directories(pfile, header_htab, name);
}
static void
synthesize_name_from_path(name, path, fname)
char *name;
struct search_path *path;
const char *fname;
{
int len = path->len;
memcpy(name, path->name, len);
if (name[len-1] == '/')
len--;
name[len] = '/';
strcpy (&name[len + 1], fname);
}
static struct include_file *
find_include_file_in_hashtable (pfile, fname, name, type, path)
cpp_reader *pfile;
const char *fname;
char *name;
enum include_type type;
struct search_path *path;
{
char *slash_in_fname = strrchr(fname, '/');
struct hashed_entry *entry;
struct include_file *file;
if (!header_htab)
_init_include_hash(pfile, name);
if ((type == CPP_STRING) && (path != CPP_OPTION (pfile, bracket_include)))
{
synthesize_name_from_path(name, path, fname);
if ((file = open_file (pfile, name)))
{
file->foundhere = path;
return file;
}
}
if (CPP_OPTION (pfile, header_map))
{
struct search_path *hmap_path = hmap_lookup_path (pfile, &fname);
if (hmap_path != CPP_OPTION (pfile, bracket_include))
{
synthesize_name_from_path(name, hmap_path, fname);
if ((file = open_file (pfile, name)))
{
file->foundhere = hmap_path;
return file;
}
}
}
if (!slash_in_fname)
{
if ((entry = htab_find(header_htab, fname)))
{
synthesize_name_from_path(name, entry->include_directory, fname);
if ((file = open_file (pfile, name)))
{
file->foundhere = entry->include_directory;
return file;
}
}
}
else
{
char *basename = strchr(fname, '/');
memcpy(name, fname, basename-fname);
name[basename-fname] = 0;
if ((entry = htab_find(header_htab, name)))
{
synthesize_name_from_path(name, entry->include_directory, fname);
if ((file = open_file (pfile, name)))
{
file->foundhere = entry->include_directory;
return file;
}
else if (entry->list) {
struct hashed_attribute *hattr = entry->list;
do
{
synthesize_name_from_path(name, hattr->include_directory, fname);
if ((file = open_file (pfile, name)))
{
file->foundhere = hattr->include_directory;
return file;
}
}
while ((hattr = hattr->next));
}
}
memcpy(name, fname, basename-fname);
name[basename-fname] = 0;
strcat(name, ".framework");
if ((entry = htab_find(header_htab, name)))
{
int len = entry->include_directory->len;
memcpy(name, entry->include_directory->name, entry->include_directory->len);
name[len] = '/';
strcpy (&name[len + 1], entry->file_name);
strcat (name, "/Headers");
strcat (name, basename); if ((file = open_file (pfile, name)))
{
file->foundhere = entry->include_directory;
return file;
}
memcpy(name, entry->include_directory->name, entry->include_directory->len);
name[len] = '/';
strcpy (&name[len + 1], entry->file_name);
strcat (name, "/PrivateHeaders");
strcat (name, basename); if ((file = open_file (pfile, name)))
{
file->foundhere = entry->include_directory;
return file;
}
}
}
return 0;
}
#ifdef DEBUG
extern cpp_reader *parse_in;
static int found = 0, not_found = 0;
static int total_size = 0;
static int
splay_func (n, b)
splay_tree_node n;
void *b;
{
struct include_file *f = (struct include_file *) n->value;
int *bannerp = (int *)b;
ssize_t size = f->st.st_size;
if (f->st.st_ino)
{
if (parse_in->buffer->inc == f)
{
; }
else
{
total_size += size;
}
found++;
}
else
{
not_found++;
}
return 0;
}
void
cpp_log (pfile)
{
int banner = 0;
struct include_file *f = parse_in->buffer->inc;
ssize_t size = f->st.st_size;
found = 0; not_found = 0;
splay_tree_foreach (parse_in->all_include_files, splay_func, (PTR) &banner);
fprintf(stderr, "=> module %s %d header %d found %d nfound %d\n", f->name, size, total_size,
found, not_found);
}
#endif