read / write options to config file

This commit is contained in:
Anthony Pesch 2016-06-18 01:29:15 -07:00
parent 20dd75aa67
commit 0dab5967d5
5 changed files with 125 additions and 77 deletions

View File

@ -1,3 +1,5 @@
#include <ini.h>
#include <stdlib.h>
#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));
}
}

View File

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

View File

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

View File

@ -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 R = struct ir_valueInfo<VALUE_V>, \
typename A0 = struct ir_valueInfo<VALUE_V>, \
typename A1 = struct ir_valueInfo<VALUE_V>> \
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<VALUE_##r>, struct ir_valueInfo<VALUE_##a0>, \
struct ir_valueInfo<VALUE_##a1>>; \
} \
#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<VALUE_##r>, \
struct ir_valueInfo<VALUE_##a0>, \
struct ir_valueInfo<VALUE_##a1>>; \
} \
} cpp_##op##_##r##_##a0##_##a1##_init
// common helpers for fold functions

View File

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