diff --git a/src/core/option.c b/src/core/option.c index b24640ce..14d4b342 100644 --- a/src/core/option.c +++ b/src/core/option.c @@ -1,3 +1,5 @@ +#include +#include #include "core/log.h" #include "core/math.h" #include "core/option.h" @@ -5,7 +7,7 @@ static struct list s_options; -static struct option *option_find(const char *name) { +static struct option *options_find(const char *name) { list_for_each_entry(opt, &s_options, struct option, it) { if (!strcmp(opt->name, name)) { return opt; @@ -15,15 +17,47 @@ static struct option *option_find(const char *name) { return NULL; } -void option_register(struct option *option) { +static void options_parse_value(struct option *opt, const char *value) { + switch (opt->type) { + case OPT_BOOL: + *(bool *)opt->storage = strcmp(value, "false") && strcmp(value, "0"); + break; + + case OPT_INT: + *(int *)opt->storage = atoi(value); + break; + + case OPT_STRING: + strncpy((char *)opt->storage, value, MAX_OPTION_LENGTH); + break; + } +} + +static const char *options_format_value(struct option *opt) { + static char value[MAX_OPTION_LENGTH]; + + switch (opt->type) { + case OPT_BOOL: + return *(bool *)opt->storage ? "true" : "false"; + + case OPT_INT: + snprintf(value, sizeof(value), "%d", *(int *)opt->storage); + return value; + + case OPT_STRING: + return (char *)opt->storage; + } +} + +void options_register(struct option *option) { list_add(&s_options, &option->it); } -void option_unregister(struct option *option) { +void options_unregister(struct option *option) { list_remove(&s_options, &option->it); } -void option_parse(int *argc, char ***argv) { +void options_parse(int *argc, char ***argv) { int end = *argc; for (int i = 1; i < end;) { @@ -54,22 +88,10 @@ void option_parse(int *argc, char ***argv) { } // lookup the option and assign the parsed value to it - struct option *opt = option_find(arg); + struct option *opt = options_find(arg); if (opt) { - switch (opt->type) { - case OPT_BOOL: - *(bool *)opt->storage = strcmp(value, "false") && strcmp(value, "0"); - break; - - case OPT_INT: - *(int *)opt->storage = atoi(value); - break; - - case OPT_STRING: - strcpy((char *)opt->storage, value); - break; - } + options_parse_value(opt, value); } i++; @@ -79,7 +101,38 @@ void option_parse(int *argc, char ***argv) { *argv += end - 1; } -void option_print_help() { +static int options_ini_handler(void *user, const char *section, + const char *name, const char *value) { + struct option *opt = options_find(name); + + if (opt) { + options_parse_value(opt, value); + } + + return 0; +} + +bool options_read(const char *filename) { + return ini_parse(filename, options_ini_handler, NULL) >= 0; +} + +bool options_write(const char *filename) { + FILE *output = fopen(filename, "wt"); + + if (!output) { + return false; + } + + list_for_each_entry(opt, &s_options, struct option, it) { + fprintf(output, "%s: %s\n", opt->name, options_format_value(opt)); + } + + fclose(output); + + return true; +} + +void options_print_help() { int max_name_width = 0; int max_desc_width = 0; @@ -92,22 +145,7 @@ void option_print_help() { } list_for_each_entry(opt, &s_options, struct option, it) { - switch (opt->type) { - case OPT_BOOL: - LOG_INFO("--%-*s %-*s [default %s]", max_name_width, opt->name, - max_desc_width, opt->desc, - *(bool *)opt->storage ? "true" : "false"); - break; - - case OPT_INT: - LOG_INFO("--%-*s %-*s [default %s]", max_name_width, opt->name, - max_desc_width, opt->desc, *(int *)opt->storage); - break; - - case OPT_STRING: - LOG_INFO("--%-*s %-*s [default %s]", max_name_width, opt->name, - max_desc_width, opt->desc, (char *)opt->storage); - break; - } + LOG_INFO("--%-*s %-*s %s", max_name_width, opt->name, max_desc_width, + opt->desc, options_format_value(opt)); } } diff --git a/src/core/option.h b/src/core/option.h index f294404d..a3aad2b6 100644 --- a/src/core/option.h +++ b/src/core/option.h @@ -6,6 +6,8 @@ #include "core/constructor.h" #include "core/list.h" +static const int MAX_OPTION_LENGTH = 1024; + #define DECLARE_OPTION_BOOL(name) extern bool OPTION_##name; #define DEFINE_OPTION_BOOL(name, value, desc) \ @@ -14,10 +16,10 @@ OPT_BOOL, #name, desc, &OPTION_##name, {}}; \ CONSTRUCTOR(OPTION_REGISTER_##name) { \ *(bool *)(&OPTION_##name) = value; \ - option_register(&OPTION_T_##name); \ + options_register(&OPTION_T_##name); \ } \ DESTRUCTOR(OPTION_UNREGISTER_##name) { \ - option_unregister(&OPTION_T_##name); \ + options_unregister(&OPTION_T_##name); \ } #define DECLARE_OPTION_INT(name) extern int OPTION_##name; @@ -28,24 +30,25 @@ OPT_INT, #name, desc, &OPTION_##name, {}}; \ CONSTRUCTOR(OPTION_REGISTER_##name) { \ *(int *)(&OPTION_##name) = value; \ - option_register(&OPTION_T_##name); \ + options_register(&OPTION_T_##name); \ } \ DESTRUCTOR(OPTION_UNREGISTER_##name) { \ - option_unregister(&OPTION_T_##name); \ + options_unregister(&OPTION_T_##name); \ } -#define DECLARE_OPTION_STRING(name) extern char OPTION_##name[1024]; +#define DECLARE_OPTION_STRING(name) \ + extern char OPTION_##name[MAX_OPTION_LENGTH]; -#define DEFINE_OPTION_STRING(name, value, desc) \ - char OPTION_##name[1024]; \ - static struct option OPTION_T_##name = { \ - OPT_STRING, #name, desc, &OPTION_##name, {}}; \ - CONSTRUCTOR(OPTION_REGISTER_##name) { \ - strcpy((char *) & OPTION_##name, value); \ - option_register(&OPTION_T_##name); \ - } \ - DESTRUCTOR(OPTION_UNREGISTER_##name) { \ - option_unregister(&OPTION_T_##name); \ +#define DEFINE_OPTION_STRING(name, value, desc) \ + char OPTION_##name[MAX_OPTION_LENGTH]; \ + static struct option OPTION_T_##name = { \ + OPT_STRING, #name, desc, &OPTION_##name, {}}; \ + CONSTRUCTOR(OPTION_REGISTER_##name) { \ + strncpy(OPTION_##name, value, MAX_OPTION_LENGTH); \ + options_register(&OPTION_T_##name); \ + } \ + DESTRUCTOR(OPTION_UNREGISTER_##name) { \ + options_unregister(&OPTION_T_##name); \ } enum option_type { @@ -62,10 +65,13 @@ struct option { struct list_node it; }; -void option_register(struct option *option); -void option_unregister(struct option *option); +void options_register(struct option *option); +void options_unregister(struct option *option); -void option_parse(int *argc, char ***argv); -void option_print_help(); +void options_parse(int *argc, char ***argv); +bool options_read(const char *filename); +bool options_write(const char *filename); + +void options_print_help(); #endif diff --git a/src/emu/emulator.c b/src/emu/emulator.c index 7f17baad..ca5a635c 100644 --- a/src/emu/emulator.c +++ b/src/emu/emulator.c @@ -8,10 +8,8 @@ #include "ui/window.h" #include "sys/time.h" -DEFINE_OPTION_STRING(bios, "/Users/inolen/projects/dreamcast/dc_boot.bin", - "Path to BIOS"); -DEFINE_OPTION_STRING(flash, "/Users/inolen/projects/dreamcast/dc_flash.bin", - "Path to flash ROM"); +DEFINE_OPTION_STRING(bios, "dc_boot.bin", "Path to BIOS"); +DEFINE_OPTION_STRING(flash, "dc_flash.bin", "Path to flash ROM"); struct emu { struct window *window; diff --git a/src/jit/ir/passes/constant_propagation_pass.c b/src/jit/ir/passes/constant_propagation_pass.c index e8c44062..2150bb4c 100644 --- a/src/jit/ir/passes/constant_propagation_pass.c +++ b/src/jit/ir/passes/constant_propagation_pass.c @@ -25,25 +25,26 @@ int fold_masks[NUM_OPS]; // declare a templated callback for an IR operation. note, declaring a // callback does not actually register it. callbacks must be registered // for a particular signature with REGISTER_FOLD -#define FOLD(op, mask) \ - static struct _##op##_init { \ - _##op##_init() { \ - fold_masks[OP_##op] = mask; \ - } \ - } op##_init; \ +#define FOLD(op, mask) \ + static struct _##op##_init { \ + _##op##_init() { \ + fold_masks[OP_##op] = mask; \ + } \ + } op##_init; \ template , \ typename A0 = struct ir_valueInfo, \ typename A1 = struct ir_valueInfo> \ void Handle##op(struct ir *ir, Instr *instr) // registers a fold callback for the specified signature -#define REGISTER_FOLD(op, r, a0, a1) \ - static struct _cpp_##op##_##r##_##a0##_##a1##_init { \ - _cpp_##op##_##r##_##a0##_##a1##_init() { \ - fold_cbs[CALLBACK_IDX(OP_##op, VALUE_##r, VALUE_##a0, VALUE_##a1)] = \ - &Handle##op, struct ir_valueInfo, \ - struct ir_valueInfo>; \ - } \ +#define REGISTER_FOLD(op, r, a0, a1) \ + static struct _cpp_##op##_##r##_##a0##_##a1##_init { \ + _cpp_##op##_##r##_##a0##_##a1##_init() { \ + fold_cbs[CALLBACK_IDX(OP_##op, VALUE_##r, VALUE_##a0, VALUE_##a1)] = \ + &Handle##op, \ + struct ir_valueInfo, \ + struct ir_valueInfo>; \ + } \ } cpp_##op##_##r##_##a0##_##a1##_init // common helpers for fold functions diff --git a/src/main.c b/src/main.c index df84eb7a..a6522a45 100644 --- a/src/main.c +++ b/src/main.c @@ -38,15 +38,19 @@ int main(int argc, char **argv) { LOG_FATAL("Failed to create app directory %s", appdir); } - option_parse(&argc, &argv); + // load base options from config + char config[PATH_MAX] = {}; + snprintf(config, sizeof(config), "%s" PATH_SEPARATOR "config", appdir); + options_read(config); + + // override options from the command line + options_parse(&argc, &argv); if (OPTION_help) { - option_print_help(); + options_print_help(); return EXIT_SUCCESS; } - // InitFlags(&argc, &argv); - if (!exception_handler_install()) { LOG_WARNING("Failed to initialize exception handler"); return EXIT_FAILURE; @@ -73,7 +77,8 @@ int main(int argc, char **argv) { exception_handler_uninstall(); - // ShutdownFlags(); + // persist options for next run + options_write(config); return EXIT_SUCCESS; }