/*- * 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 #include #include #include #include #include #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; iwhere = *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; iexpansion != 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; iwhere = *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; isuppress_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 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