Mercurial > ~dholland > hg > tradcpp > index.cgi
diff main.c @ 4:ee9a66b87c70
Initial version of toplevel and options handling.
author | David A. Holland |
---|---|
date | Sun, 19 Dec 2010 17:52:59 -0500 |
parents | |
children | 7c489c73d62b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.c Sun Dec 19 17:52:59 2010 -0500 @@ -0,0 +1,914 @@ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <err.h> + +#include "inlinedefs.h" // XXX +#include "version.h" +#include "config.h" +#include "utils.h" +#include "array.h" +#include "mode.h" +#include "files.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_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 { + 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) +{ + array_cleanup(&commandline_macros); +} + +static +void +commandline_macro_add(const char *macro, const char *expansion) +{ + struct commandline_macro *cm; + + cm = domalloc(sizeof(*cm)); + cm->macro = macro; + cm->expansion = expansion; +} + +static +void +commandline_def(char *str) +{ + char *val; + + val = strchr(str, '='); + if (val != NULL) { + *val = '\0'; + val++; + } + commandline_macro_add(str, val ? val : "1"); +} + +static +void +commandline_undef(char *str) +{ + commandline_macro_add(str, 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(NULL, cm->macro, cm->expansion); + } else { + macro_undef(cm->macro); + } + free(cm); + } + array_setsize(&commandline_macros, 0); +} + +static +void +apply_builtin_macro(const char *name, const char *val) +{ + /* XXX distinguish builtin-place and commandline-place and nowhere */ + macro_define(NULL, name, val); +} + +static +void +apply_builtin_macros(void) +{ +#ifdef CONFIG_OS + apply_builtin_macro(CONFIG_OS, "1"); +#endif +#ifdef CONFIG_OS_2 + apply_builtin_macro(CONFIG_OS_2, "1"); +#endif + +#ifdef CONFIG_CPU + apply_builtin_macro(CONFIG_CPU, "1"); +#endif +#ifdef CONFIG_CPU_2 + apply_builtin_macro(CONFIG_CPU_2, "1"); +#endif + +#ifdef CONFIG_SIZE + apply_builtin_macro(CONFIG_SIZE, "1"); +#endif +#ifdef CONFIG_BINFMT + apply_builtin_macro(CONFIG_BINFMT, "1"); +#endif + +#ifdef CONFIG_COMPILER + apply_builtin_macro(CONFIG_COMPILER, VERSION_MAJOR); + apply_builtin_macro(CONFIG_COMPILER_MINOR, VERSION_MINOR); + apply_builtin_macro("__VERSION__", VERSION_LONG); +#endif +} + +//////////////////////////////////////////////////////////// +// extra included files + +struct commandline_file { + 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) +{ + array_cleanup(&commandline_files); +} + +static +void +commandline_addfile(char *name, bool suppress_output) +{ + struct commandline_file *cf; + + cf = domalloc(sizeof(*cf)); + cf->name = name; + cf->suppress_output = suppress_output; + array_add(&commandline_files, cf, NULL); +} + +static +void +commandline_addfile_output(char *name) +{ + commandline_addfile(name, false); +} + +static +void +commandline_addfile_nooutput(char *name) +{ + commandline_addfile(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); + if (cf->suppress_output) { + save = mode.do_output; + mode.do_output = false; + files_read(NULL, cf->name); + mode.do_output = save; + } else { + files_read(NULL, cf->name); + } + } +} + +//////////////////////////////////////////////////////////// +// 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_cleanup(&incpath_quote); + stringarray_cleanup(&incpath_user); + stringarray_cleanup(&incpath_system); + stringarray_cleanup(&incpath_late); +} + +static +void +commandline_isysroot(char *dir) +{ + sysroot = dir; +} + +static +void +commandline_addincpath(struct stringarray *arr, char *s) +{ + stringarray_add(arr, s, NULL); +} + +static +void +commandline_addincpath_quote(char *dir) +{ + commandline_addincpath(&incpath_quote, dir); +} + +static +void +commandline_addincpath_user(char *dir) +{ + commandline_addincpath(&incpath_user, dir); +} + +static +void +commandline_addincpath_system(char *dir) +{ + commandline_addincpath(&incpath_system, dir); +} + +static +void +commandline_addincpath_late(char *dir) +{ + 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(".", 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(char *prefix) +{ + commandline_prefix = prefix; +} + +static +void +commandline_addincpath_user_withprefix(char *dir) +{ + char *s; + + if (commandline_prefix == NULL) { + warnx("-iprefix needed"); + die(); + } + s = dostrdup3(commandline_prefix, "/", dir); + freestringlater(s); + commandline_addincpath_user(s); +} + +static +void +commandline_addincpath_late_withprefix(char *dir) +{ + char *s; + + if (commandline_prefix == NULL) { + warnx("-iprefix needed"); + die(); + } + s = dostrdup3(commandline_prefix, "/", dir); + freestringlater(s); + commandline_addincpath_late(s); +} + +static +void +commandline_setstd(char *std) +{ + if (!strcmp(std, "krc")) { + return; + } + warnx("Standard %s not supported by this preprocessor", std); + die(); +} + +static +void +commandline_setlang(char *lang) +{ + if (!strcmp(lang, "c") || !strcmp(lang, "assembler-with-cpp")) { + return; + } + warnx("Language %s not supported by this preprocessor", lang); + die(); +} + +//////////////////////////////////////////////////////////// +// complex modes + +static +void +commandline_iremap(char *str) +{ + /* XXX */ + warnx("-iremap not supported"); + die(); +} + +static +void +commandline_tabstop(char *s) +{ + char *t; + unsigned long val; + + t = strchr(s, '='); + if (t == NULL) { + /* should not happen */ + warnx("Invalid tabstop"); + die(); + } + t++; + errno = 0; + val = strtoul(t, &t, 10); + if (errno || *t != '\0') { + warnx("Invalid tabstop"); + die(); + } + if (val > 64) { + warnx("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(char *str) +{ + mode.depend_target = str; + mode.depend_quote_target = false; +} + +static +void +commandline_setdependtarget_quoted(char *str) +{ + mode.depend_target = str; + mode.depend_quote_target = true; +} + +static +void +commandline_setdependoutput(char *str) +{ + 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 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)(char *); +}; + +struct arg_option { + const char *string; + void (*func)(char *); +}; + +static const struct flag_option flag_options[] = { + { "C", &mode.output_retain_comments, true }, + { "CC", &mode.output_retain_comments, true }, + { "fdollars-in-identifiers", &mode.input_allow_dollars, true }, + { "fno-dollars-in-identifiers", &mode.input_allow_dollars, false }, + { "MG", &mode.depend_assume_generated, true }, + { "MP", &mode.depend_issue_fakerules, true }, + { "nostdinc", &mode.do_stdinc, false }, + { "P", &mode.output_linenumbers, false }, + { "undef", &mode.do_stddef, 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 }, +}; +static const unsigned num_flag_options = HOWMANY(flag_options); + +static const struct act_option act_options[] = { + { "dD", commandline_dD }, + { "dI", commandline_dI }, + { "dM", commandline_dM }, + { "dN", commandline_dN }, + { "H", commandline_H }, + { "M", commandline_M }, + { "MD", commandline_MD }, + { "MM", commandline_MM }, + { "MMD", commandline_MMD }, + { "Wall", commandline_wall }, + { "Wno-all", commandline_wnoall }, + { "w", commandline_wnone }, +}; +static const unsigned num_act_options = HOWMANY(act_options); + +static const struct prefix_option prefix_options[] = { + { "D", commandline_def }, + { "ftabstop=", commandline_tabstop }, + { "I", commandline_addincpath_user }, + { "std=", commandline_setstd }, + { "U", commandline_undef }, +}; +static const unsigned num_prefix_options = HOWMANY(prefix_options); + +static const struct arg_option arg_options[] = { + { "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 }, + { "MF", commandline_setdependoutput }, + { "MT", commandline_setdependtarget }, + { "MQ", commandline_setdependtarget_quoted }, + { "x", commandline_setlang }, +}; +static const unsigned num_arg_options = HOWMANY(arg_options); + +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(char *opt) +{ + unsigned i; + int r; + + for (i=0; i<num_prefix_options; i++) { + r = strncmp(opt, prefix_options[i].string, + strlen(prefix_options[i].string)); + if (r == 0) { + prefix_options[i].func(opt); + return true; + } + if (r < 0) { + break; + } + } + return false; +} + +static +bool +check_arg_option(const char *opt, 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) { + warnx("Option -%s requires an argument", opt); + die(); + } + arg_options[i].func(arg); + return true; + } + if (r < 0) { + break; + } + } + return false; +} + +static +void +usage(void) +{ + fprintf(stderr, "Usage: %s [options] [infile [outfile]]\n", + getprogname()); + 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(); +} + +static +void +cleanup(void) +{ + unsigned i, num; + + commandline_files_cleanup(); + commandline_macros_cleanup(); + incpath_cleanup(); + + num = stringarray_num(&freestrings); + for (i=0; i<num; i++) { + free(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 *inputfile = NULL; + const char *outputfile = NULL; + int i; + + init(); + + for (i=1; i<argc; i++) { + if (argv[i][0] != '-') { + break; + } + if (check_flag_option(argv[i]+1)) { + continue; + } + if (check_act_option(argv[i]+1)) { + continue; + } + if (check_prefix_option(argv[i]+1)) { + continue; + } + if (check_arg_option(argv[i]+1, argv[i+1])) { + i++; + continue; + } + usage(); + } + if (i < argc) { + inputfile = argv[i++]; + } + if (i < argc) { + outputfile = argv[i++]; + } + if (i < argc) { + usage(); + } + + mode.output_file = outputfile; + + loadincludepath(); + apply_builtin_macros(); + apply_commandline_macros(); + read_commandline_files(); + files_read(NULL, inputfile); + + cleanup(); + return EXIT_SUCCESS; +}