mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
1113 lines
22 KiB
C
1113 lines
22 KiB
C
/*-
|
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by David A. Holland.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "bool.h"
|
|
#include "version.h"
|
|
#include "config.h"
|
|
#include "utils.h"
|
|
#include "array.h"
|
|
#include "mode.h"
|
|
#include "place.h"
|
|
#include "files.h"
|
|
#include "directive.h"
|
|
#include "macro.h"
|
|
|
|
struct mode mode = {
|
|
.werror = false,
|
|
|
|
.input_allow_dollars = false,
|
|
.input_tabstop = 8,
|
|
|
|
.do_stdinc = true,
|
|
.do_stddef = true,
|
|
|
|
.do_output = true,
|
|
.output_linenumbers = true,
|
|
.output_cheaplinenumbers = false,
|
|
.output_retain_comments = false,
|
|
.output_file = NULL,
|
|
|
|
.do_depend = false,
|
|
.depend_report_system = false,
|
|
.depend_assume_generated = false,
|
|
.depend_issue_fakerules = false,
|
|
.depend_quote_target = true,
|
|
.depend_target = NULL,
|
|
.depend_file = NULL,
|
|
|
|
.do_macrolist = false,
|
|
.macrolist_include_stddef = false,
|
|
.macrolist_include_expansions = false,
|
|
|
|
.do_trace = false,
|
|
.trace_namesonly = false,
|
|
.trace_indented = false,
|
|
};
|
|
|
|
struct warns warns = {
|
|
.endiflabels = true,
|
|
.nestcomment = false,
|
|
.undef = false,
|
|
.unused = false,
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// commandline macros
|
|
|
|
struct commandline_macro {
|
|
struct place where;
|
|
struct place where2;
|
|
const char *macro;
|
|
const char *expansion;
|
|
};
|
|
|
|
static struct array commandline_macros;
|
|
|
|
static
|
|
void
|
|
commandline_macros_init(void)
|
|
{
|
|
array_init(&commandline_macros);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_macros_cleanup(void)
|
|
{
|
|
unsigned i, num;
|
|
struct commandline_macro *cm;
|
|
|
|
num = array_num(&commandline_macros);
|
|
for (i=0; i<num; i++) {
|
|
cm = array_get(&commandline_macros, i);
|
|
dofree(cm, sizeof(*cm));
|
|
}
|
|
array_setsize(&commandline_macros, 0);
|
|
|
|
array_cleanup(&commandline_macros);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_macro_add(const struct place *p, const char *macro,
|
|
const struct place *p2, const char *expansion)
|
|
{
|
|
struct commandline_macro *cm;
|
|
|
|
cm = domalloc(sizeof(*cm));
|
|
cm->where = *p;
|
|
cm->where2 = *p2;
|
|
cm->macro = macro;
|
|
cm->expansion = expansion;
|
|
|
|
array_add(&commandline_macros, cm, NULL);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_def(const struct place *p, char *str)
|
|
{
|
|
struct place p2;
|
|
char *val;
|
|
|
|
if (*str == '\0') {
|
|
complain(NULL, "-D: macro name expected");
|
|
die();
|
|
}
|
|
|
|
val = strchr(str, '=');
|
|
if (val != NULL) {
|
|
*val = '\0';
|
|
val++;
|
|
}
|
|
|
|
if (val) {
|
|
p2 = *p;
|
|
place_addcolumns(&p2, strlen(str));
|
|
} else {
|
|
place_setbuiltin(&p2, 1);
|
|
}
|
|
commandline_macro_add(p, str, &p2, val ? val : "1");
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_undef(const struct place *p, char *str)
|
|
{
|
|
if (*str == '\0') {
|
|
complain(NULL, "-U: macro name expected");
|
|
die();
|
|
}
|
|
commandline_macro_add(p, str, p, NULL);
|
|
}
|
|
|
|
static
|
|
void
|
|
apply_commandline_macros(void)
|
|
{
|
|
struct commandline_macro *cm;
|
|
unsigned i, num;
|
|
|
|
num = array_num(&commandline_macros);
|
|
for (i=0; i<num; i++) {
|
|
cm = array_get(&commandline_macros, i);
|
|
if (cm->expansion != NULL) {
|
|
macro_define_plain(&cm->where, cm->macro,
|
|
&cm->where2, cm->expansion);
|
|
} else {
|
|
macro_undef(cm->macro);
|
|
}
|
|
dofree(cm, sizeof(*cm));
|
|
}
|
|
array_setsize(&commandline_macros, 0);
|
|
}
|
|
|
|
static
|
|
void
|
|
apply_magic_macro(unsigned num, const char *name)
|
|
{
|
|
struct place p;
|
|
|
|
place_setbuiltin(&p, num);
|
|
macro_define_magic(&p, name);
|
|
}
|
|
|
|
static
|
|
void
|
|
apply_builtin_macro(unsigned num, const char *name, const char *val)
|
|
{
|
|
struct place p;
|
|
|
|
place_setbuiltin(&p, num);
|
|
macro_define_plain(&p, name, &p, val);
|
|
}
|
|
|
|
static
|
|
void
|
|
apply_builtin_macros(void)
|
|
{
|
|
unsigned n = 1;
|
|
|
|
apply_magic_macro(n++, "__FILE__");
|
|
apply_magic_macro(n++, "__LINE__");
|
|
|
|
#ifdef CONFIG_OS
|
|
apply_builtin_macro(n++, CONFIG_OS, "1");
|
|
#endif
|
|
#ifdef CONFIG_OS_2
|
|
apply_builtin_macro(n++, CONFIG_OS_2, "1");
|
|
#endif
|
|
|
|
#ifdef CONFIG_CPU
|
|
apply_builtin_macro(n++, CONFIG_CPU, "1");
|
|
#endif
|
|
#ifdef CONFIG_CPU_2
|
|
apply_builtin_macro(n++, CONFIG_CPU_2, "1");
|
|
#endif
|
|
|
|
#ifdef CONFIG_SIZE
|
|
apply_builtin_macro(n++, CONFIG_SIZE, "1");
|
|
#endif
|
|
#ifdef CONFIG_BINFMT
|
|
apply_builtin_macro(n++, CONFIG_BINFMT, "1");
|
|
#endif
|
|
|
|
#ifdef CONFIG_COMPILER
|
|
apply_builtin_macro(n++, CONFIG_COMPILER, VERSION_MAJOR);
|
|
apply_builtin_macro(n++, CONFIG_COMPILER_MINOR, VERSION_MINOR);
|
|
apply_builtin_macro(n++, "__VERSION__", VERSION_LONG);
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// extra included files
|
|
|
|
struct commandline_file {
|
|
struct place where;
|
|
char *name;
|
|
bool suppress_output;
|
|
};
|
|
|
|
static struct array commandline_files;
|
|
|
|
static
|
|
void
|
|
commandline_files_init(void)
|
|
{
|
|
array_init(&commandline_files);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_files_cleanup(void)
|
|
{
|
|
unsigned i, num;
|
|
struct commandline_file *cf;
|
|
|
|
num = array_num(&commandline_files);
|
|
for (i=0; i<num; i++) {
|
|
cf = array_get(&commandline_files, i);
|
|
if (cf != NULL) {
|
|
dofree(cf, sizeof(*cf));
|
|
}
|
|
}
|
|
array_setsize(&commandline_files, 0);
|
|
|
|
array_cleanup(&commandline_files);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addfile(const struct place *p, char *name, bool suppress_output)
|
|
{
|
|
struct commandline_file *cf;
|
|
|
|
cf = domalloc(sizeof(*cf));
|
|
cf->where = *p;
|
|
cf->name = name;
|
|
cf->suppress_output = suppress_output;
|
|
array_add(&commandline_files, cf, NULL);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addfile_output(const struct place *p, char *name)
|
|
{
|
|
commandline_addfile(p, name, false);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addfile_nooutput(const struct place *p, char *name)
|
|
{
|
|
commandline_addfile(p, name, true);
|
|
}
|
|
|
|
static
|
|
void
|
|
read_commandline_files(void)
|
|
{
|
|
struct commandline_file *cf;
|
|
unsigned i, num;
|
|
bool save = false;
|
|
|
|
num = array_num(&commandline_files);
|
|
for (i=0; i<num; i++) {
|
|
cf = array_get(&commandline_files, i);
|
|
array_set(&commandline_files, i, NULL);
|
|
if (cf->suppress_output) {
|
|
save = mode.do_output;
|
|
mode.do_output = false;
|
|
file_readquote(&cf->where, cf->name);
|
|
mode.do_output = save;
|
|
} else {
|
|
file_readquote(&cf->where, cf->name);
|
|
}
|
|
dofree(cf, sizeof(*cf));
|
|
}
|
|
array_setsize(&commandline_files, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// include path accumulation
|
|
|
|
static struct stringarray incpath_quote;
|
|
static struct stringarray incpath_user;
|
|
static struct stringarray incpath_system;
|
|
static struct stringarray incpath_late;
|
|
static const char *sysroot;
|
|
|
|
static
|
|
void
|
|
incpath_init(void)
|
|
{
|
|
stringarray_init(&incpath_quote);
|
|
stringarray_init(&incpath_user);
|
|
stringarray_init(&incpath_system);
|
|
stringarray_init(&incpath_late);
|
|
}
|
|
|
|
static
|
|
void
|
|
incpath_cleanup(void)
|
|
{
|
|
stringarray_setsize(&incpath_quote, 0);
|
|
stringarray_setsize(&incpath_user, 0);
|
|
stringarray_setsize(&incpath_system, 0);
|
|
stringarray_setsize(&incpath_late, 0);
|
|
|
|
stringarray_cleanup(&incpath_quote);
|
|
stringarray_cleanup(&incpath_user);
|
|
stringarray_cleanup(&incpath_system);
|
|
stringarray_cleanup(&incpath_late);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_isysroot(const struct place *p, char *dir)
|
|
{
|
|
(void)p;
|
|
sysroot = dir;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath(struct stringarray *arr, char *s)
|
|
{
|
|
if (*s == '\0') {
|
|
complain(NULL, "Empty include directory");
|
|
die();
|
|
}
|
|
stringarray_add(arr, s, NULL);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_quote(const struct place *p, char *dir)
|
|
{
|
|
(void)p;
|
|
commandline_addincpath(&incpath_quote, dir);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_user(const struct place *p, char *dir)
|
|
{
|
|
(void)p;
|
|
commandline_addincpath(&incpath_user, dir);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_system(const struct place *p, char *dir)
|
|
{
|
|
(void)p;
|
|
commandline_addincpath(&incpath_system, dir);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_late(const struct place *p, char *dir)
|
|
{
|
|
(void)p;
|
|
commandline_addincpath(&incpath_late, dir);
|
|
}
|
|
|
|
static
|
|
void
|
|
loadincludepath(void)
|
|
{
|
|
unsigned i, num;
|
|
const char *dir;
|
|
char *t;
|
|
|
|
num = stringarray_num(&incpath_quote);
|
|
for (i=0; i<num; i++) {
|
|
dir = stringarray_get(&incpath_quote, i);
|
|
files_addquotepath(dir, false);
|
|
}
|
|
files_addquotepath(NULL, false);
|
|
|
|
num = stringarray_num(&incpath_user);
|
|
for (i=0; i<num; i++) {
|
|
dir = stringarray_get(&incpath_user, i);
|
|
files_addquotepath(dir, false);
|
|
files_addbracketpath(dir, false);
|
|
}
|
|
|
|
if (mode.do_stdinc) {
|
|
if (sysroot != NULL) {
|
|
t = dostrdup3(sysroot, "/", CONFIG_LOCALINCLUDE);
|
|
freestringlater(t);
|
|
dir = t;
|
|
} else {
|
|
dir = CONFIG_LOCALINCLUDE;
|
|
}
|
|
files_addquotepath(dir, true);
|
|
files_addbracketpath(dir, true);
|
|
|
|
if (sysroot != NULL) {
|
|
t = dostrdup3(sysroot, "/", CONFIG_SYSTEMINCLUDE);
|
|
freestringlater(t);
|
|
dir = t;
|
|
} else {
|
|
dir = CONFIG_SYSTEMINCLUDE;
|
|
}
|
|
files_addquotepath(dir, true);
|
|
files_addbracketpath(dir, true);
|
|
}
|
|
|
|
num = stringarray_num(&incpath_system);
|
|
for (i=0; i<num; i++) {
|
|
dir = stringarray_get(&incpath_system, i);
|
|
files_addquotepath(dir, true);
|
|
files_addbracketpath(dir, true);
|
|
}
|
|
|
|
num = stringarray_num(&incpath_late);
|
|
for (i=0; i<num; i++) {
|
|
dir = stringarray_get(&incpath_late, i);
|
|
files_addquotepath(dir, false);
|
|
files_addbracketpath(dir, false);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// silly commandline stuff
|
|
|
|
static const char *commandline_prefix;
|
|
|
|
static
|
|
void
|
|
commandline_setprefix(const struct place *p, char *prefix)
|
|
{
|
|
(void)p;
|
|
commandline_prefix = prefix;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_user_withprefix(const struct place *p, char *dir)
|
|
{
|
|
char *s;
|
|
|
|
if (commandline_prefix == NULL) {
|
|
complain(NULL, "-iprefix needed");
|
|
die();
|
|
}
|
|
s = dostrdup3(commandline_prefix, "/", dir);
|
|
freestringlater(s);
|
|
commandline_addincpath_user(p, s);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_addincpath_late_withprefix(const struct place *p, char *dir)
|
|
{
|
|
char *s;
|
|
|
|
if (commandline_prefix == NULL) {
|
|
complain(NULL, "-iprefix needed");
|
|
die();
|
|
}
|
|
s = dostrdup3(commandline_prefix, "/", dir);
|
|
freestringlater(s);
|
|
commandline_addincpath_late(p, s);
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_setstd(const struct place *p, char *std)
|
|
{
|
|
(void)p;
|
|
|
|
if (!strcmp(std, "krc")) {
|
|
return;
|
|
}
|
|
complain(NULL, "Standard %s not supported by this preprocessor", std);
|
|
die();
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_setlang(const struct place *p, char *lang)
|
|
{
|
|
(void)p;
|
|
|
|
if (!strcmp(lang, "c") || !strcmp(lang, "assembler-with-cpp")) {
|
|
return;
|
|
}
|
|
complain(NULL, "Language %s not supported by this preprocessor", lang);
|
|
die();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// complex modes
|
|
|
|
DEAD static
|
|
void
|
|
commandline_iremap(const struct place *p, char *str)
|
|
{
|
|
(void)p;
|
|
/* XXX */
|
|
(void)str;
|
|
complain(NULL, "-iremap not supported");
|
|
die();
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_tabstop(const struct place *p, char *s)
|
|
{
|
|
char *t;
|
|
unsigned long val;
|
|
|
|
(void)p;
|
|
|
|
t = strchr(s, '=');
|
|
if (t == NULL) {
|
|
/* should not happen */
|
|
complain(NULL, "Invalid tabstop");
|
|
die();
|
|
}
|
|
t++;
|
|
errno = 0;
|
|
val = strtoul(t, &t, 10);
|
|
if (errno || *t != '\0') {
|
|
complain(NULL, "Invalid tabstop");
|
|
die();
|
|
}
|
|
if (val > 64) {
|
|
complain(NULL, "Preposterously large tabstop");
|
|
die();
|
|
}
|
|
mode.input_tabstop = val;
|
|
}
|
|
|
|
/*
|
|
* macrolist
|
|
*/
|
|
|
|
static
|
|
void
|
|
commandline_dD(void)
|
|
{
|
|
mode.do_macrolist = true;
|
|
mode.macrolist_include_stddef = false;
|
|
mode.macrolist_include_expansions = true;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_dM(void)
|
|
{
|
|
mode.do_macrolist = true;
|
|
mode.macrolist_include_stddef = true;
|
|
mode.macrolist_include_expansions = true;
|
|
mode.do_output = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_dN(void)
|
|
{
|
|
mode.do_macrolist = true;
|
|
mode.macrolist_include_stddef = false;
|
|
mode.macrolist_include_expansions = false;
|
|
}
|
|
|
|
/*
|
|
* include trace
|
|
*/
|
|
|
|
static
|
|
void
|
|
commandline_dI(void)
|
|
{
|
|
mode.do_trace = true;
|
|
mode.trace_namesonly = false;
|
|
mode.trace_indented = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_H(void)
|
|
{
|
|
mode.do_trace = true;
|
|
mode.trace_namesonly = true;
|
|
mode.trace_indented = true;
|
|
}
|
|
|
|
/*
|
|
* depend
|
|
*/
|
|
|
|
static
|
|
void
|
|
commandline_setdependtarget(const struct place *p, char *str)
|
|
{
|
|
(void)p;
|
|
mode.depend_target = str;
|
|
mode.depend_quote_target = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_setdependtarget_quoted(const struct place *p, char *str)
|
|
{
|
|
(void)p;
|
|
mode.depend_target = str;
|
|
mode.depend_quote_target = true;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_setdependoutput(const struct place *p, char *str)
|
|
{
|
|
(void)p;
|
|
mode.depend_file = str;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_M(void)
|
|
{
|
|
mode.do_depend = true;
|
|
mode.depend_report_system = true;
|
|
mode.do_output = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_MM(void)
|
|
{
|
|
mode.do_depend = true;
|
|
mode.depend_report_system = false;
|
|
mode.do_output = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_MD(void)
|
|
{
|
|
mode.do_depend = true;
|
|
mode.depend_report_system = true;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_MMD(void)
|
|
{
|
|
mode.do_depend = true;
|
|
mode.depend_report_system = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_wall(void)
|
|
{
|
|
warns.nestcomment = true;
|
|
warns.undef = true;
|
|
warns.unused = true;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_wnoall(void)
|
|
{
|
|
warns.nestcomment = false;
|
|
warns.undef = false;
|
|
warns.unused = false;
|
|
}
|
|
|
|
static
|
|
void
|
|
commandline_wnone(void)
|
|
{
|
|
warns.nestcomment = false;
|
|
warns.endiflabels = false;
|
|
warns.undef = false;
|
|
warns.unused = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// options
|
|
|
|
struct ignore_option {
|
|
const char *string;
|
|
};
|
|
|
|
struct flag_option {
|
|
const char *string;
|
|
bool *flag;
|
|
bool setto;
|
|
};
|
|
|
|
struct act_option {
|
|
const char *string;
|
|
void (*func)(void);
|
|
};
|
|
|
|
struct prefix_option {
|
|
const char *string;
|
|
void (*func)(const struct place *, char *);
|
|
};
|
|
|
|
struct arg_option {
|
|
const char *string;
|
|
void (*func)(const struct place *, char *);
|
|
};
|
|
|
|
static const struct ignore_option ignore_options[] = {
|
|
{ "m32" },
|
|
{ "traditional" },
|
|
};
|
|
static const unsigned num_ignore_options = HOWMANY(ignore_options);
|
|
|
|
static const struct flag_option flag_options[] = {
|
|
{ "C", &mode.output_retain_comments, true },
|
|
{ "CC", &mode.output_retain_comments, true },
|
|
{ "MG", &mode.depend_assume_generated, true },
|
|
{ "MP", &mode.depend_issue_fakerules, true },
|
|
{ "P", &mode.output_linenumbers, false },
|
|
{ "Wcomment", &warns.nestcomment, true },
|
|
{ "Wendif-labels", &warns.endiflabels, true },
|
|
{ "Werror", &mode.werror, true },
|
|
{ "Wno-comment", &warns.nestcomment, false },
|
|
{ "Wno-endif-labels", &warns.endiflabels, false },
|
|
{ "Wno-error", &mode.werror, false },
|
|
{ "Wno-undef", &warns.undef, false },
|
|
{ "Wno-unused-macros", &warns.unused, false },
|
|
{ "Wundef", &warns.undef, true },
|
|
{ "Wunused-macros", &warns.unused, true },
|
|
{ "fdollars-in-identifiers", &mode.input_allow_dollars, true },
|
|
{ "fno-dollars-in-identifiers", &mode.input_allow_dollars, false },
|
|
{ "nostdinc", &mode.do_stdinc, false },
|
|
{ "p", &mode.output_cheaplinenumbers, true },
|
|
{ "undef", &mode.do_stddef, false },
|
|
};
|
|
static const unsigned num_flag_options = HOWMANY(flag_options);
|
|
|
|
static const struct act_option act_options[] = {
|
|
{ "H", commandline_H },
|
|
{ "M", commandline_M },
|
|
{ "MD", commandline_MD },
|
|
{ "MM", commandline_MM },
|
|
{ "MMD", commandline_MMD },
|
|
{ "Wall", commandline_wall },
|
|
{ "Wno-all", commandline_wnoall },
|
|
{ "dD", commandline_dD },
|
|
{ "dI", commandline_dI },
|
|
{ "dM", commandline_dM },
|
|
{ "dN", commandline_dN },
|
|
{ "w", commandline_wnone },
|
|
};
|
|
static const unsigned num_act_options = HOWMANY(act_options);
|
|
|
|
static const struct prefix_option prefix_options[] = {
|
|
{ "D", commandline_def },
|
|
{ "I", commandline_addincpath_user },
|
|
{ "U", commandline_undef },
|
|
{ "ftabstop=", commandline_tabstop },
|
|
{ "std=", commandline_setstd },
|
|
};
|
|
static const unsigned num_prefix_options = HOWMANY(prefix_options);
|
|
|
|
static const struct arg_option arg_options[] = {
|
|
{ "MF", commandline_setdependoutput },
|
|
{ "MQ", commandline_setdependtarget_quoted },
|
|
{ "MT", commandline_setdependtarget },
|
|
{ "debuglog", debuglog_open },
|
|
{ "idirafter", commandline_addincpath_late },
|
|
{ "imacros", commandline_addfile_nooutput },
|
|
{ "include", commandline_addfile_output },
|
|
{ "iprefix", commandline_setprefix },
|
|
{ "iquote", commandline_addincpath_quote },
|
|
{ "iremap", commandline_iremap },
|
|
{ "isysroot", commandline_isysroot },
|
|
{ "isystem", commandline_addincpath_system },
|
|
{ "iwithprefix", commandline_addincpath_late_withprefix },
|
|
{ "iwithprefixbefore", commandline_addincpath_user_withprefix },
|
|
{ "x", commandline_setlang },
|
|
};
|
|
static const unsigned num_arg_options = HOWMANY(arg_options);
|
|
|
|
static
|
|
bool
|
|
check_ignore_option(const char *opt)
|
|
{
|
|
unsigned i;
|
|
int r;
|
|
|
|
for (i=0; i<num_ignore_options; i++) {
|
|
r = strcmp(opt, ignore_options[i].string);
|
|
if (r == 0) {
|
|
return true;
|
|
}
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static
|
|
bool
|
|
check_flag_option(const char *opt)
|
|
{
|
|
unsigned i;
|
|
int r;
|
|
|
|
for (i=0; i<num_flag_options; i++) {
|
|
r = strcmp(opt, flag_options[i].string);
|
|
if (r == 0) {
|
|
*flag_options[i].flag = flag_options[i].setto;
|
|
return true;
|
|
}
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static
|
|
bool
|
|
check_act_option(const char *opt)
|
|
{
|
|
unsigned i;
|
|
int r;
|
|
|
|
for (i=0; i<num_act_options; i++) {
|
|
r = strcmp(opt, act_options[i].string);
|
|
if (r == 0) {
|
|
act_options[i].func();
|
|
return true;
|
|
}
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static
|
|
bool
|
|
check_prefix_option(const struct place *p, char *opt)
|
|
{
|
|
unsigned i, len;
|
|
int r;
|
|
|
|
for (i=0; i<num_prefix_options; i++) {
|
|
len = strlen(prefix_options[i].string);
|
|
r = strncmp(opt, prefix_options[i].string, len);
|
|
if (r == 0) {
|
|
prefix_options[i].func(p, opt + len);
|
|
return true;
|
|
}
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static
|
|
bool
|
|
check_arg_option(const char *opt, const struct place *argplace, char *arg)
|
|
{
|
|
unsigned i;
|
|
int r;
|
|
|
|
for (i=0; i<num_arg_options; i++) {
|
|
r = strcmp(opt, arg_options[i].string);
|
|
if (r == 0) {
|
|
if (arg == NULL) {
|
|
complain(NULL,
|
|
"Option -%s requires an argument",
|
|
opt);
|
|
die();
|
|
}
|
|
arg_options[i].func(argplace, arg);
|
|
return true;
|
|
}
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DEAD PF(2, 3) static
|
|
void
|
|
usage(const char *progname, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
fprintf(stderr, "%s: ", progname);
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
fprintf(stderr, "\n");
|
|
|
|
fprintf(stderr, "usage: %s [options] [infile [outfile]]\n", progname);
|
|
fprintf(stderr, "Common options:\n");
|
|
fprintf(stderr, " -C Retain comments\n");
|
|
fprintf(stderr, " -Dmacro[=def] Predefine macro\n");
|
|
fprintf(stderr, " -Idir Add to include path\n");
|
|
fprintf(stderr, " -M Issue depend info\n");
|
|
fprintf(stderr, " -MD Issue depend info and output\n");
|
|
fprintf(stderr, " -MM -M w/o system headers\n");
|
|
fprintf(stderr, " -MMD -MD w/o system headers\n");
|
|
fprintf(stderr, " -nostdinc Drop default include path\n");
|
|
fprintf(stderr, " -Umacro Undefine macro\n");
|
|
fprintf(stderr, " -undef Undefine everything\n");
|
|
fprintf(stderr, " -Wall Enable all warnings\n");
|
|
fprintf(stderr, " -Werror Make warnings into errors\n");
|
|
fprintf(stderr, " -w Disable all warnings\n");
|
|
die();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// exit and cleanup
|
|
|
|
static struct stringarray freestrings;
|
|
|
|
static
|
|
void
|
|
init(void)
|
|
{
|
|
stringarray_init(&freestrings);
|
|
|
|
incpath_init();
|
|
commandline_macros_init();
|
|
commandline_files_init();
|
|
|
|
place_init();
|
|
files_init();
|
|
directive_init();
|
|
macros_init();
|
|
}
|
|
|
|
static
|
|
void
|
|
cleanup(void)
|
|
{
|
|
unsigned i, num;
|
|
|
|
macros_cleanup();
|
|
directive_cleanup();
|
|
files_cleanup();
|
|
place_cleanup();
|
|
|
|
commandline_files_cleanup();
|
|
commandline_macros_cleanup();
|
|
incpath_cleanup();
|
|
debuglog_close();
|
|
|
|
num = stringarray_num(&freestrings);
|
|
for (i=0; i<num; i++) {
|
|
dostrfree(stringarray_get(&freestrings, i));
|
|
}
|
|
stringarray_setsize(&freestrings, 0);
|
|
stringarray_cleanup(&freestrings);
|
|
}
|
|
|
|
void
|
|
die(void)
|
|
{
|
|
cleanup();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
freestringlater(char *s)
|
|
{
|
|
stringarray_add(&freestrings, s, NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// main
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
const char *progname;
|
|
const char *inputfile = NULL;
|
|
const char *outputfile = NULL;
|
|
struct place cmdplace;
|
|
int i;
|
|
|
|
progname = strrchr(argv[0], '/');
|
|
progname = progname == NULL ? argv[0] : progname + 1;
|
|
complain_init(progname);
|
|
|
|
init();
|
|
|
|
for (i=1; i<argc; i++) {
|
|
if (argv[i][0] != '-' || argv[i][1] == 0) {
|
|
break;
|
|
}
|
|
place_setcommandline(&cmdplace, i, 1);
|
|
if (check_ignore_option(argv[i]+1)) {
|
|
continue;
|
|
}
|
|
if (check_flag_option(argv[i]+1)) {
|
|
continue;
|
|
}
|
|
if (check_act_option(argv[i]+1)) {
|
|
continue;
|
|
}
|
|
if (check_prefix_option(&cmdplace, argv[i]+1)) {
|
|
continue;
|
|
}
|
|
place_setcommandline(&cmdplace, i+1, 1);
|
|
if (check_arg_option(argv[i]+1, &cmdplace, argv[i+1])) {
|
|
i++;
|
|
continue;
|
|
}
|
|
usage(progname, "Invalid option %s", argv[i]);
|
|
}
|
|
if (i < argc) {
|
|
inputfile = argv[i++];
|
|
if (!strcmp(inputfile, "-")) {
|
|
inputfile = NULL;
|
|
}
|
|
}
|
|
if (i < argc) {
|
|
outputfile = argv[i++];
|
|
if (!strcmp(outputfile, "-")) {
|
|
outputfile = NULL;
|
|
}
|
|
}
|
|
if (i < argc) {
|
|
usage(progname, "Extra non-option argument %s", argv[i]);
|
|
}
|
|
|
|
mode.output_file = outputfile;
|
|
|
|
loadincludepath();
|
|
apply_builtin_macros();
|
|
apply_commandline_macros();
|
|
read_commandline_files();
|
|
place_setnowhere(&cmdplace);
|
|
file_readabsolute(&cmdplace, inputfile);
|
|
|
|
cleanup();
|
|
if (complain_failed()) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|