mirror of https://github.com/inolen/redream.git
read / write options to config file
This commit is contained in:
parent
20dd75aa67
commit
0dab5967d5
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
15
src/main.c
15
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue