#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "prefix.h"
#include "intl.h"
#include "mkdeps.h"
#include "cppdefault.h"
#include "tree.h"
#include "c-common.h"
#include <ctype.h>
#ifdef FRAMEWORK_HEADERS
struct { const char *path; int u1; }
framework_paths_defaults_array [] = {
{"/System/Library/Frameworks", 0},
{"/Library/Frameworks", 0},
{"/Local/Library/Frameworks", 0},
{NULL, 0}
};
#endif
#ifdef VMS
# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A)))
# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC))
#else
# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__
# define INO_T_EQ(A, B) 0
# else
# define INO_T_EQ(A, B) ((A) == (B))
# endif
# define INO_T_COPY(DEST, SRC) (DEST) = (SRC)
#endif
typedef void (* cl_directive_handler) PARAMS ((cpp_reader *, const char *));
struct pending_option
{
struct pending_option *next;
const char *arg;
cl_directive_handler handler;
};
struct cpp_pending
{
struct pending_option *directive_head, *directive_tail;
struct search_path *quote_head, *quote_tail;
struct search_path *brack_head, *brack_tail;
struct search_path *systm_head, *systm_tail;
struct search_path *after_head, *after_tail;
#ifdef FRAMEWORK_HEADERS
struct search_path *framework_system_head, *framework_system_tail;
struct search_path *framework_head, *framework_tail;
#endif
struct pending_option *imacros_head, *imacros_tail;
struct pending_option *include_head, *include_tail;
};
#ifdef __STDC__
#define APPEND(pend, list, elt) \
do { if (!(pend)->list##_head) (pend)->list##_head = (elt); \
else (pend)->list##_tail->next = (elt); \
(pend)->list##_tail = (elt); \
} while (0)
#else
#define APPEND(pend, list, elt) \
do { if (!(pend)->list_head) (pend)->list_head = (elt); \
else (pend)->list_tail->next = (elt); \
(pend)->list_tail = (elt); \
} while (0)
#endif
static void path_include PARAMS ((cpp_reader *,
char *, int));
static void init_library PARAMS ((void));
static void init_builtins PARAMS ((cpp_reader *));
static void mark_named_operators PARAMS ((cpp_reader *));
static void append_include_chain PARAMS ((cpp_reader *,
char *, int, int));
static struct search_path * remove_dup_dir PARAMS ((cpp_reader *,
struct search_path *,
struct search_path **));
static struct search_path * remove_dup_nonsys_dirs PARAMS ((cpp_reader *,
struct search_path **,
struct search_path *));
static struct search_path * remove_dup_dirs PARAMS ((cpp_reader *,
struct search_path **));
static void merge_include_chains PARAMS ((cpp_reader *));
static bool push_include PARAMS ((cpp_reader *,
struct pending_option *));
static void free_chain PARAMS ((struct pending_option *));
static void init_standard_includes PARAMS ((cpp_reader *));
#ifdef FRAMEWORK_HEADERS
static void init_standard_frameworks PARAMS ((cpp_reader *));
#endif
static void read_original_filename PARAMS ((cpp_reader *));
static void read_original_directory PARAMS ((cpp_reader *));
static void new_pending_directive PARAMS ((struct cpp_pending *,
const char *,
cl_directive_handler));
static int parse_option PARAMS ((const char *));
static void post_options PARAMS ((cpp_reader *));
static inline uint32 hmap_hash_string PARAMS ((const char *));
static inline unsigned hmap_compare_strings PARAMS ((const char *,
const char *));
static struct hmap_header_map * hmap_load_header_map PARAMS ((const char *));
static void hmap_free_header_map PARAMS ((cpp_reader *));
static FILE *ilog_open PARAMS ((const char *));
static void ilog_close PARAMS ((cpp_reader *));
enum { BRACKET = 0, SYSTEM, AFTER, FRAMEWORK, FRAMEWORK_SYSTEM, HMAPFILE };
#if HAVE_DESIGNATED_INITIALIZERS
#define init_trigraph_map()
#define TRIGRAPH_MAP \
__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = {
#define END };
#define s(p, v) [p] = v,
#else
#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
static void init_trigraph_map PARAMS ((void)) { \
unsigned char *x = _cpp_trigraph_map;
#define END }
#define s(p, v) x[p] = v;
#endif
TRIGRAPH_MAP
s('=', '#') s(')', ']') s('!', '|')
s('(', '[') s('\'', '^') s('>', '}')
s('/', '\\') s('<', '{') s('-', '~')
END
#undef s
#undef END
#undef TRIGRAPH_MAP
static void
path_include (pfile, list, path)
cpp_reader *pfile;
char *list;
int path;
{
char *p, *q, *name;
p = list;
do
{
q = p;
while (*q != 0 && *q != PATH_SEPARATOR) q++;
if (q == p)
{
name = (char *) xmalloc (2);
name[0] = '.';
name[1] = 0;
}
else
{
name = (char *) xmalloc (q - p + 1);
memcpy (name, p, q - p);
name[q - p] = 0;
}
append_include_chain (pfile, name, path, path == SYSTEM);
if (*q == 0)
break;
p = q + 1;
}
while (1);
}
static void
append_include_chain (pfile, dir, path, cxx_aware)
cpp_reader *pfile;
char *dir;
int path;
int cxx_aware;
{
struct cpp_pending *pend = CPP_OPTION (pfile, pending);
struct search_path *new;
struct stat st;
unsigned int len;
if (path == HMAPFILE && CPP_OPTION (pfile, hmap_path))
{
free (CPP_OPTION (pfile, hmap_path));
CPP_OPTION (pfile, hmap_path) = 0;
}
if (*dir == '\0')
{
free (dir);
dir = xstrdup (".");
}
_cpp_simplify_pathname (dir);
if (stat (dir, &st))
{
if (errno != ENOENT)
cpp_errno (pfile, DL_ERROR, dir);
else if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
free (dir);
return;
}
if (!S_ISDIR (st.st_mode))
{
cpp_error_with_line (pfile, DL_ERROR, 0, 0, "%s: Not a directory", dir);
free (dir);
return;
}
len = strlen (dir);
if (len > pfile->max_include_len)
pfile->max_include_len = len;
new = (struct search_path *) xmalloc (sizeof (struct search_path));
new->name = dir;
new->len = len;
INO_T_COPY (new->ino, st.st_ino);
new->dev = st.st_dev;
#ifdef FRAMEWORK_HEADERS
if (path == SYSTEM || path == AFTER || path == FRAMEWORK_SYSTEM)
#else
if (path == SYSTEM || path == AFTER)
#endif
new->sysp = cxx_aware ? 1 : 2;
else
new->sysp = 0;
new->name_map = NULL;
new->next = NULL;
switch (path)
{
case BRACKET: APPEND (pend, brack, new); break;
case SYSTEM: APPEND (pend, systm, new); break;
case AFTER: APPEND (pend, after, new); break;
#ifdef FRAMEWORK_HEADERS
case FRAMEWORK_SYSTEM: APPEND (pend, framework_system, new); break;
case FRAMEWORK: APPEND (pend, framework, new); break;
#endif
case HMAPFILE:
new->next = CPP_OPTION (pfile, bracket_include);
CPP_OPTION (pfile, hmap_path) = new;
break;
}
}
static struct search_path *
remove_dup_dir (pfile, prev, head_ptr)
cpp_reader *pfile;
struct search_path *prev;
struct search_path **head_ptr;
{
struct search_path *cur;
if (prev != NULL)
{
cur = prev->next;
prev->next = cur->next;
}
else
{
cur = *head_ptr;
*head_ptr = cur->next;
}
if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name);
free ((PTR) cur->name);
free (cur);
return prev;
}
static struct search_path *
remove_dup_nonsys_dirs (pfile, head_ptr, end)
cpp_reader *pfile;
struct search_path **head_ptr;
struct search_path *end;
{
int sysdir = 0;
struct search_path *prev = NULL, *cur, *other;
for (cur = *head_ptr; cur; cur = cur->next)
{
if (cur->sysp)
{
sysdir = 1;
for (other = *head_ptr, prev = NULL;
other != end;
other = other ? other->next : *head_ptr)
{
if (!other->sysp
&& INO_T_EQ (cur->ino, other->ino)
&& cur->dev == other->dev)
{
other = remove_dup_dir (pfile, prev, head_ptr);
if (CPP_OPTION (pfile, verbose))
fprintf (stderr,
_(" as it is a non-system directory that duplicates a system directory\n"));
}
prev = other;
}
}
}
if (!sysdir)
for (cur = *head_ptr; cur != end; cur = cur->next)
prev = cur;
return prev;
}
static struct search_path *
remove_dup_dirs (pfile, head_ptr)
cpp_reader *pfile;
struct search_path **head_ptr;
{
struct search_path *prev = NULL, *cur, *other;
for (cur = *head_ptr; cur; cur = cur->next)
{
for (other = *head_ptr; other != cur; other = other->next)
if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
{
cur = remove_dup_dir (pfile, prev, head_ptr);
break;
}
prev = cur;
}
return prev;
}
static void
merge_include_chains (pfile)
cpp_reader *pfile;
{
struct search_path *quote, *brack, *systm, *qtail;
struct cpp_pending *pend = CPP_OPTION (pfile, pending);
quote = pend->quote_head;
brack = pend->brack_head;
systm = pend->systm_head;
qtail = pend->quote_tail;
if (systm)
pend->systm_tail->next = pend->after_head;
else
systm = pend->after_head;
if (brack)
pend->brack_tail->next = systm;
else
brack = systm;
remove_dup_nonsys_dirs (pfile, &brack, systm);
remove_dup_dirs (pfile, &brack);
if (quote)
{
qtail = remove_dup_dirs (pfile, "e);
qtail->next = brack;
qtail = remove_dup_nonsys_dirs (pfile, "e, brack);
if (qtail && brack && INO_T_EQ (qtail->ino, brack->ino)
&& qtail->dev == brack->dev)
brack = remove_dup_dir (pfile, qtail, "e);
}
else
quote = brack;
CPP_OPTION (pfile, quote_include) = quote;
CPP_OPTION (pfile, bracket_include) = brack;
#ifdef FRAMEWORK_HEADERS
if (pend->framework_head)
pend->framework_tail->next = pend->framework_system_head;
else
pend->framework_head = pend->framework_system_head;
CPP_OPTION (pfile, framework_include) = pend->framework_head;
#endif
}
struct lang_flags
{
char c99;
char cplusplus;
char extended_numbers;
char std;
char dollars_in_ident;
char cplusplus_comments;
char digraphs;
};
static const struct lang_flags lang_defaults[] =
{
{ 0, 0, 1, 0, 1, 1, 1 },
{ 1, 0, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1 },
{ 0, 1, 1, 0, 1, 1, 1 },
{ 0, 1, 1, 1, 0, 1, 1 },
#ifdef CONFIG_DARWIN_H
{ 0, 0, 1, 0, 1, 1, 0 }
#else
{ 0, 0, 1, 0, 0, 1, 0 }
#endif
};
void
cpp_set_lang (pfile, lang)
cpp_reader *pfile;
enum c_lang lang;
{
const struct lang_flags *l = &lang_defaults[(int) lang];
CPP_OPTION (pfile, lang) = lang;
CPP_OPTION (pfile, objc) = flag_objc;
CPP_OPTION (pfile, c99) = l->c99;
CPP_OPTION (pfile, cplusplus) = l->cplusplus;
CPP_OPTION (pfile, extended_numbers) = l->extended_numbers;
CPP_OPTION (pfile, std) = l->std;
CPP_OPTION (pfile, trigraphs) = l->std;
CPP_OPTION (pfile, dollars_in_ident) = l->dollars_in_ident;
CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments;
CPP_OPTION (pfile, digraphs) = l->digraphs;
}
#ifdef HOST_EBCDIC
static int opt_comp PARAMS ((const void *, const void *));
static int
opt_comp (p1, p2)
const void *p1, *p2;
{
return strcmp (((struct cl_option *) p1)->opt_text,
((struct cl_option *) p2)->opt_text);
}
#endif
static void
init_library ()
{
static int initialized = 0;
if (! initialized)
{
initialized = 1;
#ifdef HOST_EBCDIC
qsort (cl_options, N_OPTS, sizeof (struct cl_option), opt_comp);
#endif
init_trigraph_map ();
}
}
cpp_reader *
cpp_create_reader (lang)
enum c_lang lang;
{
cpp_reader *pfile;
init_library ();
pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader));
cpp_set_lang (pfile, lang);
CPP_OPTION (pfile, warn_import) = 0;
CPP_OPTION (pfile, warn_pragma_once) = 0;
CPP_OPTION (pfile, warn_extra_tokens) = 0;
CPP_OPTION (pfile, warn_newline_at_eof) = 0;
CPP_OPTION (pfile, warn_four_char_constants) = WARN_FOUR_CHAR_CONSTANTS;
CPP_OPTION (pfile, warn_multichar) = 1;
CPP_OPTION (pfile, discard_comments) = 1;
CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
CPP_OPTION (pfile, show_column) = 1;
CPP_OPTION (pfile, tabstop) = 8;
CPP_OPTION (pfile, operator_names) = 1;
CPP_OPTION (pfile, warn_endif_labels) = 0;
CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99);
CPP_OPTION (pfile, pending) =
(struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long);
CPP_OPTION (pfile, char_precision) = CHAR_BIT;
CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int);
CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
CPP_OPTION (pfile, unsigned_char) = 0;
CPP_OPTION (pfile, unsigned_wchar) = 1;
init_line_maps (&pfile->line_maps);
pfile->line = 1;
pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
pfile->avoid_paste.type = CPP_PADDING;
pfile->avoid_paste.val.source = NULL;
pfile->eof.type = CPP_EOF;
pfile->eof.flags = 0;
_cpp_init_tokenrun (&pfile->base_run, 250);
pfile->cur_run = &pfile->base_run;
pfile->cur_token = pfile->base_run.base;
pfile->context = &pfile->base_context;
pfile->base_context.macro = 0;
pfile->base_context.prev = pfile->base_context.next = 0;
pfile->a_buff = _cpp_get_buff (pfile, 0);
pfile->u_buff = _cpp_get_buff (pfile, 0);
_cpp_expand_op_stack (pfile);
gcc_obstack_init (&pfile->buffer_ob);
_cpp_init_includes (pfile);
return pfile;
}
void
cpp_destroy (pfile)
cpp_reader *pfile;
{
struct search_path *dir, *dirn;
cpp_context *context, *contextn;
tokenrun *run, *runn;
free_chain (CPP_OPTION (pfile, pending)->include_head);
free (CPP_OPTION (pfile, pending));
free (pfile->op_stack);
while (CPP_BUFFER (pfile) != NULL)
_cpp_pop_buffer (pfile);
if (pfile->out.base)
free (pfile->out.base);
if (pfile->macro_buffer)
{
free ((PTR) pfile->macro_buffer);
pfile->macro_buffer = NULL;
pfile->macro_buffer_len = 0;
}
if (pfile->deps)
deps_free (pfile->deps);
obstack_free (&pfile->buffer_ob, 0);
_cpp_destroy_hashtable (pfile);
_cpp_cleanup_includes (pfile);
_cpp_free_buff (pfile->a_buff);
_cpp_free_buff (pfile->u_buff);
_cpp_free_buff (pfile->free_buffs);
for (run = &pfile->base_run; run; run = runn)
{
runn = run->next;
free (run->base);
if (run != &pfile->base_run)
free (run);
}
for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn)
{
dirn = dir->next;
free ((PTR) dir->name);
free (dir);
}
for (context = pfile->base_context.next; context; context = contextn)
{
contextn = context->next;
free (context);
}
free_line_maps (&pfile->line_maps);
free (pfile);
}
struct builtin
{
const uchar *name;
unsigned short len;
unsigned short value;
};
#define B(n, t) { DSC(n), t }
static const struct builtin builtin_array[] =
{
B("__TIME__", BT_TIME),
B("__DATE__", BT_DATE),
B("__FILE__", BT_FILE),
B("__BASE_FILE__", BT_BASE_FILE),
B("__LINE__", BT_SPECLINE),
B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
B("_Pragma", BT_PRAGMA),
B("__STDC__", BT_STDC),
};
static const struct builtin operator_array[] =
{
B("and", CPP_AND_AND),
B("and_eq", CPP_AND_EQ),
B("bitand", CPP_AND),
B("bitor", CPP_OR),
B("compl", CPP_COMPL),
B("not", CPP_NOT),
B("not_eq", CPP_NOT_EQ),
B("or", CPP_OR_OR),
B("or_eq", CPP_OR_EQ),
B("xor", CPP_XOR),
B("xor_eq", CPP_XOR_EQ)
};
#undef B
static void
mark_named_operators (pfile)
cpp_reader *pfile;
{
const struct builtin *b;
for (b = operator_array;
b < (operator_array + ARRAY_SIZE (operator_array));
b++)
{
cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
hp->flags |= NODE_OPERATOR;
hp->value.operator = b->value;
}
}
static void
init_builtins (pfile)
cpp_reader *pfile;
{
const struct builtin *b;
size_t n = ARRAY_SIZE (builtin_array);
if (CPP_OPTION (pfile, traditional))
n -= 2;
for(b = builtin_array; b < builtin_array + n; b++)
{
cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
hp->type = NT_MACRO;
hp->flags |= NODE_BUILTIN | NODE_WARN;
hp->value.builtin = b->value;
}
if (CPP_OPTION (pfile, cplusplus))
_cpp_define_builtin (pfile, "__cplusplus 1");
else if (CPP_OPTION (pfile, lang) == CLK_ASM)
_cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
else if (CPP_OPTION (pfile, lang) == CLK_STDC94)
_cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L");
else if (CPP_OPTION (pfile, c99))
_cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L");
if (CPP_OPTION (pfile, objc))
_cpp_define_builtin (pfile, "__OBJC__ 1");
if (pfile->cb.register_builtins)
(*pfile->cb.register_builtins) (pfile);
}
static void
init_standard_includes (pfile)
cpp_reader *pfile;
{
char *path;
const struct default_include *p;
const char *specd_prefix = CPP_OPTION (pfile, include_prefix);
GET_ENVIRONMENT (path, "CPATH");
if (path != 0 && *path != 0)
path_include (pfile, path, BRACKET);
switch ((CPP_OPTION (pfile, objc) ? 2 : 0) + CPP_OPTION (pfile, cplusplus))
{
case 0:
GET_ENVIRONMENT (path, "C_INCLUDE_PATH");
break;
case 1:
GET_ENVIRONMENT (path, "CPLUS_INCLUDE_PATH");
break;
case 2:
GET_ENVIRONMENT (path, "OBJC_INCLUDE_PATH");
break;
case 3:
GET_ENVIRONMENT (path, "OBJCPLUS_INCLUDE_PATH");
break;
}
if (path != 0 && *path != 0)
path_include (pfile, path, SYSTEM);
if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len)
{
int default_len = cpp_GCC_INCLUDE_DIR_len;
char *default_prefix = (char *) alloca (default_len + 1);
int specd_len = strlen (specd_prefix);
memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len);
default_prefix[default_len] = '\0';
for (p = cpp_include_defaults; p->fname; p++)
{
if (!p->cplusplus
|| (CPP_OPTION (pfile, cplusplus)
&& !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
{
if (!strncmp (p->fname, default_prefix, default_len))
{
int flen = strlen (p->fname);
int this_len = specd_len + flen - default_len;
char *str = (char *) xmalloc (this_len + 1);
memcpy (str, specd_prefix, specd_len);
memcpy (str + specd_len,
p->fname + default_len,
flen - default_len + 1);
append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
}
}
}
}
for (p = cpp_include_defaults; p->fname; p++)
{
if (!p->cplusplus
|| (CPP_OPTION (pfile, cplusplus)
&& !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
{
char *str = update_path (p->fname, p->component);
append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
}
}
#ifdef FRAMEWORK_HEADERS
init_standard_frameworks (pfile);
#endif
}
#ifdef FRAMEWORK_HEADERS
static void
init_standard_frameworks (pfile)
cpp_reader *pfile;
{
int i = 0;
const char *path;
char *next_root = getenv ("NEXT_ROOT");
if (next_root && *next_root && next_root[strlen (next_root) - 1] == '/')
next_root[strlen (next_root) - 1] = '\0';
while ((path = framework_paths_defaults_array[i++].path))
{
char *new_fname = NULL;
if (next_root && *next_root)
new_fname = (char *) xmalloc (strlen (next_root) + strlen (path) + 1);
if (new_fname)
sprintf (new_fname, "%s%s", next_root, path);
else
{
new_fname = (char *) xmalloc (strlen (path) + 1);
strcpy (new_fname, path);
}
append_include_chain (pfile, new_fname, FRAMEWORK_SYSTEM, 1);
}
}
#endif
static bool
push_include (pfile, p)
cpp_reader *pfile;
struct pending_option *p;
{
cpp_token header;
if (CPP_OPTION (pfile, use_ss))
find_include_cinfo (pfile, p->arg);
header.type = CPP_STRING;
header.val.str.text = (const unsigned char *) p->arg;
header.val.str.len = strlen (p->arg);
pfile->line++;
return _cpp_execute_include (pfile, &header, IT_CMDLINE);
}
static void
free_chain (head)
struct pending_option *head;
{
struct pending_option *next;
while (head)
{
next = head->next;
free (head);
head = next;
}
}
#if ENABLE_CHECKING
static void sanity_checks PARAMS ((cpp_reader *));
static void sanity_checks (pfile)
cpp_reader *pfile;
{
cppchar_t test = 0;
size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
test--;
if (test < 1)
cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
if (CPP_OPTION (pfile, precision) > max_precision)
cpp_error (pfile, DL_ICE,
"preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
(unsigned long) max_precision,
(unsigned long) CPP_OPTION (pfile, precision));
if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
cpp_error (pfile, DL_ICE,
"CPP arithmetic must be at least as precise as a target int");
if (CPP_OPTION (pfile, char_precision) < 8)
cpp_error (pfile, DL_ICE, "target char is less than 8 bits wide");
if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision))
cpp_error (pfile, DL_ICE,
"target wchar_t is narrower than target char");
if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision))
cpp_error (pfile, DL_ICE,
"target int is narrower than target char");
if (sizeof (cppchar_t) > sizeof (cpp_num_part))
cpp_error (pfile, DL_ICE, "CPP half-integer narrower than CPP character");
if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
cpp_error (pfile, DL_ICE,
"CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
(unsigned long) BITS_PER_CPPCHAR_T,
(unsigned long) CPP_OPTION (pfile, wchar_precision));
}
#else
# define sanity_checks(PFILE)
#endif
void
cpp_add_dependency_target (pfile, target, quote)
cpp_reader *pfile;
const char *target;
int quote;
{
if (!pfile->deps)
pfile->deps = deps_init ();
deps_add_target (pfile->deps, target, quote);
}
const char *
cpp_read_main_file (pfile, fname, table)
cpp_reader *pfile;
const char *fname;
hash_table *table;
{
sanity_checks (pfile);
post_options (pfile);
_cpp_init_hashtable (pfile, table);
if (! CPP_OPTION (pfile, no_standard_includes))
init_standard_includes (pfile);
merge_include_chains (pfile);
if (CPP_OPTION (pfile, verbose))
{
struct search_path *l;
fprintf (stderr, _("#include \"...\" search starts here:\n"));
for (l = CPP_OPTION (pfile, quote_include); l; l = l->next)
{
if (l == CPP_OPTION (pfile, bracket_include))
fprintf (stderr, _("#include <...> search starts here:\n"));
fprintf (stderr, " %s\n", l->name);
}
fprintf (stderr, _("End of search list.\n"));
#ifdef FRAMEWORK_HEADERS
fprintf (stderr, _("Framework search starts here:\n"));
for (l = CPP_OPTION (pfile, framework_include); l; l = l->next)
{
fprintf (stderr, " %s\n", l->name);
}
fprintf (stderr, _("End of framework search list.\n"));
#endif
}
if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
{
if (!pfile->deps)
pfile->deps = deps_init ();
deps_add_default_target (pfile->deps, fname);
}
if (!_cpp_read_file (pfile, fname))
return NULL;
if (CPP_OPTION (pfile, making_pch) && CPP_OPTION (pfile, use_ss))
find_include_cinfo (pfile, fname);
pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names);
if (pfile->print.outf
&& ! CPP_OPTION (pfile, no_output)
&& ! CPP_OPTION (pfile, preprocessed)
&& CPP_OPTION (pfile, lang) != CLK_ASM)
{
char *buf = getpwd ();
int len = strlen (buf);
char *buf2 = alloca (len * 4 + 4);
char *buf3;
buf3 = cpp_quote_string (buf2, (const unsigned char *) buf, len);
*buf3 = '\0';
fprintf (pfile->print.outf, "#pragma GCC set_debug_pwd \"%s\"\n",
buf2);
pfile->print.line++;
pfile->print.printed = 0;
}
if (CPP_OPTION (pfile, preprocessed))
read_original_filename (pfile);
if (CPP_OPTION (pfile, preprocessed))
read_original_directory (pfile);
return pfile->map->to_file;
}
static void
read_original_directory (pfile)
cpp_reader *pfile;
{
const cpp_token *token, *token1;
if (pfile->lookaheads)
token = _cpp_lex_token (pfile);
else
token = _cpp_lex_direct (pfile);
if (token->type == CPP_HASH)
{
token1 = _cpp_lex_direct (pfile);
_cpp_backup_tokens (pfile, 1);
if (token1->type == CPP_NAME
&& token1->val.node->directive_index
&& token1->val.node->ident.len == 6
&& strcmp (token1->val.node->ident.str, "pragma") == 0)
{
_cpp_handle_directive (pfile, token->flags & PREV_WHITE);
return;
}
}
_cpp_backup_tokens (pfile, 1);
}
static void
read_original_filename (pfile)
cpp_reader *pfile;
{
const cpp_token *token, *token1;
token = _cpp_lex_direct (pfile);
if (token->type == CPP_HASH)
{
token1 = _cpp_lex_direct (pfile);
_cpp_backup_tokens (pfile, 1);
if (token1->type == CPP_NUMBER)
{
_cpp_handle_directive (pfile, token->flags & PREV_WHITE);
return;
}
}
_cpp_backup_tokens (pfile, 1);
}
void
cpp_finish_options (pfile)
cpp_reader *pfile;
{
if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names))
mark_named_operators (pfile);
if (! CPP_OPTION (pfile, preprocessed))
{
struct pending_option *p;
_cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
init_builtins (pfile);
_cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
(*p->handler) (pfile, p->arg);
for (p = CPP_OPTION (pfile, pending)->imacros_head; p; p = p->next)
if (push_include (pfile, p))
cpp_scan_nooutput (pfile);
pfile->next_include_file = &CPP_OPTION (pfile, pending)->include_head;
_cpp_maybe_push_include_file (pfile);
}
pfile->first_unused_line = pfile->line;
free_chain (CPP_OPTION (pfile, pending)->imacros_head);
free_chain (CPP_OPTION (pfile, pending)->directive_head);
if (pfile->cinfo_state == CINFO_FOUND)
{
if (c_valid_cinfo (pfile, pfile->cinfo_candidate_file))
{
pfile->cinfo_state = CINFO_READ;
if (pfile->cb.clear_write_symbols)
pfile->cb.clear_write_symbols (pfile->cinfo_src_file, cpp_get_stabs_checksum ());
}
}
}
void
_cpp_maybe_push_include_file (pfile)
cpp_reader *pfile;
{
if (pfile->next_include_file)
{
struct pending_option *head = *pfile->next_include_file;
while (head && !push_include (pfile, head))
head = head->next;
if (head)
pfile->next_include_file = &head->next;
else
{
_cpp_do_file_change (pfile, LC_RENAME,
pfile->line_maps.maps[0].to_file, 1, 0);
pfile->next_include_file = NULL;
}
}
}
int
cpp_finish (pfile, deps_stream)
cpp_reader *pfile;
FILE *deps_stream;
{
if (CPP_OPTION (pfile, warn_unused_macros))
cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
while (pfile->buffer)
_cpp_pop_buffer (pfile);
if (CPP_OPTION (pfile, deps.style) != DEPS_NONE
&& deps_stream && pfile->errors == 0)
{
deps_write (pfile->deps, deps_stream, 72);
if (CPP_OPTION (pfile, deps.phony_targets))
deps_phony_targets (pfile->deps, deps_stream);
}
if (CPP_OPTION (pfile, print_include_names))
_cpp_report_missing_guards (pfile);
if (CPP_OPTION (pfile, inclusion_log_file))
ilog_close (pfile);
return pfile->errors;
}
static void
new_pending_directive (pend, text, handler)
struct cpp_pending *pend;
const char *text;
cl_directive_handler handler;
{
struct pending_option *o = (struct pending_option *)
xmalloc (sizeof (struct pending_option));
o->arg = text;
o->next = NULL;
o->handler = handler;
APPEND (pend, directive, o);
}
#define no_ass N_("assertion missing after %s")
#define no_dir N_("directory name missing after %s")
#define no_fil N_("file name missing after %s")
#define no_mac N_("macro name missing after %s")
#define no_pth N_("path name missing after %s")
#define no_tgt N_("target missing after %s")
#define COMMAND_LINE_OPTIONS \
DEF_OPT("A", no_ass, OPT_A) \
DEF_OPT("D", no_mac, OPT_D) \
\
DEF_OPT("F", no_dir, OPT_F) \
DEF_OPT("I", no_dir, OPT_I) \
DEF_OPT("U", no_mac, OPT_U) \
\
DEF_OPT("arch", no_tgt, OPT_arch) \
\
DEF_OPT("header-mapfile", no_fil, OPT_header_mapfile) \
DEF_OPT("idirafter", no_dir, OPT_idirafter) \
\
DEF_OPT("iframework", no_dir, OPT_iframework) \
DEF_OPT("imacros", no_fil, OPT_imacros) \
DEF_OPT("include", no_fil, OPT_include) \
\
DEF_OPT("inclusion-log-file", no_fil, OPT_inclusion_log_file) \
DEF_OPT("iprefix", no_pth, OPT_iprefix) \
DEF_OPT("isystem", no_dir, OPT_isystem) \
DEF_OPT("iwithprefix", no_dir, OPT_iwithprefix) \
DEF_OPT("iwithprefixbefore", no_dir, OPT_iwithprefixbefore) \
\
DEF_OPT("precomp-trustfile", no_fil, OPT_precomp_trustfile)
#define DEF_OPT(text, msg, code) code,
enum opt_code
{
COMMAND_LINE_OPTIONS
N_OPTS
};
#undef DEF_OPT
struct cl_option
{
const char *opt_text;
const char *msg;
size_t opt_len;
enum opt_code opt_code;
};
#define DEF_OPT(text, msg, code) { text, msg, sizeof(text) - 1, code },
#ifdef HOST_EBCDIC
static struct cl_option cl_options[] =
#else
static const struct cl_option cl_options[] =
#endif
{
COMMAND_LINE_OPTIONS
};
#undef DEF_OPT
#undef COMMAND_LINE_OPTIONS
static int
parse_option (input)
const char *input;
{
unsigned int md, mn, mx;
size_t opt_len;
int comp;
mn = 0;
mx = N_OPTS;
while (mx > mn)
{
md = (mn + mx) / 2;
opt_len = cl_options[md].opt_len;
comp = strncmp (input, cl_options[md].opt_text, opt_len);
if (comp > 0)
mn = md + 1;
else if (comp < 0)
mx = md;
else
{
if (input[opt_len] == '\0')
return md;
mn = md + 1;
if (cl_options[md].msg)
{
mx = md;
for (; mn < (unsigned int) N_OPTS; mn++)
{
opt_len = cl_options[mn].opt_len;
if (strncmp (input, cl_options[mn].opt_text, opt_len))
break;
if (input[opt_len] == '\0')
return mn;
if (cl_options[mn].msg)
mx = mn;
}
return mx;
}
}
}
return -1;
}
int
cpp_handle_option (pfile, argc, argv)
cpp_reader *pfile;
int argc;
char **argv;
{
int i = 0;
struct cpp_pending *pend = CPP_OPTION (pfile, pending);
{
enum opt_code opt_code;
int opt_index;
const char *arg = 0;
opt_index = parse_option (&argv[i][1]);
if (opt_index < 0)
return i;
opt_code = cl_options[opt_index].opt_code;
if (cl_options[opt_index].msg)
{
arg = &argv[i][cl_options[opt_index].opt_len + 1];
if (arg[0] == '\0')
{
arg = argv[++i];
if (!arg)
{
cpp_error (pfile, DL_ERROR,
cl_options[opt_index].msg, argv[i - 1]);
return argc;
}
}
}
switch (opt_code)
{
case N_OPTS:
break;
case OPT_arch:
break;
case OPT_D:
new_pending_directive (pend, arg, cpp_define);
break;
case OPT_iprefix:
CPP_OPTION (pfile, include_prefix) = arg;
CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
break;
case OPT_A:
if (arg[0] == '-')
{
if (arg[1] == '\0')
{
free_chain (pend->directive_head);
pend->directive_head = NULL;
pend->directive_tail = NULL;
}
else
new_pending_directive (pend, arg + 1, cpp_unassert);
}
else
new_pending_directive (pend, arg, cpp_assert);
break;
case OPT_U:
new_pending_directive (pend, arg, cpp_undef);
break;
case OPT_I:
if (!strcmp (arg, "-"))
{
if (! CPP_OPTION (pfile, ignore_srcdir))
{
pend->quote_head = pend->brack_head;
pend->quote_tail = pend->brack_tail;
pend->brack_head = 0;
pend->brack_tail = 0;
CPP_OPTION (pfile, ignore_srcdir) = 1;
}
else
{
cpp_error (pfile, DL_ERROR, "-I- specified twice");
return argc;
}
}
else
append_include_chain (pfile, xstrdup (arg), BRACKET, 0);
break;
case OPT_isystem:
append_include_chain (pfile, xstrdup (arg), SYSTEM, 0);
break;
#ifdef FRAMEWORK_HEADERS
case OPT_F:
case OPT_iframework:
append_include_chain (pfile, xstrdup (arg), FRAMEWORK, 0);
break;
#endif
case OPT_include:
case OPT_imacros:
{
struct pending_option *o = (struct pending_option *)
xmalloc (sizeof (struct pending_option));
o->arg = arg;
o->next = NULL;
if (opt_code == OPT_include)
APPEND (pend, include, o);
else
APPEND (pend, imacros, o);
}
break;
case OPT_iwithprefix:
case OPT_iwithprefixbefore:
{
char *fname;
int len;
len = strlen (arg);
if (CPP_OPTION (pfile, include_prefix) != 0)
{
size_t ipl = CPP_OPTION (pfile, include_prefix_len);
fname = xmalloc (ipl + len + 1);
memcpy (fname, CPP_OPTION (pfile, include_prefix), ipl);
memcpy (fname + ipl, arg, len + 1);
}
else if (cpp_GCC_INCLUDE_DIR_len)
{
fname = xmalloc (cpp_GCC_INCLUDE_DIR_len + len + 1);
memcpy (fname, cpp_GCC_INCLUDE_DIR, cpp_GCC_INCLUDE_DIR_len);
memcpy (fname + cpp_GCC_INCLUDE_DIR_len, arg, len + 1);
}
else
fname = xstrdup (arg);
append_include_chain (pfile, fname,
opt_code == OPT_iwithprefix ? SYSTEM: BRACKET, 0);
}
break;
case OPT_idirafter:
append_include_chain (pfile, xstrdup (arg), AFTER, 0);
break;
case OPT_header_mapfile:
if (CPP_OPTION (pfile, header_map) != NULL)
cpp_error (pfile, DL_ERROR,
"more than one `-header-mapfile' option specified; "
"only one is allowed");
else
CPP_OPTION (pfile, header_map) = hmap_load_header_map (arg);
break;
case OPT_inclusion_log_file:
if (CPP_OPTION (pfile, inclusion_log_file) != NULL)
cpp_error (pfile, DL_ERROR,
"more than one `-inclusion-log-file' option specified; "
"only one is allowed");
else
CPP_OPTION (pfile, inclusion_log_file) = ilog_open (arg);
break;
case OPT_precomp_trustfile:
break;
}
}
return i + 1;
}
int
cpp_handle_options (pfile, argc, argv)
cpp_reader *pfile;
int argc;
char **argv;
{
int i;
int strings_processed;
for (i = 0; i < argc; i += strings_processed)
{
strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
if (strings_processed == 0)
break;
}
return i;
}
static void
post_options (pfile)
cpp_reader *pfile;
{
if (CPP_OPTION (pfile, cplusplus))
CPP_OPTION (pfile, warn_traditional) = 0;
if (CPP_OPTION (pfile, preprocessed))
{
pfile->state.prevent_expansion = 1;
CPP_OPTION (pfile, traditional) = 0;
}
if (CPP_OPTION (pfile, traditional))
CPP_OPTION (pfile, show_column) = 0;
}
static inline
uint32 hmap_hash_string (str)
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;
}
static inline unsigned
hmap_compare_strings (str1, str2)
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');
}
static struct
hmap_header_map *hmap_load_header_map (filename)
const char *filename;
{
struct hmap_header_map *headermap = NULL;
if (filename != NULL && filename[0] != '\0')
{
FILE * f;
struct stat f_info;
f = fopen (filename, "rb");
if (f != NULL)
{
if (fstat (fileno (f), &f_info) == 0)
{
unsigned headermap_size = f_info.st_size;
headermap = (struct hmap_header_map *) xmalloc (headermap_size);
if (fread (headermap, 1, headermap_size, f) != headermap_size)
{
perror (filename);
free (headermap);
headermap = NULL;
}
if (headermap->magic == HMAP_OPPOSITE_ENDIANNESS_MAGIC)
{
fprintf (stderr,
"headermap \"%s\" has incompatible endianness\n",
filename);
free (headermap);
headermap = NULL;
}
else if (headermap->magic != HMAP_SAME_ENDIANNESS_MAGIC)
{
fprintf (stderr,
"\"%s\" is not a headermap file (bad magic: 0x%08lx)\n",
filename, headermap->magic);
free (headermap);
headermap = NULL;
}
}
else
perror (filename);
fclose (f);
}
else
perror (filename);
}
return headermap;
}
static void
hmap_free_header_map (pfile)
cpp_reader *pfile;
{
struct hmap_header_map *headermap = CPP_OPTION (pfile, header_map);
if (headermap != NULL)
free (headermap);
if (CPP_OPTION (pfile, hmap_path))
free (CPP_OPTION (pfile, hmap_path));
}
struct search_path *
hmap_lookup_path (pfile, filename_beg)
cpp_reader *pfile;
const char **filename_beg;
{
struct hmap_header_map *headermap = CPP_OPTION (pfile, header_map);
const char *strings;
struct hmap_bucket *buckets;
uint32 bucket_mask;
uint32 i;
uint32 key_offset;
strings = ((const char *)headermap) + headermap->strings_offset;
buckets = headermap->buckets;
bucket_mask = headermap->capacity-1;
i = hmap_hash_string (*filename_beg) & bucket_mask;
while ((key_offset = buckets[i].key) != HMAP_NOT_A_KEY)
{
if (hmap_compare_strings (*filename_beg, strings+key_offset))
{
static char *hmap_path_result_buffer = NULL;
const char *sp;
char *dp;
char *last_slash;
if (hmap_path_result_buffer == NULL)
hmap_path_result_buffer =
xmalloc (headermap->max_value_length + 1);
last_slash = dp = hmap_path_result_buffer;
sp = strings + buckets[i].value.prefix;
while (*sp != '\0')
{
if (*sp == '/')
last_slash = dp;
*dp++ = *sp++;
}
sp = strings + buckets[i].value.suffix;
while (*sp != '\0')
{
if (*sp == '/')
last_slash = dp;
*dp++ = *sp++;
}
*dp = '\0';
if (*last_slash == '/')
*last_slash++ = '\0';
append_include_chain (pfile, xstrdup (hmap_path_result_buffer),
HMAPFILE, 0);
if (!CPP_OPTION (pfile, hmap_path))
break;
*filename_beg = last_slash;
return CPP_OPTION (pfile, hmap_path);
}
i = (i + 1) & bucket_mask;
}
return CPP_OPTION (pfile, bracket_include);
}
static FILE *
ilog_open (ilog_name)
const char *ilog_name;
{
FILE *inclusion_log_file = ((ilog_name[0] != '-' || ilog_name[1] != '\0')
? fopen (ilog_name, "w")
: fdopen (dup (fileno (stdout)), "w"));
if (!inclusion_log_file)
perror (ilog_name);
return inclusion_log_file;
}
static void
ilog_close (pfile)
cpp_reader *pfile;
{
if (CPP_OPTION (pfile, inclusion_log_file))
ilog_printf (pfile, "The `-inclusion-log-file' option has not been\n"
"implemented in GCC3 just yet. Our apologies.\n");
if (CPP_OPTION (pfile, inclusion_log_file)
&& CPP_OPTION (pfile, inclusion_log_file) != stdout
&& (ferror (CPP_OPTION (pfile, inclusion_log_file))
|| fclose (CPP_OPTION (pfile, inclusion_log_file)) != 0))
cpp_error (pfile, DL_ERROR, "I/O error on `-inclusion-log-file' output");
}
void
ilog_printf (cpp_reader *pfile, const char * format, ...)
{
va_list ap;
va_start(ap, format);
if (CPP_OPTION (pfile, inclusion_log_file))
vfprintf(CPP_OPTION (pfile, inclusion_log_file), format, ap);
va_end(ap);
}