mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 21:21:14 +00:00
Using set_line_file sort of worked with its stack, but line directives embedded in the source (which glsl's initialization code uses) messed up the start path for quoted include searches.
836 lines
17 KiB
C
836 lines
17 KiB
C
/*
|
|
cpp.c
|
|
|
|
cpp preprocessing support
|
|
|
|
Copyright (C) 2002 Bill Currie <bill@taniwha.org>
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
Date: 2002/06/04
|
|
|
|
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 2
|
|
of the License, 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; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
# include <sys/wait.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_PROCESS_H
|
|
# include <process.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
#ifdef HAVE_IO_H
|
|
#include <io.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "QF/alloc.h"
|
|
#include "QF/dstring.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/va.h"
|
|
|
|
#include "tools/qfcc/include/cpp.h"
|
|
#include "tools/qfcc/include/debug.h"
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
#include "tools/qfcc/include/options.h"
|
|
#include "tools/qfcc/include/qfcc.h"
|
|
#include "tools/qfcc/include/rua-lang.h"
|
|
#include "tools/qfcc/include/strpool.h"
|
|
#include "tools/qfcc/include/symtab.h"
|
|
|
|
typedef struct cpp_arg_s {
|
|
struct cpp_arg_s *next;
|
|
const char *arg;
|
|
} cpp_arg_t;
|
|
|
|
typedef struct cpp_func_s {
|
|
const char *name;
|
|
int (*func) (const char *opt, const char *arg);
|
|
} cpp_func_t;
|
|
|
|
ALLOC_STATE (cpp_arg_t, cpp_args);
|
|
|
|
static cpp_arg_t *cpp_quote_list, **cpp_quote_tail = &cpp_quote_list;
|
|
static cpp_arg_t *cpp_include_list,**cpp_include_tail= &cpp_include_list;
|
|
static cpp_arg_t *cpp_system_list, **cpp_system_tail = &cpp_system_list;
|
|
static cpp_arg_t *cpp_after_list, **cpp_after_tail = &cpp_after_list;
|
|
|
|
static const char *cpp_prefix = "";
|
|
static const char *cpp_sysroot = QFCC_INCLUDE_PATH;
|
|
static cpp_arg_t *cpp_quote_start = 0; // stack
|
|
|
|
static cpp_arg_t *cpp_arg_list, **cpp_arg_tail = &cpp_arg_list;
|
|
static cpp_arg_t *cpp_def_list, **cpp_def_tail = &cpp_def_list;
|
|
static cpp_arg_t *cpp_undef_list, **cpp_undef_tail = &cpp_undef_list;
|
|
static cpp_arg_t *cpp_sysinc_list, **cpp_sysinc_tail = &cpp_sysinc_list;
|
|
|
|
static const char **cpp_argv;
|
|
static int cpp_argc = 0;
|
|
|
|
static const char *cpp_dep_file = 0;
|
|
static const char *cpp_dep_target = 0;
|
|
static bool cpp_dep_generate = false;
|
|
static bool cpp_dep_phony = false;
|
|
static bool cpp_dep_quote = false;
|
|
|
|
symtab_t *cpp_macros;
|
|
const char *cpp_name = 0;//CPP_NAME;
|
|
dstring_t *tempname;
|
|
|
|
static const char **
|
|
append_cpp_args (const char **arg, cpp_arg_t *arg_list)
|
|
{
|
|
cpp_arg_t *cpp_arg;
|
|
|
|
for (cpp_arg = arg_list; cpp_arg; cpp_arg = cpp_arg->next)
|
|
*arg++ = cpp_arg->arg;
|
|
return arg;
|
|
}
|
|
|
|
static cpp_arg_t *
|
|
cpp_alloc_arg (void)
|
|
{
|
|
cpp_arg_t *cpp_arg;
|
|
ALLOC (256, cpp_arg_t, cpp_args, cpp_arg);
|
|
return cpp_arg;
|
|
}
|
|
|
|
static void
|
|
cpp_free_arg (cpp_arg_t *cpp_arg)
|
|
{
|
|
FREE (cpp_args, cpp_arg);
|
|
}
|
|
|
|
#define CPP_ADD(list, a) \
|
|
do { \
|
|
cpp_arg_t *cpp_arg = cpp_alloc_arg (); \
|
|
*(cpp_arg) = (cpp_arg_t) { .arg = save_string (a) }; \
|
|
*cpp_##list##_tail = cpp_arg; \
|
|
cpp_##list##_tail = &cpp_arg->next; \
|
|
} while (0)
|
|
|
|
static void
|
|
add_cpp_arg (const char *arg)
|
|
{
|
|
CPP_ADD (arg, arg);
|
|
cpp_argc++;
|
|
}
|
|
|
|
static void
|
|
add_cpp_sysinc (const char *arg)
|
|
{
|
|
CPP_ADD (sysinc, arg);
|
|
cpp_argc++;
|
|
}
|
|
|
|
void
|
|
add_cpp_undef (const char *arg)
|
|
{
|
|
CPP_ADD (undef, arg);
|
|
cpp_argc++;
|
|
}
|
|
|
|
void
|
|
add_cpp_def (const char *arg)
|
|
{
|
|
CPP_ADD (def, arg);
|
|
cpp_argc++;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_ (const char *opt, const char *arg)
|
|
{
|
|
options.preprocess_only = true;
|
|
options.dependencies = true;
|
|
|
|
add_cpp_def ("-M");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_D (const char *opt, const char *arg)
|
|
{
|
|
options.dependencies = true;
|
|
|
|
add_cpp_def ("-MD");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_F (const char *opt, const char *arg)
|
|
{
|
|
cpp_dep_file = save_string (arg);
|
|
|
|
add_cpp_def ("-MF");
|
|
add_cpp_def (arg);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_G (const char *opt, const char *arg)
|
|
{
|
|
cpp_dep_generate = true;
|
|
|
|
add_cpp_def ("-MG");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_M (const char *opt, const char *arg)
|
|
{
|
|
options.preprocess_only = true;
|
|
options.dependencies = true;
|
|
|
|
add_cpp_def ("-MM");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_MD (const char *opt, const char *arg)
|
|
{
|
|
options.dependencies = true;
|
|
|
|
add_cpp_def ("-MMD");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_P (const char *opt, const char *arg)
|
|
{
|
|
cpp_dep_phony = true;
|
|
|
|
add_cpp_def ("-MP");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_Q (const char *opt, const char *arg)
|
|
{
|
|
cpp_dep_quote = true;
|
|
cpp_dep_target = save_string (arg);
|
|
|
|
add_cpp_def ("-MQ");
|
|
add_cpp_def (arg);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_depend_T (const char *opt, const char *arg)
|
|
{
|
|
cpp_dep_target = save_string (arg);
|
|
|
|
add_cpp_def ("-MT");
|
|
add_cpp_def (arg);
|
|
return 1;
|
|
}
|
|
|
|
#define CPP_DEPEND(name) {#name, cpp_depend_##name}
|
|
int
|
|
cpp_depend (const char *opt, const char *arg)
|
|
{
|
|
static cpp_func_t depend_funcs[] = {
|
|
CPP_DEPEND (),
|
|
CPP_DEPEND (D),
|
|
CPP_DEPEND (F),
|
|
CPP_DEPEND (G),
|
|
CPP_DEPEND (M),
|
|
CPP_DEPEND (MD),
|
|
CPP_DEPEND (P),
|
|
CPP_DEPEND (Q),
|
|
CPP_DEPEND (T),
|
|
{}
|
|
};
|
|
if (!opt) {
|
|
opt = "";
|
|
}
|
|
for (int i = 0; depend_funcs[i].name; i++) {
|
|
if (!strcmp (opt, depend_funcs[i].name)) {
|
|
return depend_funcs[i].func (opt, arg);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
#undef CPP_DEPEND
|
|
|
|
static int
|
|
cpp_include_I (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
if (!strcmp (arg, "-")) {
|
|
return -1;
|
|
}
|
|
CPP_ADD (include, arg);
|
|
add_cpp_def (save_string ("-I"));
|
|
add_cpp_def (save_string (arg));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_include_dirafter (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
CPP_ADD (quote, arg);
|
|
add_cpp_def (save_string ("-idirafter"));
|
|
add_cpp_def (save_string (arg));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_include_prefix (const char *opt, const char *arg)
|
|
{
|
|
cpp_prefix = save_string (arg);
|
|
add_cpp_def (save_string ("-iprefix"));
|
|
add_cpp_def (save_string (arg));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_include_quote (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
CPP_ADD (quote, arg);
|
|
add_cpp_def (save_string ("-iquote"));
|
|
add_cpp_def (save_string (arg));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_include_sysroot (const char *opt, const char *arg)
|
|
{
|
|
cpp_sysroot = save_string (arg);
|
|
add_cpp_def (save_string ("-isysroot"));
|
|
add_cpp_def (save_string (arg));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_include_system (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
CPP_ADD (system, arg);
|
|
|
|
add_cpp_sysinc ("-isystem");
|
|
add_cpp_sysinc (arg);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
cpp_include_withprefix (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
arg = va (0, "%s%s", cpp_prefix, arg);
|
|
CPP_ADD (after, arg);
|
|
add_cpp_def (save_string ("-iwithprefix"));
|
|
add_cpp_def (save_string (arg));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
cpp_include_withprefixbefore (const char *opt, const char *arg)
|
|
{
|
|
if (!arg) {
|
|
return -1;
|
|
}
|
|
arg = va (0, "%s%s", cpp_prefix, arg);
|
|
CPP_ADD (include, arg);
|
|
add_cpp_def (save_string ("-iwithprefixbefore"));
|
|
add_cpp_def (save_string (arg));
|
|
return 0;
|
|
}
|
|
|
|
#define CPP_INCLUDE(name) {#name, cpp_include_##name}
|
|
int
|
|
cpp_include (const char *opt, const char *arg)
|
|
{
|
|
static cpp_func_t include_funcs[] = {
|
|
CPP_INCLUDE (I),
|
|
CPP_INCLUDE (prefix),
|
|
CPP_INCLUDE (dirafter),
|
|
CPP_INCLUDE (quote),
|
|
CPP_INCLUDE (sysroot),
|
|
CPP_INCLUDE (system),
|
|
CPP_INCLUDE (withprefix),
|
|
CPP_INCLUDE (withprefixbefore),
|
|
{}
|
|
};
|
|
for (int i = 0; include_funcs[i].name; i++) {
|
|
if (!strcmp (opt, include_funcs[i].name)) {
|
|
return include_funcs[i].func (opt, arg);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
#undef CPP_INCLUDE
|
|
|
|
static rua_macro_t *
|
|
make_magic_macro (symtab_t *tab, const char *name, rua_macro_f update)
|
|
{
|
|
rua_macro_t *macro = malloc (sizeof (*macro));
|
|
*macro = (rua_macro_t) {
|
|
.name = save_string (name),
|
|
.tail = ¯o->tokens,
|
|
.update = update,
|
|
};
|
|
auto sym = symtab_lookup (tab, macro->name);
|
|
if (sym) {
|
|
internal_error (0, "\"%s\" redefined", macro->name);
|
|
}
|
|
sym = new_symbol (macro->name);
|
|
sym->sy_type = sy_macro;
|
|
sym->macro = macro;
|
|
symtab_addsymbol (tab, sym);
|
|
return macro;
|
|
}
|
|
|
|
void cpp_define (const char *arg)
|
|
{
|
|
if (!cpp_macros) {
|
|
cpp_macros = new_symtab (0, stab_global);
|
|
make_magic_macro (cpp_macros, "__FILE__", rua_macro_file);
|
|
make_magic_macro (cpp_macros, "__LINE__", rua_macro_line);
|
|
make_magic_macro (cpp_macros, "__VA_ARGS__", rua_macro_va_args);
|
|
}
|
|
size_t len = strlen (arg);
|
|
if (len > 0x10000) {
|
|
error (0, "command line define too long: %zd", len);
|
|
return;
|
|
}
|
|
char argstr[len + 4];
|
|
strcpy (argstr, arg);
|
|
argstr[len] = '\n';
|
|
argstr[len + 1] = 0;
|
|
char *eq = strchr (argstr, '=');
|
|
if (eq) {
|
|
*eq = ' ';
|
|
} else {
|
|
strcpy (argstr + len, " 1\n");
|
|
}
|
|
rua_parse_define (argstr);
|
|
|
|
arg = va (0, "-D%s", arg);
|
|
CPP_ADD (def, arg);
|
|
cpp_argc++;
|
|
}
|
|
|
|
void cpp_undefine (const char *arg)
|
|
{
|
|
if (cpp_macros) {
|
|
auto sym = symtab_lookup (cpp_macros, arg);
|
|
if (sym) {
|
|
symtab_removesymbol (cpp_macros, sym);
|
|
}
|
|
}
|
|
arg = va (0, "-D%s", arg);
|
|
CPP_ADD (undef, arg);
|
|
}
|
|
|
|
void
|
|
parse_cpp_name (void)
|
|
{
|
|
char *n, *e;
|
|
|
|
if (!cpp_name || !*cpp_name) {
|
|
return;
|
|
}
|
|
|
|
for (n = strdup (cpp_name); *n; n = e) {
|
|
for (; *n && *n == ' '; n++) continue;
|
|
for (e = n; *e && *e != ' '; e++) continue;
|
|
if (*e) *e++ = 0;
|
|
add_cpp_arg (n);
|
|
}
|
|
}
|
|
|
|
static void
|
|
build_cpp_args (const char *in_name, const char *out_name)
|
|
{
|
|
cpp_arg_t *cpp_arg;
|
|
const char **arg;
|
|
|
|
if (cpp_argv)
|
|
free (cpp_argv);
|
|
cpp_argv = (const char **)malloc ((cpp_argc + 1) * sizeof (char *));
|
|
for (arg = cpp_argv, cpp_arg = cpp_arg_list;
|
|
cpp_arg;
|
|
cpp_arg = cpp_arg->next) {
|
|
if (!strcmp (cpp_arg->arg, "%u")) {
|
|
arg = append_cpp_args (arg, cpp_undef_list);
|
|
} else if (!strcmp (cpp_arg->arg, "%s")) {
|
|
arg = append_cpp_args (arg, cpp_sysinc_list);
|
|
} else if (!strcmp (cpp_arg->arg, "%d")) {
|
|
arg = append_cpp_args (arg, cpp_def_list);
|
|
} else if (!strcmp (cpp_arg->arg, "%i")) {
|
|
*arg++ = in_name;
|
|
} else if (!strcmp (cpp_arg->arg, "%o")) {
|
|
if (!options.preprocess_only) {
|
|
*arg++ = out_name;
|
|
}
|
|
} else {
|
|
if (!options.preprocess_only || strcmp (cpp_arg->arg, "-o") != 0)
|
|
*arg++ = cpp_arg->arg;
|
|
}
|
|
}
|
|
*arg = 0;
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
void
|
|
intermediate_file (dstring_t *ifile, const char *filename, const char *ext,
|
|
int local)
|
|
{
|
|
if (options.save_temps) {
|
|
char *basename = strdup (filename);
|
|
char *temp;
|
|
|
|
temp = strrchr (basename, '/');
|
|
if (!temp)
|
|
temp = basename;
|
|
temp = strrchr (temp, '.');
|
|
if (temp)
|
|
*temp = '\0'; // ignore the rest of the string
|
|
|
|
temp = strrchr (basename, '/');
|
|
if (!temp)
|
|
temp = basename;
|
|
else
|
|
temp++;
|
|
|
|
if (*sourcedir) {
|
|
dsprintf (ifile, "%s%c%s.%s", sourcedir,
|
|
PATH_SEPARATOR, temp, ext);
|
|
} else {
|
|
dsprintf (ifile, "%s.%s", temp, ext);
|
|
}
|
|
free (basename);
|
|
} else if (local) {
|
|
char *temp2 = strrchr (this_program, PATH_SEPARATOR);
|
|
dsprintf (ifile, "%sXXXXXX", temp2 ? temp2 + 1 : this_program);
|
|
} else {
|
|
const char *temp1 = getenv ("TMPDIR");
|
|
char *temp2 = strrchr (this_program, PATH_SEPARATOR);
|
|
|
|
if ((!temp1) || (!temp1[0])) {
|
|
temp1 = getenv ("TEMP");
|
|
if ((!temp1) || (!temp1[0])) {
|
|
temp1 = "/tmp";
|
|
}
|
|
}
|
|
|
|
dsprintf (ifile, "%s%c%sXXXXXX", temp1,
|
|
PATH_SEPARATOR, temp2 ? temp2 + 1 : this_program);
|
|
}
|
|
}
|
|
|
|
static FILE *
|
|
run_cpp (const char *filename, const char *ext)
|
|
{
|
|
#ifndef _WIN32
|
|
pid_t pid;
|
|
int tempfd = 0;
|
|
#endif
|
|
|
|
intermediate_file (tempname, filename, ext ? ext : "p", 0);
|
|
build_cpp_args (filename, tempname->str);
|
|
if (!cpp_argv[0]) {
|
|
internal_error(0, "cpp_argv[0] is null");
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
if (!options.save_temps && !options.preprocess_only)
|
|
mktemp (tempname->str);
|
|
}
|
|
|
|
FILE *tmp = fopen (tempname->str, "wb");
|
|
if (tmp == NULL) {
|
|
fprintf (stderr, "%s: qfcc was unable to open\n",
|
|
tempname->str);
|
|
return 0;
|
|
}
|
|
fclose (tmp);
|
|
|
|
int status;
|
|
|
|
if (options.verbosity > 1) {
|
|
const char **a;
|
|
for (a = cpp_argv; *a; a++)
|
|
printf ("%s ", *a);
|
|
puts("");
|
|
}
|
|
|
|
#if defined(_WIN64) || defined(_WIN32)
|
|
status = spawnvp (_P_WAIT, cpp_argv[0], (char **) cpp_argv);
|
|
#else
|
|
status = spawnvp (_P_WAIT, cpp_argv[0], cpp_argv);
|
|
#endif
|
|
|
|
if (status) {
|
|
fprintf (stderr, "%s: cpp returned error code %d\n",
|
|
filename,
|
|
status);
|
|
return 0;
|
|
}
|
|
|
|
if (options.preprocess_only)
|
|
return 0;
|
|
return fopen (tempname->str, "rb");
|
|
#else
|
|
if (!options.save_temps && !options.preprocess_only)
|
|
tempfd = mkstemp (tempname->str);
|
|
|
|
if ((pid = fork ()) == -1) {
|
|
perror ("fork");
|
|
return 0;
|
|
}
|
|
if (!pid) {
|
|
// we're a child, check for abuse
|
|
if (options.verbosity > 1) {
|
|
const char **a;
|
|
for (a = cpp_argv; *a; a++)
|
|
printf ("%s ", *a);
|
|
puts("");
|
|
}
|
|
#ifdef HAVE_EXECVP
|
|
execvp (cpp_argv[0], (char **)cpp_argv);
|
|
#else
|
|
execve (cpp_argv[0], (char **)cpp_argv, environ);
|
|
#endif
|
|
perror (cpp_argv[0]);
|
|
exit (1);
|
|
} else {
|
|
// give parental guidance (or bury it in the back yard)
|
|
int status;
|
|
pid_t rc;
|
|
|
|
// printf ("pid = %d\n", pid);
|
|
#ifdef HAVE_WAITPID
|
|
rc = waitpid (0, &status, 0 | WUNTRACED);
|
|
#else
|
|
rc = wait (&status);
|
|
#endif
|
|
if ((rc) != pid) {
|
|
if (rc == -1) {
|
|
perror ("wait");
|
|
return 0;
|
|
}
|
|
fprintf (stderr, "%s: The wrong child (%ld) died. Don't ask me, I don't know either.\n",
|
|
this_program,
|
|
(long) rc);
|
|
return 0;
|
|
}
|
|
if (WIFEXITED (status)) {
|
|
if (WEXITSTATUS (status)) {
|
|
fprintf (stderr, "%s: cpp returned error code %d\n",
|
|
filename,
|
|
WEXITSTATUS (status));
|
|
return 0;
|
|
}
|
|
} else {
|
|
fprintf (stderr, "%s: cpp returned prematurely.\n", filename);
|
|
return 0;
|
|
}
|
|
}
|
|
if (options.preprocess_only) {
|
|
return 0;
|
|
} else if (options.save_temps) {
|
|
set_line_file (1, tempname->str, 0);
|
|
return fopen (tempname->str, "rb");
|
|
} else {
|
|
set_line_file (1, "1", 0);
|
|
return fdopen (tempfd, "rb");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
FILE *
|
|
preprocess_file (const char *filename, const char *ext)
|
|
{
|
|
if (cpp_name) {
|
|
return run_cpp (filename, ext);
|
|
} else {
|
|
set_line_file (1, filename, 0);
|
|
cpp_push_quote_path (filename);
|
|
FILE *file = fopen (filename, "rb");
|
|
if (!file) {
|
|
fprintf (stderr, "%s: error: %s: %s\n", this_program, filename,
|
|
strerror (errno));
|
|
pr.error_count++;
|
|
}
|
|
return file;
|
|
}
|
|
}
|
|
|
|
static const char *
|
|
test_path (const char *path, const char *name)
|
|
{
|
|
static dstring_t *fullpath;
|
|
if (!fullpath) {
|
|
fullpath = dstring_new ();
|
|
}
|
|
dstring_copystr (fullpath, path);
|
|
if (fullpath->size > 1 && fullpath->str[fullpath->size - 2] != '/') {
|
|
dstring_appendstr (fullpath, "/");
|
|
}
|
|
dstring_appendstr (fullpath, name);
|
|
if (Sys_FileExists (fullpath->str) == 0) {
|
|
return fullpath->str;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *
|
|
cpp_find_file (const char *name, int quote, bool *is_system)
|
|
{
|
|
*is_system = false;
|
|
if (*name == '/') {
|
|
return name;
|
|
}
|
|
const char *path;
|
|
if (quote == '"') {
|
|
if (cpp_quote_start
|
|
&& (path = test_path (cpp_quote_start->arg, name))) {
|
|
return path;
|
|
}
|
|
for (auto dir = cpp_quote_list; dir; dir = dir->next) {
|
|
if ((path = test_path (cpp_quote_start->arg, dir->arg))) {
|
|
return path;
|
|
}
|
|
}
|
|
}
|
|
for (auto dir = cpp_include_list; dir; dir = dir->next) {
|
|
if ((path = test_path (dir->arg, name))) {
|
|
return path;
|
|
}
|
|
}
|
|
*is_system = true;
|
|
for (auto dir = cpp_system_list; dir; dir = dir->next) {
|
|
if ((path = test_path (dir->arg, name))) {
|
|
return path;
|
|
}
|
|
}
|
|
for (auto dir = cpp_after_list; dir; dir = dir->next) {
|
|
if ((path = test_path (dir->arg, name))) {
|
|
return path;
|
|
}
|
|
}
|
|
if (!errno) {
|
|
errno = ENOENT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cpp_push_quote_path (const char *path)
|
|
{
|
|
if (!path) {
|
|
path = "";
|
|
} else {
|
|
const char *e = strrchr (path, '/');
|
|
if (!e) {
|
|
path = "";
|
|
} else {
|
|
path = save_substring (path, e - path);
|
|
}
|
|
}
|
|
auto quote_path = cpp_alloc_arg ();
|
|
quote_path->arg = path;
|
|
quote_path->next = cpp_quote_start;
|
|
cpp_quote_start = quote_path;
|
|
}
|
|
|
|
void cpp_pop_quote_path (void)
|
|
{
|
|
if (!cpp_quote_start) {
|
|
internal_error (0, "quote path stack underflow");
|
|
}
|
|
auto quote_path = cpp_quote_start;
|
|
cpp_quote_start = cpp_quote_start->next;
|
|
cpp_free_arg (quote_path);
|
|
}
|
|
|
|
void
|
|
cpp_write_dependencies (const char *sourcefile, const char *outputfile)
|
|
{
|
|
if (!options.dependencies || cpp_name) {
|
|
return;
|
|
}
|
|
if (!cpp_dep_target) {
|
|
const char *out = strrchr (outputfile, '/');
|
|
if (!out) {
|
|
out = outputfile - 1;
|
|
}
|
|
out++;
|
|
const char *dot = strrchr (outputfile, '.');
|
|
if (!dot) {
|
|
dot = outputfile + strlen (outputfile);
|
|
}
|
|
const char *tgt = va (0, "%.*s.qfo", (int) (dot - out), out);
|
|
cpp_dep_target = save_string (tgt);
|
|
cpp_dep_quote = 1;//FIXME implement
|
|
}
|
|
FILE *out = stdout;
|
|
if (cpp_dep_file) {
|
|
out = fopen (cpp_dep_file, "wt");
|
|
if (!out) {
|
|
fprintf (stderr, "%s: %s\n", cpp_dep_file, strerror (errno));
|
|
exit (1);
|
|
}
|
|
}
|
|
fprintf (out, "%s: %s", cpp_dep_target, sourcefile);
|
|
for (size_t i = 0; i < pr.comp_files.size; i++) {
|
|
const char *cf = pr.comp_files.a[i];
|
|
if (!strcmp (cf, sourcefile)) {
|
|
continue;
|
|
}
|
|
fprintf (out, " \\\n %s", cf);
|
|
}
|
|
if (cpp_dep_phony) {
|
|
for (size_t i = 0; i < pr.comp_files.size; i++) {
|
|
const char *cf = pr.comp_files.a[i];
|
|
if (!strcmp (cf, sourcefile)) {
|
|
continue;
|
|
}
|
|
fprintf (out, "\n%s:", cf);
|
|
}
|
|
}
|
|
fprintf (out, "\n");
|
|
}
|