From: Dale Weiler Date: Tue, 18 Dec 2012 04:57:17 +0000 (+0000) Subject: Cleanups of compiler option configuration. Added ini/cfg parser system as well. X-Git-Tag: 0.1.9~73 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=4b3e2571af85da0990d88434e0cf2613e1baf734;p=xonotic%2Fgmqcc.git Cleanups of compiler option configuration. Added ini/cfg parser system as well. --- diff --git a/Makefile b/Makefile index 482f132..6ebf7b4 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,8 @@ OBJ = \ ast.o \ ir.o \ con.o \ - ftepp.o + ftepp.o \ + opts.o OBJ_T = test.o util.o con.o OBJ_C = main.o lexer.o parser.o diff --git a/ast.c b/ast.c index d997bae..7c5d0b1 100644 --- a/ast.c +++ b/ast.c @@ -1417,14 +1417,14 @@ bool ast_generate_accessors(ast_value *self, ir_builder *ir) } } - options_set(opts.warn, WARN_USED_UNINITIALIZED, false); + opts_set(opts.warn, WARN_USED_UNINITIALIZED, false); if (self->setter) { if (!ast_global_codegen (self->setter, ir, false) || !ast_function_codegen(self->setter->constval.vfunc, ir) || !ir_function_finalize(self->setter->constval.vfunc->ir_func)) { compile_error(ast_ctx(self), "internal error: failed to generate setter for `%s`", self->name); - options_set(opts.warn, WARN_USED_UNINITIALIZED, warn); + opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn); return false; } } @@ -1434,14 +1434,14 @@ bool ast_generate_accessors(ast_value *self, ir_builder *ir) !ir_function_finalize(self->getter->constval.vfunc->ir_func)) { compile_error(ast_ctx(self), "internal error: failed to generate getter for `%s`", self->name); - options_set(opts.warn, WARN_USED_UNINITIALIZED, warn); + opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn); return false; } } for (i = 0; i < self->expression.count; ++i) { vec_free(self->ir_values[i]->life); } - options_set(opts.warn, WARN_USED_UNINITIALIZED, warn); + opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn); return true; } diff --git a/gmqcc.h b/gmqcc.h index 02a8c89..5f39634 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -623,10 +623,10 @@ int con_out (const char *, ...); extern size_t compile_errors; extern size_t compile_warnings; -void /********/ compile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...); -bool GMQCC_WARN compile_warning(lex_ctx ctx, int warntype, const char *fmt, ...); -void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list); -bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list); +void /********/ compile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...); +void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap); +bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...); +bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap); /*===================================================================*/ /*========================= assembler.c =============================*/ @@ -867,14 +867,22 @@ typedef uint32_t longbit; #define LONGBIT(bit) (bit) #endif -/* Used to store the list of flags with names */ +/*===================================================================*/ +/*============================= opts.c ==============================*/ +/*===================================================================*/ typedef struct { const char *name; longbit bit; } opts_flag_def; -/*===================================================================*/ -/* list of -f flags, like -fdarkplaces-string-table-bug */ +bool opts_setflag (const char *, bool); +bool opts_setwarn (const char *, bool); +bool opts_setoptim(const char *, bool); + +void opts_init (const char *, int, size_t); +void opts_set (uint32_t *, size_t, bool); +void opts_setoptimlevel(unsigned int); + enum { # define GMQCC_TYPE_FLAGS # define GMQCC_DEFINE_FLAG(X) X, @@ -919,21 +927,21 @@ static const unsigned int opts_opt_oflag[] = { # include "opts.def" 0 }; -extern unsigned int optimization_count[COUNT_OPTIMIZATIONS]; +extern unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; /* other options: */ -enum { +typedef enum { COMPILER_QCC, /* circa QuakeC */ COMPILER_FTEQCC, /* fteqcc QuakeC */ COMPILER_QCCX, /* qccx QuakeC */ COMPILER_GMQCC /* this QuakeC */ -}; +} opts_std_t; typedef struct { uint32_t O; /* -Ox */ const char *output; /* -o file */ bool g; /* -g */ - int standard; /* -std= */ + opts_std_t standard; /* -std= */ bool debug; /* -debug */ bool memchk; /* -memchk */ bool dumpfin; /* -dumpfin */ @@ -947,15 +955,13 @@ typedef struct { uint32_t flags [1 + (COUNT_FLAGS / 32)]; uint32_t warn [1 + (COUNT_WARNINGS / 32)]; uint32_t optimization[1 + (COUNT_OPTIMIZATIONS / 32)]; -} cmd_options; +} opts_cmd_t; -extern cmd_options opts; +extern opts_cmd_t opts; /*===================================================================*/ #define OPTS_FLAG(i) (!! (opts.flags [(i)/32] & (1<< ((i)%32)))) #define OPTS_WARN(i) (!! (opts.warn [(i)/32] & (1<< ((i)%32)))) #define OPTS_OPTIMIZATION(i) (!! (opts.optimization[(i)/32] & (1<< ((i)%32)))) -void options_set(uint32_t *flags, size_t idx, bool on); - #endif diff --git a/ir.c b/ir.c index 3467d32..2cffb9d 100644 --- a/ir.c +++ b/ir.c @@ -209,11 +209,11 @@ static void irerror(lex_ctx ctx, const char *msg, ...) static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...) { bool r; - va_list ap; - va_start(ap, fmt); - r = vcompile_warning(ctx, warntype, fmt, ap); - va_end(ap); - return r; + va_list ap; + va_start(ap, fmt); + r = vcompile_warning(ctx, warntype, fmt, ap); + va_end(ap); + return r; } /*********************************************************************** @@ -575,7 +575,7 @@ bool ir_function_pass_peephole(ir_function *self) if (store->_ops[1] != value) continue; - ++optimization_count[OPTIM_PEEPHOLE]; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; (void)!ir_instr_op(oper, 0, store->_ops[0], true); vec_remove(block->instr, i, 1); @@ -610,7 +610,7 @@ bool ir_function_pass_peephole(ir_function *self) } /* count */ - ++optimization_count[OPTIM_PEEPHOLE]; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; /* change operand */ (void)!ir_instr_op(inst, 0, inot->_ops[1], false); /* remove NOT */ @@ -678,7 +678,7 @@ bool ir_function_pass_tailcall(ir_function *self) ret->_ops[0] == store->_ops[0] && store->_ops[1] == call->_ops[0]) { - ++optimization_count[OPTIM_PEEPHOLE]; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; call->_ops[0] = store->_ops[0]; vec_remove(block->instr, vec_size(block->instr) - 2, 1); ir_instr_delete(store); @@ -700,7 +700,7 @@ bool ir_function_pass_tailcall(ir_function *self) if (ret->_ops[0] && call->_ops[0] != ret->_ops[0]) continue; - ++optimization_count[OPTIM_TAIL_RECURSION]; + ++opts_optimizationcount[OPTIM_TAIL_RECURSION]; vec_shrinkby(block->instr, 2); block->final = false; /* open it back up */ @@ -2897,7 +2897,7 @@ tailcall: if (stmt.o2.u1 == stmt.o1.u1 && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) { - ++optimization_count[OPTIM_PEEPHOLE]; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; continue; } } diff --git a/main.c b/main.c index 4032264..6ae0091 100644 --- a/main.c +++ b/main.c @@ -24,15 +24,12 @@ #include "gmqcc.h" #include "lexer.h" -/* counter increased in ir.c */ -unsigned int optimization_count[COUNT_OPTIMIZATIONS]; -static bool opts_output_wasset = false; - -cmd_options opts; +/* TODO: cleanup this whole file .. it's a fuckign mess */ /* set by the standard */ const oper_info *operators = NULL; size_t operator_count = 0; +static bool opts_output_wasset = false; typedef struct { char *filename; int type; } argitem; typedef struct { char *name; char *value; } ppitem; @@ -84,38 +81,7 @@ static int usage() { return -1; } -static bool options_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) { - size_t i; - - for (i = 0; i < listsize; ++i) { - if (!strcmp(name, list[i].name)) { - longbit lb = list[i].bit; -#if 0 - if (on) - flags[lb.idx] |= (1<<(lb.bit)); - else - flags[lb.idx] &= ~(1<<(lb.bit)); -#else - if (on) - flags[0] |= (1<= opts_opt_oflag[i]); -} - static bool options_parse(int argc, char **argv) { bool argend = false; size_t itr; @@ -205,26 +148,34 @@ static bool options_parse(int argc, char **argv) { --argc; if (argv[0][0] == '-') { - /* All gcc-type long options */ + /* All gcc-type long options */ if (options_long_gcc("std", &argc, &argv, &argarg)) { - if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default")) { - options_set(opts.flags, ADJUST_VECTOR_FIELDS, true); + if (!strcmp(argarg, "gmqcc") || !strcmp(argarg, "default")) { + + opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true); opts.standard = COMPILER_GMQCC; + } else if (!strcmp(argarg, "qcc")) { - options_set(opts.flags, ADJUST_VECTOR_FIELDS, false); - options_set(opts.flags, ASSIGN_FUNCTION_TYPES, true); + + opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false); + opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true); opts.standard = COMPILER_QCC; + } else if (!strcmp(argarg, "fte") || !strcmp(argarg, "fteqcc")) { - options_set(opts.flags, FTEPP, true); - options_set(opts.flags, TRANSLATABLE_STRINGS, true); - options_set(opts.flags, ADJUST_VECTOR_FIELDS, false); - options_set(opts.flags, ASSIGN_FUNCTION_TYPES, true); - options_set(opts.warn, WARN_TERNARY_PRECEDENCE, true); - options_set(opts.flags, CORRECT_TERNARY, false); + + opts_set(opts.flags, FTEPP, true); + opts_set(opts.flags, TRANSLATABLE_STRINGS, true); + opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false); + opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true); + opts_set(opts.warn, WARN_TERNARY_PRECEDENCE, true); + opts_set(opts.flags, CORRECT_TERNARY, false); opts.standard = COMPILER_FTEQCC; + } else if (!strcmp(argarg, "qccx")) { - options_set(opts.flags, ADJUST_VECTOR_FIELDS, false); + + opts_set(opts.flags, ADJUST_VECTOR_FIELDS, false); opts.standard = COMPILER_QCCX; + } else { con_out("Unknown standard: %s\n", argarg); return false; @@ -232,7 +183,7 @@ static bool options_parse(int argc, char **argv) { continue; } if (options_long_gcc("force-crc", &argc, &argv, &argarg)) { - opts.forcecrc = true; + opts.forcecrc = true; opts.forced_crc = strtol(argarg, NULL, 0); continue; } @@ -308,7 +259,7 @@ static bool options_parse(int argc, char **argv) { /* debug turns on -flno */ case 'g': - options_setflag("LNO", true); + opts_setflag("LNO", true); break; case 'D': @@ -340,12 +291,12 @@ static bool options_parse(int argc, char **argv) { exit(0); } else if (!strncmp(argv[0]+2, "NO_", 3)) { - if (!options_setflag(argv[0]+5, false)) { + if (!opts_setflag(argv[0]+5, false)) { con_out("unknown flag: %s\n", argv[0]+2); return false; } } - else if (!options_setflag(argv[0]+2, true)) { + else if (!opts_setflag(argv[0]+2, true)) { con_out("unknown flag: %s\n", argv[0]+2); return false; } @@ -379,12 +330,12 @@ static bool options_parse(int argc, char **argv) { break; } if (!strncmp(argv[0]+2, "NO_", 3)) { - if (!options_setwarn(argv[0]+5, false)) { + if (!opts_setwarn(argv[0]+5, false)) { con_out("unknown warning: %s\n", argv[0]+2); return false; } } - else if (!options_setwarn(argv[0]+2, true)) { + else if (!opts_setwarn(argv[0]+2, true)) { con_out("unknown warning: %s\n", argv[0]+2); return false; } @@ -397,7 +348,7 @@ static bool options_parse(int argc, char **argv) { } if (isdigit(argarg[0])) { opts.O = atoi(argarg); - set_optimizations(opts.O); + opts_setoptimlevel(opts.O); } else { util_strtocmd(argarg, argarg, strlen(argarg)+1); if (!strcmp(argarg, "HELP")) { @@ -409,15 +360,15 @@ static bool options_parse(int argc, char **argv) { exit(0); } else if (!strcmp(argarg, "ALL")) - set_optimizations(opts.O = 9999); + opts_setoptimlevel(opts.O = 9999); else if (!strncmp(argarg, "NO_", 3)) { - if (!options_setoptim(argarg+3, false)) { + if (!opts_setoptim(argarg+3, false)) { con_out("unknown optimization: %s\n", argarg+3); return false; } } else { - if (!options_setoptim(argarg, true)) { + if (!opts_setoptim(argarg, true)) { con_out("unknown optimization: %s\n", argarg); return false; } @@ -517,46 +468,15 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) { int main(int argc, char **argv) { size_t itr; - int retval = 0; - bool opts_output_free = false; - bool operators_free = false; - bool progs_src = false; - FILE *outfile = NULL; - - memset(&opts, 0, sizeof(opts)); - opts.output = "progs.dat"; - opts.standard = COMPILER_GMQCC; - opts.max_array_size = (1024<<3); + int retval = 0; + bool opts_output_free = false; + bool operators_free = false; + bool progs_src = false; + FILE *outfile = NULL; app_name = argv[0]; - con_init(); - - /* default options / warn flags */ - options_set(opts.warn, WARN_UNKNOWN_CONTROL_SEQUENCE, true); - options_set(opts.warn, WARN_EXTENSIONS, true); - options_set(opts.warn, WARN_FIELD_REDECLARED, true); - options_set(opts.warn, WARN_TOO_FEW_PARAMETERS, true); - options_set(opts.warn, WARN_MISSING_RETURN_VALUES, true); - options_set(opts.warn, WARN_USED_UNINITIALIZED, true); - options_set(opts.warn, WARN_LOCAL_CONSTANTS, true); - options_set(opts.warn, WARN_VOID_VARIABLES, true); - options_set(opts.warn, WARN_IMPLICIT_FUNCTION_POINTER, true); - options_set(opts.warn, WARN_VARIADIC_FUNCTION, true); - options_set(opts.warn, WARN_FRAME_MACROS, true); - options_set(opts.warn, WARN_UNUSED_VARIABLE, true); - options_set(opts.warn, WARN_EFFECTLESS_STATEMENT, true); - options_set(opts.warn, WARN_END_SYS_FIELDS, true); - options_set(opts.warn, WARN_ASSIGN_FUNCTION_TYPES, true); - options_set(opts.warn, WARN_PREPROCESSOR, true); - options_set(opts.warn, WARN_MULTIFILE_IF, true); - options_set(opts.warn, WARN_DOUBLE_DECLARATION, true); - options_set(opts.warn, WARN_CONST_VAR, true); - options_set(opts.warn, WARN_MULTIBYTE_CHARACTER, true); - options_set(opts.warn, WARN_UNKNOWN_PRAGMAS, true); - - options_set(opts.flags, ADJUST_VECTOR_FIELDS, true); - options_set(opts.flags, FTEPP, false); - options_set(opts.flags, CORRECT_TERNARY, true); + con_init (); + opts_init("progs.dat", COMPILER_GMQCC, (1024 << 3)); if (!options_parse(argc, argv)) { return usage(); @@ -564,13 +484,13 @@ int main(int argc, char **argv) { /* the standard decides which set of operators to use */ if (opts.standard == COMPILER_GMQCC) { - operators = c_operators; + operators = c_operators; operator_count = c_operator_count; } else if (opts.standard == COMPILER_FTEQCC) { - operators = fte_operators; + operators = fte_operators; operator_count = fte_operator_count; } else { - operators = qcc_operators; + operators = qcc_operators; operator_count = qcc_operator_count; } @@ -595,15 +515,14 @@ int main(int argc, char **argv) { } if (opts.dump) { - for (itr = 0; itr < COUNT_FLAGS; ++itr) { - con_out("Flag %s = %i\n", opts_flag_list[itr].name, OPTS_FLAG(itr)); - } - for (itr = 0; itr < COUNT_WARNINGS; ++itr) { + for (itr = 0; itr < COUNT_FLAGS; ++itr) + con_out("Flag %s = %i\n", opts_flag_list[itr].name, OPTS_FLAG(itr)); + for (itr = 0; itr < COUNT_WARNINGS; ++itr) con_out("Warning %s = %i\n", opts_warn_list[itr].name, OPTS_WARN(itr)); - } - con_out("output = %s\n", opts.output); - con_out("optimization level = %i\n", (int)opts.O); - con_out("standard = %i\n", opts.standard); + + con_out("output = %s\n", opts.output); + con_out("optimization level = %d\n", opts.O); + con_out("standard = %i\n", opts.standard); } if (opts.pp_only) { @@ -758,11 +677,10 @@ srcdone: } /* stuff */ - if (!opts.pp_only) { for (itr = 0; itr < COUNT_OPTIMIZATIONS; ++itr) { - if (optimization_count[itr]) { - con_out("%s: %u\n", opts_opt_list[itr].name, (unsigned int)optimization_count[itr]); + if (opts_optimizationcount[itr]) { + con_out("%s: %u\n", opts_opt_list[itr].name, (unsigned int)opts_optimizationcount[itr]); } } } diff --git a/opts.c b/opts.c new file mode 100644 index 0000000..93433b6 --- /dev/null +++ b/opts.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2012 + * Wolfgang Bumiller + * 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 + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "gmqcc.h" +unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; +opts_cmd_t opts; /* command lien options */ + +static void opts_ini_init(); +static void opts_setdefault() { + memset(&opts, 0, sizeof(opts_cmd_t)); + + /* warnings */ + opts_set(opts.warn, WARN_UNKNOWN_CONTROL_SEQUENCE, true); + opts_set(opts.warn, WARN_EXTENSIONS, true); + opts_set(opts.warn, WARN_FIELD_REDECLARED, true); + opts_set(opts.warn, WARN_TOO_FEW_PARAMETERS, true); + opts_set(opts.warn, WARN_MISSING_RETURN_VALUES, true); + opts_set(opts.warn, WARN_USED_UNINITIALIZED, true); + opts_set(opts.warn, WARN_LOCAL_CONSTANTS, true); + opts_set(opts.warn, WARN_VOID_VARIABLES, true); + opts_set(opts.warn, WARN_IMPLICIT_FUNCTION_POINTER, true); + opts_set(opts.warn, WARN_VARIADIC_FUNCTION, true); + opts_set(opts.warn, WARN_FRAME_MACROS, true); + opts_set(opts.warn, WARN_UNUSED_VARIABLE, true); + opts_set(opts.warn, WARN_EFFECTLESS_STATEMENT, true); + opts_set(opts.warn, WARN_END_SYS_FIELDS, true); + opts_set(opts.warn, WARN_ASSIGN_FUNCTION_TYPES, true); + opts_set(opts.warn, WARN_PREPROCESSOR, true); + opts_set(opts.warn, WARN_MULTIFILE_IF, true); + opts_set(opts.warn, WARN_DOUBLE_DECLARATION, true); + opts_set(opts.warn, WARN_CONST_VAR, true); + opts_set(opts.warn, WARN_MULTIBYTE_CHARACTER, true); + opts_set(opts.warn, WARN_UNKNOWN_PRAGMAS, true); + /* flags */ + opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true); + opts_set(opts.flags, FTEPP, false); + opts_set(opts.flags, CORRECT_TERNARY, true); +} + +void opts_init(const char *output, int standard, size_t arraysize) { + opts_setdefault(); + + opts.output = output; + opts.standard = standard; + opts.max_array_size = arraysize; + + opts_ini_init(); +} + +static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) { + size_t i; + + for (i = 0; i < listsize; ++i) { + if (!strcmp(name, list[i].name)) { + longbit lb = list[i].bit; +#if 0 + if (on) + flags[lb.idx] |= (1<<(lb.bit)); + else + flags[lb.idx] &= ~(1<<(lb.bit)); +#else + if (on) + flags[0] |= (1<= opts_opt_oflag[i]); +} + +/* + * Standard configuration parser and subsystem. Yes, optionally you may + * create ini files or cfg (the driver accepts both) for a project opposed + * to supplying just a progs.src (since you also may need to supply command + * line arguments or set the options of the compiler) [which cannot be done + * from a progs.src. + */ +static char *opts_ini_rstrip(char *s) { + char *p = s + strlen(s); + while(p > s && isspace(*--p)) + *p = '\0'; + return s; +} + +static char *opts_ini_lskip(const char *s) { + while (*s && isspace(*s)) + s++; + return (char*)s; +} + +static char *opts_ini_next(const char *s, char c) { + bool last = false; + while (*s && *s != c && !(last && *s == ';')) + last = !!isspace(*s), s++; + + return (char*)s; +} + +static size_t opts_ini_parse ( + FILE *filehandle, + char *(*loadhandle)(const char *, const char *, const char *), + char **errorhandle +) { + size_t linesize; + size_t lineno = 1; + size_t error = 0; + char *line = NULL; + char section_data[2048] = ""; + char oldname_data[2048] = ""; + + /* parsing and reading variables */ + char *parse_beg; + char *parse_end; + char *read_name; + char *read_value; + + while (util_getline(&line, &linesize, filehandle) != EOF) { + parse_beg = line; + + /* handle BOM */ + if (lineno == 1 && ( + (unsigned char)parse_beg[0] == 0xEF && + (unsigned char)parse_beg[1] == 0xBB && + (unsigned char)parse_beg[2] == 0xBF + ) + ) { + parse_beg ++; /* 0xEF */ + parse_beg ++; /* 0xBB */ + parse_beg ++; /* 0xBF */ + } + + if (*(parse_beg = opts_ini_lskip(opts_ini_rstrip(parse_beg))) == ';' || *parse_beg == '#') { + /* ignore '#' is a perl extension */ + } else if (*parse_beg == '[') { + /* section found */ + if (*(parse_end = opts_ini_next(parse_beg + 1, ']')) == ']') { + * parse_end = '\0'; /* terminate bro */ + strncpy(section_data, parse_beg + 1, sizeof(section_data)); + section_data[sizeof(section_data) - 1] = '\0'; + *oldname_data = '\0'; + } else if (!error) { + /* otherwise set error to the current line number */ + error = lineno; + } + } else if (*parse_beg && *parse_beg != ';') { + /* not a comment, must be a name value pair :) */ + if (*(parse_end = opts_ini_next(parse_beg, '=')) != '=') + parse_end = opts_ini_next(parse_beg, ':'); + + if (*parse_end == '=' || *parse_end == ':') { + *parse_end = '\0'; /* terminate bro */ + read_name = opts_ini_rstrip(parse_beg); + read_value = opts_ini_lskip(parse_end + 1); + if (*(parse_end = opts_ini_next(read_value, '\0')) == ';') + * parse_end = '\0'; + opts_ini_rstrip(read_value); + + /* valid name value pair, lets call down to handler */ + strncpy(oldname_data, read_name, sizeof(oldname_data)); + oldname_data[sizeof(oldname_data) - 1] ='\0'; + + if ((*errorhandle = loadhandle(section_data, read_name, read_value)) && !error) + error = lineno; + } else if (!error) { + /* otherwise set error to the current line number */ + error = lineno; + } + } + lineno++; + } + mem_d(line); + return error; +} + +/* + * returns true/false for a char that contains ("true" or "false" or numeric 0/1) + */ +static bool opts_ini_bool(const char *value) { + if (!strcmp(value, "true")) return true; + if (!strcmp(value, "false")) return false; + return !!atoi(value); +} + +static char *opts_ini_load(const char *section, const char *name, const char *value) { + char *error = NULL; + bool found = false; + + /* + * undef all of these because they may still be defined like in my + * case they where. + */ + #undef GMQCC_TYPE_FLAGS + #undef GMQCC_TYPE_OPTIMIZATIONS + #undef GMQCC_TYPE_WARNS + + /* flags */ + #define GMQCC_TYPE_FLAGS + #define GMQCC_DEFINE_FLAG(X) \ + if (!strcmp(section, "flags") && !strcmp(name, #X)) { \ + opts_set(opts.flags, X, opts_ini_bool(value)); \ + found = true; \ + } + #include "opts.def" + + /* warnings */ + #define GMQCC_TYPE_WARNS + #define GMQCC_DEFINE_FLAG(X) \ + if (!strcmp(section, "warnings") && !strcmp(name, #X)) { \ + opts_set(opts.warn, WARN_##X, opts_ini_bool(value)); \ + found = true; \ + } + #include "opts.def" + + /* optimizations */ + #define GMQCC_TYPE_OPTIMIZATIONS + #define GMQCC_DEFINE_FLAG(X,Y) \ + if (!strcmp(section, "optimizations") && !strcmp(name, #X)) { \ + opts_set(opts.optimization, OPTIM_##X, opts_ini_bool(value)); \ + found = true; \ + } + #include "opts.def" + + /* nothing was found ever! */ + if (!found) { + if (strcmp(section, "flags") && + strcmp(section, "warnings") && + strcmp(section, "optimizations")) + { + vec_upload(error, "invalid section `", 17); + vec_upload(error, section, strlen(section)); + vec_push (error, '`'); + vec_push (error, '\0'); + } else { + vec_upload(error, "invalid variable `", 18); + vec_upload(error, name, strlen(name)); + vec_push (error, '`'); + vec_upload(error, " in section: `", 14); + vec_upload(error, section, strlen(section)); + vec_push (error, '`'); + vec_push (error, '\0'); + } + } + return error; +} + +/* + * Actual loading subsystem, this finds the ini or cfg file, and properly + * loads it and executes it to set compiler options. + */ +static void opts_ini_init() { + /* + * Possible matches are: + * gmqcc.ini + * gmqcc.cfg + */ + + char *file; + char *error; + size_t line; + FILE *ini; + + /* try ini */ + if (!(ini = fopen((file = "gmqcc.ini"), "r"))) + /* try cfg */ + if (!(ini = fopen((file = "gmqcc.cfg"), "r"))) + return; + + con_out("found ini file `%s`\n", file); + + if ((line = opts_ini_parse(ini, &opts_ini_load, &error)) != 0) { + /* there was a parse error with the ini file */ + con_printmsg(LVL_ERROR, file, line, "error", error); + vec_free(error); + } + + fclose(ini); +}