Cleanups of compiler option configuration. Added ini/cfg parser system as well.

This commit is contained in:
Dale Weiler 2012-12-18 04:57:17 +00:00
parent 0befe5da1c
commit 4b3e2571af
6 changed files with 418 additions and 164 deletions

View file

@ -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

8
ast.c
View file

@ -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;
}

36
gmqcc.h
View file

@ -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

20
ir.c
View file

@ -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;
}
}

186
main.c
View file

@ -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<<lb);
else
flags[0] &= ~(1<<(lb));
#endif
return true;
}
}
return false;
}
static bool options_setflag(const char *name, bool on) {
return options_setflag_all(name, on, opts.flags, opts_flag_list, COUNT_FLAGS);
}
static bool options_setwarn(const char *name, bool on) {
return options_setflag_all(name, on, opts.warn, opts_warn_list, COUNT_WARNINGS);
}
static bool options_setoptim(const char *name, bool on) {
return options_setflag_all(name, on, opts.optimization, opts_opt_list, COUNT_OPTIMIZATIONS);
}
/* command line parsing */
static bool options_witharg(int *argc_, char ***argv_, char **out) {
int argc = *argc_;
char **argv = *argv_;
@ -166,29 +132,6 @@ static bool options_long_gcc(const char *optname, int *argc_, char ***argv_, cha
return options_long_witharg_all(optname, argc_, argv_, out, 1, false);
}
void options_set(uint32_t *flags, size_t idx, bool on)
{
longbit lb = LONGBIT(idx);
#if 0
if (on)
flags[lb.idx] |= (1<<(lb.bit));
else
flags[lb.idx] &= ~(1<<(lb.bit));
#else
if (on)
flags[0] |= (1<<(lb));
else
flags[0] &= ~(1<<(lb));
#endif
}
static void set_optimizations(unsigned int level)
{
size_t i;
for (i = 0; i < COUNT_OPTIMIZATIONS; ++i)
options_set(opts.optimization, i, level >= 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]);
}
}
}

329
opts.c Normal file
View file

@ -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<<lb);
else
flags[0] &= ~(1<<(lb));
#endif
return true;
}
}
return false;
}
bool opts_setflag (const char *name, bool on) {
return opts_setflag_all(name, on, opts.flags, opts_flag_list, COUNT_FLAGS);
}
bool opts_setwarn (const char *name, bool on) {
return opts_setflag_all(name, on, opts.warn, opts_warn_list, COUNT_WARNINGS);
}
bool opts_setoptim(const char *name, bool on) {
return opts_setflag_all(name, on, opts.optimization, opts_opt_list, COUNT_OPTIMIZATIONS);
}
void opts_set(uint32_t *flags, size_t idx, bool on) {
longbit lb = LONGBIT(idx);
#if 0
if (on)
flags[lb.idx] |= (1<<(lb.bit));
else
flags[lb.idx] &= ~(1<<(lb.bit));
#else
if (on)
flags[0] |= (1<<(lb));
else
flags[0] &= ~(1<<(lb));
#endif
}
void opts_setoptimlevel(unsigned int level) {
size_t i;
for (i = 0; i < COUNT_OPTIMIZATIONS; ++i)
opts_set(opts.optimization, i, level >= 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);
}