Mercurial > ~dholland > hg > tradcpp > index.cgi
view main.c @ 134:b17209c1ced5
Added tag release-0.3 for changeset 31fc4251ec3b
author | David A. Holland |
---|---|
date | Sun, 16 Jun 2013 22:41:27 -0400 |
parents | 64c4de3709de |
children | eaae8014a94a |
line wrap: on
line source
/*- * 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 <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <err.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_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, }; /* this is always true, but can be set explicitly with -traditional */ static bool traditional = true; //////////////////////////////////////////////////////////// // 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) { 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') { warnx("-D: macro name expected"); die(); } val = strchr(str, '='); if (val != NULL) { *val = '\0'; val++; } if (val) { p2 = *p; p2.column += 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') { warnx("-D: 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_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; #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) { 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); 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') { warnx("Empty include path"); 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) { warnx("-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) { warnx("-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; } warnx("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; } warnx("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; warnx("-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 */ 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(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 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 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 }, { "traditional", &traditional, 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 }, { "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_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) { warnx("Option -%s requires an argument", opt); die(); } arg_options[i].func(argplace, arg); return true; } if (r < 0) { break; } } return false; } DEAD static void usage(const char *argv0) { const char *progname; progname = strrchr(argv0, '/'); progname = progname == NULL ? argv0 : progname + 1; 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(); 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 *inputfile = NULL; const char *outputfile = NULL; struct place cmdplace; int i; init(); for (i=1; i<argc; i++) { if (argv[i][0] != '-') { break; } place_setcommandline(&cmdplace, i, 1); 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(argv[0]); } if (i < argc) { inputfile = argv[i++]; } if (i < argc) { outputfile = argv[i++]; } if (i < argc) { usage(argv[0]); } 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; }