X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=main.c;h=4bdde47506d883b80e00f4b1241efe7af8808fad;hp=3e8b8b6b45c73c51f9aaf3c64d9c53b49c37bd1a;hb=05966ee00986535f426c5d2229397eab4b15412e;hpb=a6d9357ef9fd9e6a83aca86115f6e32d991d1c1c diff --git a/main.c b/main.c index 3e8b8b6..4bdde47 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012 - * Dale Weiler + * Copyright (C) 2012 + * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -20,57 +20,160 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include -#include #include "gmqcc.h" +// todo CLEANUP this argitem thing +typedef struct { char *name, type; } argitem; +VECTOR_MAKE(argitem, items); -//typedef int foo; +/* global options */ +bool opts_debug = false; +bool opts_memchk = false; +bool opts_darkplaces_stringtablebug = false; +bool opts_omit_nullcode = false; +int opts_compiler = COMPILER_GMQCC; -int usage(const char *name) { - printf("Usage: %s -f infile -o outfile\n", name); - return 0; +static const int usage(const char *const app) { + printf("usage:\n" + " %s -c -oprog.dat -- compile file\n" + " %s -a -oprog.dat -- assemble file\n" + " %s -c -i -oprog.dat -- compile together (allowed multiple -i)\n" + " %s -a -i -oprog.dat -- assemble together(allowed multiple -i)\n" + " example:\n" + " %s -cfoo.qc -ibar.qc -oqc.dat -afoo.qs -ibar.qs -oqs.dat\n" + " additional flags:\n" + " -debug -- turns on compiler debug messages\n" + " -memchk -- turns on compiler memory leak check\n" + " -help -- prints this help/usage text\n" + " -std -- select the QuakeC compile type (types below):\n" + " -std=qcc -- original QuakeC\n" + " -std=ftqecc -- fteqcc QuakeC\n" + " -std=qccx -- qccx QuakeC\n" + " -std=gmqcc -- this compiler QuakeC (default selection)\n" + " codegen flags:\n" + " -fdarkplaces-string-table-bug -- patches the string table to work with bugged versions of darkplaces\n" + " -fomit-nullcode -- omits the generation of null code (will break everywhere see propsal.txt)\n", + app,app,app,app,app + ); + return -1; } int main(int argc, char **argv) { - const char *ofile = NULL; - const char *ifile = NULL; - int i; - if (argc <= 2) { - return usage(*argv); - } - - for (i=0; i < argc; i++) { - if (argc != i + 1) { - switch(argv[i][0]) { - case '-': - switch(argv[i][1]) { - case 'f': ifile = argv[i+1]; break; - case 'o': ofile = argv[i+1]; break; - } - break; - } - } - } - - if (!ofile || !ifile) { - return usage(*argv); - } - - printf("ifile: %s\n", ifile); - printf("ofile: %s\n", ofile); - - /* Open file */ - FILE *fp = fopen(ifile, "r"); - - /* run the preprocessor */ - if (!fp) { - fclose(fp); - return error(ERROR_COMPILER, "Source file: %s not found\n", ifile); - } else { - struct lex_file *lex = lex_open(fp); - parse (lex); - lex_close(lex); - } - return 0; + size_t itr = 0; + char *app = &argv[0][0]; + FILE *fpp = NULL; + lex_file *lex = NULL; + + /* + * Parse all command line arguments. This is rather annoying to do + * because of all tiny corner cases. + */ + if (argc <= 1 || (argv[1][0] != '-')) + return usage(app); + + while ((argc > 1) && argv[1][0] == '-') { + switch (argv[1][1]) { + case 'v': { + printf("GMQCC:\n" + " version: %d.%d.%d (0x%08X)\n" + " build date: %s\n" + " build time: %s\n", + (GMQCC_VERSION >> 16) & 0xFF, + (GMQCC_VERSION >> 8) & 0xFF, + (GMQCC_VERSION >> 0) & 0xFF, + (GMQCC_VERSION), + __DATE__, + __TIME__ + ); + return 0; + } + #define param_argument(argtype) do { \ + if (argv[1][2]) { \ + items_add((argitem){util_strdup(&argv[1][2]), argtype}); \ + } else { \ + ++argv; \ + --argc; \ + if (argc <= 1) \ + goto clean_params_usage; \ + items_add((argitem){util_strdup(&argv[1][0]), argtype}); \ + } \ + } while (0) + + case 'c': param_argument(0); break; /* compile */ + case 'a': param_argument(1); break; /* assemble */ + case 'i': param_argument(2); break; /* includes */ + #undef parm_argument + default: + if (!strncmp(&argv[1][1], "debug" , 5)) { opts_debug = true; break; } + if (!strncmp(&argv[1][1], "memchk", 6)) { opts_memchk = true; break; } + if (!strncmp(&argv[1][1], "help", 4)) { + return usage(app); + break; + } + /* compiler type selection */ + if (!strncmp(&argv[1][1], "std=qcc" , 7 )) { opts_compiler = COMPILER_QCC; break; } + if (!strncmp(&argv[1][1], "std=fteqcc", 10)) { opts_compiler = COMPILER_FTEQCC; break; } + if (!strncmp(&argv[1][1], "std=qccx", 8 )) { opts_compiler = COMPILER_QCCX; break; } + if (!strncmp(&argv[1][1], "std=gmqcc", 9 )) { opts_compiler = COMPILER_GMQCC; break; } + if (!strncmp(&argv[1][1], "std=", 4 )) { + printf("invalid std selection, supported types:\n" + " -std=qcc -- original QuakeC\n" + " -std=ftqecc -- fteqcc QuakeC\n" + " -std=qccx -- qccx QuakeC\n" + " -std=gmqcc -- this compiler QuakeC (default selection)\n"); + return 0; + } + + /* code specific switches */ + if (!strcmp(&argv[1][1], "fdarkplaces-stringtablebug")) { + opts_darkplaces_stringtablebug = true; + break; + } + if (!strcmp(&argv[1][1], "fomit-nullcode")) { + opts_omit_nullcode = true; + break; + } + return usage(app); + + } + ++argv; + --argc; + } + + /* + * options could depend on another option, this is where option + * validity checking like that would take place. + */ + if (opts_memchk && !opts_debug) + printf("Warning: cannot enable -memchk, without -debug.\n"); + + util_debug("COM", "starting ...\n"); + /* multi file multi path compilation system */ + for (; itr < items_elements; itr++) { + switch (items_data[itr].type) { + case 0: + lex_init (items_data[itr].name, &lex); + lex_parse(lex); + lex_close(lex); + break; + case 1: + asm_init (items_data[itr].name, &fpp); + asm_parse(fpp); + asm_close(fpp); + break; + } + } + + util_debug("COM", "cleaning ...\n"); + /* clean list */ + for (itr = 0; itr < items_elements; itr++) + mem_d(items_data[itr].name); + mem_d(items_data); + + util_meminfo(); + return 0; +clean_params_usage: + for (itr = 0; itr < items_elements; itr++) + mem_d(items_data[itr].name); + mem_d(items_data); + return usage(app); }