#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "machmode.h"
#include "target.h"
#include "tm.h"
#include "cpplib.h"
#include "prefix.h"
#include "intl.h"
#include "c-incpath.h"
#include "cppdefault.h"
#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
static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
static void add_env_var_paths (const char *, int);
static void add_standard_paths (const char *, const char *, const char *, int);
static void free_path (struct cpp_dir *, int);
static void merge_include_chains (cpp_reader *, int);
static struct cpp_dir *remove_duplicates (cpp_reader *, struct cpp_dir *,
struct cpp_dir *,
struct cpp_dir *, int);
static struct cpp_dir *heads[4];
static struct cpp_dir *tails[4];
static bool quote_ignores_source_dir;
enum { REASON_QUIET = 0, REASON_NOENT, REASON_DUP, REASON_DUP_SYS };
static void
free_path (struct cpp_dir *path, int reason)
{
switch (reason)
{
case REASON_DUP:
case REASON_DUP_SYS:
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), path->name);
if (reason == REASON_DUP_SYS)
fprintf (stderr,
_(" as it is a non-system directory that duplicates a system directory\n"));
break;
case REASON_NOENT:
fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"),
path->name);
break;
case REASON_QUIET:
default:
break;
}
free (path->name);
free (path);
}
static void
add_env_var_paths (const char *env_var, int chain)
{
char *p, *q, *path;
GET_ENVIRONMENT (q, env_var);
if (!q)
return;
for (p = q; *q; p = q + 1)
{
q = p;
while (*q != 0 && *q != PATH_SEPARATOR)
q++;
if (p == q)
path = xstrdup (".");
else
{
path = XNEWVEC (char, q - p + 1);
memcpy (path, p, q - p);
path[q - p] = '\0';
}
add_path (path, chain, chain == SYSTEM, false);
}
}
static void
add_standard_paths (const char *sysroot, const char *iprefix,
const char *imultilib, int cxx_stdinc)
{
const struct default_include *p;
size_t len;
if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)
{
for (p = cpp_include_defaults; p->fname; p++)
{
if (!p->cplusplus || cxx_stdinc)
{
if (sysroot && p->add_sysroot)
continue;
if (!strncmp (p->fname, cpp_GCC_INCLUDE_DIR, len))
{
char *str = concat (iprefix, p->fname + len, NULL);
if (p->multilib && imultilib)
str = concat (str, dir_separator_str, imultilib, NULL);
add_path (str, SYSTEM, p->cxx_aware, false);
}
}
}
}
for (p = cpp_include_defaults; p->fname; p++)
{
if (!p->cplusplus || cxx_stdinc)
{
char *str;
if (sysroot && p->add_sysroot)
str = concat (sysroot, p->fname, NULL);
else
str = update_path (p->fname, p->component);
if (p->multilib && imultilib)
str = concat (str, dir_separator_str, imultilib, NULL);
add_path (str, SYSTEM, p->cxx_aware, false);
}
}
}
static struct cpp_dir *
remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,
struct cpp_dir *system, struct cpp_dir *join,
int verbose)
{
struct cpp_dir **pcur, *tmp, *cur;
struct stat st;
for (pcur = &head; *pcur; )
{
int reason = REASON_QUIET;
cur = *pcur;
if (stat (cur->name, &st))
{
if (errno != ENOENT)
cpp_errno (pfile, CPP_DL_ERROR, cur->name);
else
{
cpp_options *opts = cpp_get_options (pfile);
if (opts->warn_missing_include_dirs && cur->user_supplied_p)
cpp_errno (pfile, CPP_DL_WARNING, cur->name);
reason = REASON_NOENT;
}
}
else if (!S_ISDIR (st.st_mode))
cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,
"%s: not a directory", cur->name);
else
{
INO_T_COPY (cur->ino, st.st_ino);
cur->dev = st.st_dev;
reason = REASON_DUP_SYS;
for (tmp = system; tmp; tmp = tmp->next)
if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev
&& cur->construct == tmp->construct)
break;
if (!tmp)
{
reason = REASON_DUP;
for (tmp = head; tmp != cur; tmp = tmp->next)
if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev
&& cur->construct == tmp->construct)
break;
if (tmp == cur
&& !(cur->next == NULL && join
&& INO_T_EQ (cur->ino, join->ino)
&& cur->dev == join->dev
&& cur->construct == join->construct))
{
pcur = &cur->next;
continue;
}
}
}
*pcur = cur->next;
free_path (cur, verbose ? reason: REASON_QUIET);
}
*pcur = join;
return head;
}
static void
merge_include_chains (cpp_reader *pfile, int verbose)
{
if (heads[SYSTEM])
tails[SYSTEM]->next = heads[AFTER];
else
heads[SYSTEM] = heads[AFTER];
heads[SYSTEM] = remove_duplicates (pfile, heads[SYSTEM], 0, 0, verbose);
heads[BRACKET] = remove_duplicates (pfile, heads[BRACKET], heads[SYSTEM],
heads[SYSTEM], verbose);
heads[QUOTE] = remove_duplicates (pfile, heads[QUOTE], heads[SYSTEM],
heads[BRACKET], verbose);
if (verbose)
{
struct cpp_dir *p;
fprintf (stderr, _("#include \"...\" search starts here:\n"));
for (p = heads[QUOTE];; p = p->next)
{
if (p == heads[BRACKET])
fprintf (stderr, _("#include <...> search starts here:\n"));
if (!p)
break;
fprintf (stderr, " %s\n", p->name);
}
fprintf (stderr, _("End of search list.\n"));
}
}
void
split_quote_chain (void)
{
heads[QUOTE] = heads[BRACKET];
tails[QUOTE] = tails[BRACKET];
heads[BRACKET] = NULL;
tails[BRACKET] = NULL;
quote_ignores_source_dir = true;
}
void
add_cpp_dir_path (cpp_dir *p, int chain)
{
if (tails[chain])
tails[chain]->next = p;
else
heads[chain] = p;
tails[chain] = p;
}
void
add_path (char *path, int chain, int cxx_aware, bool user_supplied_p)
{
cpp_dir *p;
#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
char* c;
for (c = path; *c; c++)
if (*c == '\\') *c = '/';
#endif
p = XNEW (cpp_dir);
p->next = NULL;
p->name = path;
if (chain == SYSTEM || chain == AFTER)
p->sysp = 1 + !cxx_aware;
else
p->sysp = 0;
p->construct = 0;
p->user_supplied_p = user_supplied_p;
add_cpp_dir_path (p, chain);
}
void
register_include_chains (cpp_reader *pfile, const char *sysroot,
const char *iprefix, const char *imultilib,
int stdinc, int cxx_stdinc, int verbose)
{
static const char *const lang_env_vars[] =
{ "C_INCLUDE_PATH", "CPLUS_INCLUDE_PATH",
"OBJC_INCLUDE_PATH", "OBJCPLUS_INCLUDE_PATH" };
cpp_options *cpp_opts = cpp_get_options (pfile);
size_t idx = (cpp_opts->objc ? 2: 0);
if (cpp_opts->cplusplus)
idx++;
else
cxx_stdinc = false;
add_env_var_paths ("CPATH", BRACKET);
add_env_var_paths (lang_env_vars[idx], SYSTEM);
target_c_incpath.extra_pre_includes (sysroot, iprefix, stdinc);
if (stdinc)
add_standard_paths (sysroot, iprefix, imultilib, cxx_stdinc);
target_c_incpath.extra_includes (sysroot, iprefix, stdinc);
merge_include_chains (pfile, verbose);
cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET],
quote_ignores_source_dir);
}
#if !(defined TARGET_EXTRA_INCLUDES) || !(defined TARGET_EXTRA_PRE_INCLUDES)
static void hook_void_charptr_charptr_int (const char *sysroot ATTRIBUTE_UNUSED,
const char *iprefix ATTRIBUTE_UNUSED,
int stdinc ATTRIBUTE_UNUSED)
{
}
#endif
#ifndef TARGET_EXTRA_INCLUDES
#define TARGET_EXTRA_INCLUDES hook_void_charptr_charptr_int
#endif
#ifndef TARGET_EXTRA_PRE_INCLUDES
#define TARGET_EXTRA_PRE_INCLUDES hook_void_charptr_charptr_int
#endif
struct target_c_incpath_s target_c_incpath = { TARGET_EXTRA_PRE_INCLUDES, TARGET_EXTRA_INCLUDES };