From 7ff8ef94c05ae6386463b63f3ba25add52340d8b Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sat, 12 Mar 2022 17:29:26 -0800 Subject: til_settings: always describe relevant settings The existing iterative *_setup() interface only described settings not found, quietly accepting usable settings already present in the til_settings_t. This worked fine for the existing interactive text setup thing, but it's especially problematic for providing a GUI setup frontend. This commit makes it so the *_setup() methods always describe undescribed settings they recognize, leaving the setup frontend loop calling into the *_setup() methods to both apply the description validation if wanted and actually tie the description to respective setting returned by the _setup() methods as being related to the returned description. A new helper called til_settings_get_and_describe_value() has been introduced primarily for use of module setup methods to simplify this nonsense, replacing the til_settings_get_value() calls and surrounding logic, but retaining the til_setting_desc_t definitions largely verbatim. This also results in discarding of some ad-hoc til_setting_desc_check() calls, now that there's a centralized place where settings become "described" (setup_interactively in the case of rototiller). Now a GUI frontend (like glimmer) would just provide its own setup_interactively() equivalent for constructing its widgets for a given *_setup() method's chain of returned descs. Whereas in the past this wasn't really feasible unless there was never going to be pre-supplied settings. I suspect the til_setting_desc_check() integration into setup_interactively() needs more work, but I think this is good enough for now and I'm out of spare time for the moment. --- src/drm_fb.c | 16 ++-- src/main.c | 23 +++-- src/modules/compose/compose.c | 40 ++++---- src/modules/drizzle/drizzle.c | 36 ++++--- src/modules/flui2d/flui2d.c | 103 +++++++++----------- src/modules/rtv/rtv.c | 206 ++++++++++++++++++---------------------- src/modules/sparkler/sparkler.c | 127 +++++++++++-------------- src/modules/stars/stars.c | 24 +++-- src/modules/submit/submit.c | 46 +++++---- src/sdl_fb.c | 74 ++++++--------- src/setup.c | 65 ++++++++----- src/setup.h | 2 +- src/til.c | 11 ++- src/til.h | 4 +- src/til_fb.h | 2 +- src/til_settings.c | 136 ++++++++++++++++---------- src/til_settings.h | 25 +++-- 17 files changed, 472 insertions(+), 468 deletions(-) diff --git a/src/drm_fb.c b/src/drm_fb.c index 3bd7d0d..69dd3b8 100644 --- a/src/drm_fb.c +++ b/src/drm_fb.c @@ -68,7 +68,7 @@ static const char * connector_type_name(uint32_t type) { } -static int dev_desc_generator(void *setup_context, til_setting_desc_t **res_desc) +static int dev_desc_generator(void *setup_context, const til_setting_desc_t **res_desc) { return til_setting_desc_clone(&(til_setting_desc_t){ .name = "DRM Device Path", @@ -145,7 +145,7 @@ static void free_strv(const char **strv) } -static int connector_desc_generator(void *setup_context, til_setting_desc_t **res_desc) +static int connector_desc_generator(void *setup_context, const til_setting_desc_t **res_desc) { drm_fb_setup_t *s = setup_context; const char **connectors; @@ -254,7 +254,7 @@ _out: } -static int mode_desc_generator(void *setup_context, til_setting_desc_t **res_desc) +static int mode_desc_generator(void *setup_context, const til_setting_desc_t **res_desc) { drm_fb_setup_t *s = setup_context; const char **modes; @@ -283,7 +283,7 @@ static int mode_desc_generator(void *setup_context, til_setting_desc_t **res_des /* setup is called repeatedly as settings is constructed, until 0 is returned. */ /* a negative value is returned on error */ /* positive value indicates another setting is needed, described in next_setting */ -static int drm_fb_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int drm_fb_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { drm_fb_setup_t context = {}; til_setting_desc_generator_t generators[] = { @@ -305,7 +305,7 @@ static int drm_fb_setup(const til_settings_t *settings, til_setting_desc_t **nex if (!drmAvailable()) return -ENOSYS; - return til_settings_apply_desc_generators(settings, generators, nelems(generators), &context, next_setting); + return til_settings_apply_desc_generators(settings, generators, nelems(generators), &context, res_setting, res_desc); } @@ -351,19 +351,19 @@ static int drm_fb_init(const til_settings_t *settings, void **res_context) goto _err; } - dev = til_settings_get_value(settings, "dev"); + dev = til_settings_get_value(settings, "dev", NULL); if (!dev) { r = -EINVAL; goto _err; } - connector = til_settings_get_value(settings, "connector"); + connector = til_settings_get_value(settings, "connector", NULL); if (!connector) { r = -EINVAL; goto _err; } - mode = til_settings_get_value(settings, "mode"); + mode = til_settings_get_value(settings, "mode", NULL); if (!mode) { r = -EINVAL; goto _err; diff --git a/src/main.c b/src/main.c index a8a1988..776db85 100644 --- a/src/main.c +++ b/src/main.c @@ -56,13 +56,13 @@ typedef struct setup_t { */ /* select video backend if not yet selected, then setup the selected backend. */ -static int setup_video(til_settings_t *settings, til_setting_desc_t **next_setting) +static int setup_video(til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { - const char *video; + const til_setting_t *setting; + const char *video; - /* XXX: there's only one option currently, so this is simple */ - video = til_settings_get_key(settings, 0); - if (!video) { + video = til_settings_get_key(settings, 0, &setting); + if (!video || !setting->desc) { til_setting_desc_t *desc; const char *values[] = { #ifdef HAVE_DRM @@ -80,10 +80,13 @@ static int setup_video(til_settings_t *settings, til_setting_desc_t **next_setti .preferred = DEFAULT_VIDEO, .values = values, .annotations = NULL - }, next_setting); + }, res_desc); + if (r < 0) return r; + *res_setting = video ? setting : NULL; + return 1; } @@ -92,13 +95,13 @@ static int setup_video(til_settings_t *settings, til_setting_desc_t **next_setti if (!strcmp(video, "drm")) { fb_ops = &drm_fb_ops; - return drm_fb_ops.setup(settings, next_setting); + return drm_fb_ops.setup(settings, res_setting, res_desc); } else #endif if (!strcmp(video, "sdl")) { fb_ops = &sdl_fb_ops; - return sdl_fb_ops.setup(settings, next_setting); + return sdl_fb_ops.setup(settings, res_setting, res_desc); } return -EINVAL; @@ -248,8 +251,8 @@ int main(int argc, const char *argv[]) exit_if(r && print_setup_as_args(&setup) < 0, "unable to print setup"); - exit_if(!(rototiller.module = til_lookup_module(til_settings_get_key(setup.module, 0))), - "unable to lookup module from settings \"%s\"", til_settings_get_key(setup.module, 0)); + exit_if(!(rototiller.module = til_lookup_module(til_settings_get_key(setup.module, 0, NULL))), + "unable to lookup module from settings \"%s\"", til_settings_get_key(setup.module, 0, NULL)); exit_if((r = til_fb_new(fb_ops, setup.video, NUM_FB_PAGES, &rototiller.fb)) < 0, "unable to create fb: %s", strerror(-r)); diff --git a/src/modules/compose/compose.c b/src/modules/compose/compose.c index bf3f125..81406c1 100644 --- a/src/modules/compose/compose.c +++ b/src/modules/compose/compose.c @@ -39,7 +39,7 @@ typedef struct compose_context_t { static void * compose_create_context(unsigned ticks, unsigned num_cpus); static void compose_destroy_context(void *context); static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); -static int compose_setup(const til_settings_t *settings, til_setting_desc_t **next_setting); +static int compose_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); static char *compose_default_layers[] = { "drizzle", "stars", "spiro", "plato", NULL }; static char **compose_layers; @@ -111,32 +111,30 @@ static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus } -static int compose_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int compose_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { const char *layers; - - layers = til_settings_get_value(settings, "layers"); - if (!layers) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Colon-Separated List Of Module Layers, In Draw Order", - .key = "layers", - .preferred = "drizzle:stars:spiro:plato", - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Colon-Separated List Of Module Layers, In Draw Order", + .key = "layers", + .preferred = "drizzle:stars:spiro:plato", + .annotations = NULL + }, + &layers, + res_setting, + res_desc); + if (r) + return r; /* turn layers colon-separated list into a null-terminated array of strings */ { const til_module_t **modules; - size_t n_modules; - char *toklayers, *layer; - int n = 2; + size_t n_modules; + char *toklayers, *layer; + int n = 2; til_get_modules(&modules, &n_modules); diff --git a/src/modules/drizzle/drizzle.c b/src/modules/drizzle/drizzle.c index a637368..b634a5e 100644 --- a/src/modules/drizzle/drizzle.c +++ b/src/modules/drizzle/drizzle.c @@ -153,7 +153,7 @@ static void drizzle_render_fragment(void *context, unsigned ticks, unsigned cpu, } -static int drizzle_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int drizzle_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { const char *viscosity; const char *values[] = { @@ -163,24 +163,22 @@ static int drizzle_setup(const til_settings_t *settings, til_setting_desc_t **ne ".05", NULL }; - - viscosity = til_settings_get_value(settings, "viscosity"); - if (!viscosity) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Puddle Viscosity", - .key = "viscosity", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), - .values = values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Puddle Viscosity", + .key = "viscosity", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), + .values = values, + .annotations = NULL + }, + &viscosity, + res_setting, + res_desc); + if (r) + return r; sscanf(viscosity, "%f", &drizzle_viscosity); diff --git a/src/modules/flui2d/flui2d.c b/src/modules/flui2d/flui2d.c index 5fb6087..ff0b6a4 100644 --- a/src/modules/flui2d/flui2d.c +++ b/src/modules/flui2d/flui2d.c @@ -283,7 +283,7 @@ static void flui2d_render_fragment(void *context, unsigned ticks, unsigned cpu, /* Settings hooks for configurable variables */ -static int flui2d_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int flui2d_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { const char *viscosity; const char *diffusion; @@ -307,61 +307,52 @@ static int flui2d_setup(const til_settings_t *settings, til_setting_desc_t **nex ".01", NULL }; - - - viscosity = til_settings_get_value(settings, "viscosity"); - if (!viscosity) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Fluid Viscosity", - .key = "viscosity", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), - .values = values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - diffusion = til_settings_get_value(settings, "diffusion"); - if (!diffusion) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Fluid Diffusion", - .key = "diffusion", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(DEFAULT_DIFFUSION), - .values = values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - decay = til_settings_get_value(settings, "decay"); - if (!decay) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Fluid Decay", - .key = "decay", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(DEFAULT_DECAY), - .values = decay_values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Fluid Viscosity", + .key = "viscosity", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), + .values = values, + .annotations = NULL + }, + &viscosity, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Fluid Diffusion", + .key = "diffusion", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(DEFAULT_DIFFUSION), + .values = values, + .annotations = NULL + }, + &diffusion, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Fluid Decay", + .key = "decay", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(DEFAULT_DECAY), + .values = decay_values, + .annotations = NULL + }, + &decay, + res_setting, + res_desc); + if (r) + return r; /* TODO: return -EINVAL on parse errors? */ sscanf(viscosity, "%f", &flui2d_viscosity); diff --git a/src/modules/rtv/rtv.c b/src/modules/rtv/rtv.c index a517e8c..91da0a5 100644 --- a/src/modules/rtv/rtv.c +++ b/src/modules/rtv/rtv.c @@ -48,7 +48,7 @@ static void * rtv_create_context(unsigned ticks, unsigned num_cpus); static void rtv_destroy_context(void *context); static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); static void rtv_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *fragment); -static int rtv_setup(const til_settings_t *settings, til_setting_desc_t **next_setting); +static int rtv_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); static unsigned rtv_duration = RTV_DURATION_SECS; static unsigned rtv_context_duration = RTV_CONTEXT_DURATION_SECS; @@ -94,9 +94,10 @@ static void randomize_channels(rtv_context_t *ctxt) static char * randomize_module_setup(const til_module_t *module) { - til_settings_t *settings; - til_setting_desc_t *desc; - char *arg; + til_settings_t *settings; + const til_setting_t *setting; + const til_setting_desc_t *desc; + char *arg; if (!module->setup) return NULL; @@ -105,12 +106,12 @@ static char * randomize_module_setup(const til_module_t *module) if (!settings) return NULL; - while (module->setup(settings, &desc) > 0) { + while (module->setup(settings, &setting, &desc) > 0) { if (desc->random) { char *value; value = desc->random(); - til_settings_add_value(settings, desc->key, value); + til_settings_add_value(settings, desc->key, value, desc); free(value); } else if (desc->values) { int n; @@ -119,12 +120,10 @@ static char * randomize_module_setup(const til_module_t *module) n = rand() % n; - til_settings_add_value(settings, desc->key, desc->values[n]); + til_settings_add_value(settings, desc->key, desc->values[n], desc); } else { - til_settings_add_value(settings, desc->key, desc->preferred); + til_settings_add_value(settings, desc->key, desc->preferred, desc); } - - til_setting_desc_free(desc); } arg = til_settings_as_arg(settings); @@ -313,114 +312,97 @@ static void rtv_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *f } -static int rtv_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int rtv_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { + const char *channels; const char *duration; const char *context_duration; const char *caption_duration; const char *snow_duration; - const char *channels; const char *snow_module; - - channels = til_settings_get_value(settings, "channels"); - if (!channels) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Colon-Separated List Of Channel Modules", - .key = "channels", - .preferred = "all", - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - duration = til_settings_get_value(settings, "duration"); - if (!duration) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Channel Duration In Seconds", - .key = "duration", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(RTV_DURATION_SECS), - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - context_duration = til_settings_get_value(settings, "context_duration"); - if (!context_duration) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Context Duration In Seconds", - .key = "context_duration", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(RTV_CONTEXT_DURATION_SECS), - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - caption_duration = til_settings_get_value(settings, "caption_duration"); - if (!caption_duration) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Caption Duration In Seconds", - .key = "caption_duration", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(RTV_CAPTION_DURATION_SECS), - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - snow_duration = til_settings_get_value(settings, "snow_duration"); - if (!snow_duration) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Snow On Channel Switch Duration In Seconds", - .key = "snow_duration", - .regex = "\\.[0-9]+", - .preferred = TIL_SETTINGS_STR(RTV_SNOW_DURATION_SECS), - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - snow_module = til_settings_get_value(settings, "snow_module"); - if (!snow_module) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Module To Use For Snow (\"none\" To Blank)", - .key = "snow_module", - .preferred = "snow", - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Colon-Separated List Of Channel Modules", + .key = "channels", + .preferred = "all", + .annotations = NULL + }, + &channels, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Channel Duration In Seconds", + .key = "duration", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(RTV_DURATION_SECS), + .annotations = NULL + }, + &duration, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Context Duration In Seconds", + .key = "context_duration", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(RTV_CONTEXT_DURATION_SECS), + .annotations = NULL + }, + &context_duration, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Caption Duration In Seconds", + .key = "caption_duration", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(RTV_CAPTION_DURATION_SECS), + .annotations = NULL + }, + &caption_duration, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Snow On Channel Switch Duration In Seconds", + .key = "snow_duration", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(RTV_SNOW_DURATION_SECS), + .annotations = NULL + }, + &snow_duration, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Module To Use For Snow (\"none\" To Blank)", + .key = "snow_module", + .preferred = "snow", + .annotations = NULL + }, + &snow_module, + res_setting, + res_desc); + if (r) + return r; /* turn channels colon-separated list into a null-terminated array of strings */ if (strcmp(channels, "all")) { diff --git a/src/modules/sparkler/sparkler.c b/src/modules/sparkler/sparkler.c index 8b8681f..6a4b604 100644 --- a/src/modules/sparkler/sparkler.c +++ b/src/modules/sparkler/sparkler.c @@ -96,83 +96,75 @@ static void sparkler_render_fragment(void *context, unsigned ticks, unsigned cpu /* Settings hooks for configurable variables */ -static int sparkler_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int sparkler_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { const char *show_bsp_leafs; const char *show_bsp_matches; const char *values[] = { - "off", - "on", - NULL + "off", + "on", + NULL }; + int r; /* TODO: return -EINVAL on parse errors? */ - show_bsp_leafs = til_settings_get_value(settings, "show_bsp_leafs"); - if (!show_bsp_leafs) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Show BSP Leaf Node Bounding Boxes", - .key = "show_bsp_leafs", - .preferred = "off", - .values = values, - }, next_setting); - if (r < 0) - return r; - - return 1; - } + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Show BSP Leaf Node Bounding Boxes", + .key = "show_bsp_leafs", + .preferred = "off", + .values = values + }, + &show_bsp_leafs, + res_setting, + res_desc); + if (r) + return r; if (!strcasecmp(show_bsp_leafs, "on")) { + const char *depth_values[] = { + "0", + "4", + "6", + "8", + "10", + NULL + }; const char *show_bsp_leafs_min_depth; sparkler_conf.show_bsp_leafs = 1; - show_bsp_leafs_min_depth = til_settings_get_value(settings, "show_bsp_leafs_min_depth"); - if (!show_bsp_leafs_min_depth) { - const char *depth_values[] = { - "0", - "4", - "6", - "8", - "10", - NULL - }; - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ .name = "Show BSP Leaf Node Bounding Boxes Minimum Depth", .key = "show_bsp_leafs_min_depth", .preferred = "8", - .values = depth_values, - }, next_setting); - if (r < 0) - return r; - - return 1; - } + .values = depth_values + }, + &show_bsp_leafs_min_depth, + res_setting, + res_desc); + if (r) + return r; sscanf(show_bsp_leafs_min_depth, "%u", &sparkler_conf.show_bsp_leafs_min_depth); } else { sparkler_conf.show_bsp_leafs = 0; } - show_bsp_matches = til_settings_get_value(settings, "show_bsp_matches"); - if (!show_bsp_matches) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Show BSP Search Matches", - .key = "show_bsp_matches", - .preferred = "off", - .values = values, - }, next_setting); - if (r < 0) - return r; - - return 1; - } + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Show BSP Search Matches", + .key = "show_bsp_matches", + .preferred = "off", + .values = values + }, + &show_bsp_matches, + res_setting, + res_desc); + if (r) + return r; if (!strcasecmp(show_bsp_matches, "on")) sparkler_conf.show_bsp_matches = 1; @@ -182,21 +174,18 @@ static int sparkler_setup(const til_settings_t *settings, til_setting_desc_t **n if (!strcasecmp(show_bsp_matches, "on")) { const char *show_bsp_matches_affected_only; - show_bsp_matches_affected_only = til_settings_get_value(settings, "show_bsp_matches_affected_only"); - if (!show_bsp_matches_affected_only) { - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Show Only Affected BSP Search Matches", - .key = "show_bsp_matches_affected_only", - .preferred = "off", - .values = values, - }, next_setting); - if (r < 0) - return r; - - return 1; - } + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Show Only Affected BSP Search Matches", + .key = "show_bsp_matches_affected_only", + .preferred = "off", + .values = values + }, + &show_bsp_matches_affected_only, + res_setting, + res_desc); + if (r) + return r; if (!strcasecmp(show_bsp_matches_affected_only, "on")) sparkler_conf.show_bsp_matches_affected_only = 1; diff --git a/src/modules/stars/stars.c b/src/modules/stars/stars.c index 9a0d2a9..c762043 100644 --- a/src/modules/stars/stars.c +++ b/src/modules/stars/stars.c @@ -201,10 +201,10 @@ static void stars_render_fragment(void *context, unsigned ticks, unsigned cpu, t ctxt->offset_y = tmp_y; } -int stars_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +int stars_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { const char *rot_adj; - const char *rot_adj_values[] = { + const char *rot_adj_values[] = { ".0", ".00001", ".00003", @@ -213,24 +213,22 @@ int stars_setup(const til_settings_t *settings, til_setting_desc_t **next_settin ".001", NULL }; + int r; - rot_adj = til_settings_get_value(settings, "rot_adj"); - if(!rot_adj) { - int ret_val; - - ret_val = til_setting_desc_clone(&(til_setting_desc_t){ + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ .name = "Rotation Rate", .key = "rot_adj", .regex = "\\.[0-9]+", .preferred = TIL_SETTINGS_STR(DEFAULT_ROT_ADJ), .values = rot_adj_values, .annotations = NULL - }, next_setting); - if(ret_val<0) - return ret_val; - - return 1; - } + }, + &rot_adj, + res_setting, + res_desc); + if (r) + return r; sscanf(rot_adj, "%f", &stars_rot_adj); diff --git a/src/modules/submit/submit.c b/src/modules/submit/submit.c index 288a69a..d643a2c 100644 --- a/src/modules/submit/submit.c +++ b/src/modules/submit/submit.c @@ -322,32 +322,30 @@ static void submit_render_fragment(void *context, unsigned ticks, unsigned cpu, } -static int submit_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int submit_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { + const char *values[] = { + "off", + "on", + NULL + }; const char *bilerp; - - bilerp = til_settings_get_value(settings, "bilerp"); - if (!bilerp) { - const char *values[] = { - "off", - "on", - NULL - }; - int r; - - r = til_setting_desc_clone(&(til_setting_desc_t){ - .name = "Bilinear Interpolation of Cell Colors", - .key = "bilerp", - .regex = NULL, - .preferred = values[0], - .values = values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Bilinear Interpolation of Cell Colors", + .key = "bilerp", + .regex = NULL, + .preferred = values[0], + .values = values, + .annotations = NULL + }, + &bilerp, + res_setting, + res_desc); + if (r) + return r; if (!strcasecmp(bilerp, "on")) bilerp_setting = 1; diff --git a/src/sdl_fb.c b/src/sdl_fb.c index 4a2b562..1d4aa3a 100644 --- a/src/sdl_fb.c +++ b/src/sdl_fb.c @@ -26,61 +26,47 @@ struct sdl_fb_page_t { }; -static int sdl_fb_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) +static int sdl_fb_setup(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { - const char *fullscreen_values[] = { - "off", - "on", - NULL - }; - const til_setting_desc_t descs[] = { - { + const char *fullscreen_values[] = { + "off", + "on", + NULL + }; + const char *fullscreen; + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ .name = "SDL Fullscreen Mode", .key = "fullscreen", .regex = NULL, .preferred = fullscreen_values[0], .values = fullscreen_values, .annotations = NULL - }, { - .name = "SDL Window size", - .key = "size", - .regex = "[1-9][0-9]*[xX][1-9][0-9]*", - .preferred = "640x480", - .values = NULL, - .annotations = NULL }, - }; - const char *fullscreen; - int r; - - - fullscreen = til_settings_get_value(settings, "fullscreen"); - if (!fullscreen) { - r = til_setting_desc_clone(&descs[0], next_setting); - if (r < 0) - return r; - - return 1; - } - - r = til_setting_desc_check(&descs[0], fullscreen); - if (r < 0) + &fullscreen, + res_setting, + res_desc); + if (r) return r; if (!strcasecmp(fullscreen, "off")) { const char *size; - size = til_settings_get_value(settings, "size"); - if (!size) { - r = til_setting_desc_clone(&descs[1], next_setting); - if (r < 0) - return r; - - return 1; - } - - r = til_setting_desc_check(&descs[1], size); - if (r < 0) + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "SDL Window size", + .key = "size", + .regex = "[1-9][0-9]*[xX][1-9][0-9]*", + .preferred = "640x480", + .values = NULL, + .annotations = NULL + }, + &size, + res_setting, + res_desc); + if (r) return r; } @@ -113,11 +99,11 @@ static int sdl_fb_init(const til_settings_t *settings, void **res_context) assert(settings); assert(res_context); - fullscreen = til_settings_get_value(settings, "fullscreen"); + fullscreen = til_settings_get_value(settings, "fullscreen", NULL); if (!fullscreen) return -EINVAL; - size = til_settings_get_value(settings, "size"); + size = til_settings_get_value(settings, "size", NULL); if (!size && !strcasecmp(fullscreen, "off")) return -EINVAL; diff --git a/src/setup.c b/src/setup.c index 9f67374..e027d1d 100644 --- a/src/setup.c +++ b/src/setup.c @@ -16,62 +16,78 @@ static int add_value(til_settings_t *settings, const char *key, const char *valu assert(key); - return til_settings_add_value(settings, key, value); + return til_settings_add_value(settings, key, value, NULL); } /* returns negative on error, otherwise number of additions made to settings */ -int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_desc_t **next), int defaults) +int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc), int defaults) { - unsigned additions = 0; - char buf[256] = "\n"; - til_setting_desc_t *next; - int r; + unsigned additions = 0; + char buf[256] = "\n"; + const til_setting_t *setting; + const til_setting_desc_t *desc; + int r; assert(settings); assert(setup_func); /* TODO: regex and error handling */ - while ((r = setup_func(settings, &next)) > 0) { + while ((r = setup_func(settings, &setting, &desc)) > 0) { additions++; + /* if setup_func() has returned a description for an undescribed preexisting setting, + * validate its value against the description and assign the description if it passes. + */ + if (setting && !setting->desc) { + /* XXX FIXME: this key as value exception is janky, make a helper to access the value or stop doing that. */ + r = til_setting_desc_check(desc, setting->value ? : setting->key); + if (r < 0) + return r; + + /* XXX FIXME everything's constified necessitating this fuckery, revisit and cleanup later, prolly another til_settings helper */ + ((til_setting_t *)setting)->desc = desc; + + continue; + } + if (!defaults) puts(""); - if (next->values) { + if (desc->values) { unsigned i, preferred = 0; int width = 0; - for (i = 0; next->values[i]; i++) { + for (i = 0; desc->values[i]; i++) { int len; - len = strlen(next->values[i]); + len = strlen(desc->values[i]); if (len > width) width = len; } /* multiple choice */ if (!defaults) - printf("%s:\n", next->name); + printf("%s:\n", desc->name); - for (i = 0; next->values[i]; i++) { + for (i = 0; desc->values[i]; i++) { if (!defaults) - printf("%2u: %*s%s%s\n", i, width, next->values[i], - next->annotations ? ": " : "", - next->annotations ? next->annotations[i] : ""); + printf("%2u: %*s%s%s\n", i, width, desc->values[i], + desc->annotations ? ": " : "", + desc->annotations ? desc->annotations[i] : ""); - if (!strcmp(next->preferred, next->values[i])) + if (!strcmp(desc->preferred, desc->values[i])) preferred = i; } if (!defaults) printf("Enter a value 0-%u [%u (%s)]: ", - i - 1, preferred, next->preferred); + i - 1, preferred, desc->preferred); } else { /* arbitrarily typed input */ if (!defaults) - printf("%s [%s]: ", next->name, next->preferred); + printf("%s [%s]: ", desc->name, desc->preferred); } if (!defaults) { @@ -81,11 +97,11 @@ int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings if (*buf == '\n') { /* accept preferred */ - add_value(settings, next->key, next->preferred); + add_value(settings, desc->key, desc->preferred); } else { buf[strlen(buf) - 1] = '\0'; - if (next->values) { + if (desc->values) { unsigned i, j, found; /* multiple choice, map numeric input to values entry */ @@ -95,9 +111,9 @@ int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings goto _next; } - for (found = i = 0; next->values[i]; i++) { + for (found = i = 0; desc->values[i]; i++) { if (i == j) { - add_value(settings, next->key, next->values[i]); + add_value(settings, desc->key, desc->values[i]); found = 1; break; } @@ -112,12 +128,11 @@ int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings } else { /* use typed input as setting, TODO: apply regex */ - add_value(settings, next->key, buf); + add_value(settings, desc->key, buf); } } - _next: - til_setting_desc_free(next); + til_setting_desc_free(desc); } return r < 0 ? r : additions; diff --git a/src/setup.h b/src/setup.h index 878e68b..5135b8e 100644 --- a/src/setup.h +++ b/src/setup.h @@ -3,6 +3,6 @@ #include "til_settings.h" -int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_desc_t **next), int defaults); +int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc), int defaults); #endif diff --git a/src/til.c b/src/til.c index 0989a6d..e69cade 100644 --- a/src/til.c +++ b/src/til.c @@ -165,12 +165,13 @@ int til_module_create_context(const til_module_t *module, unsigned ticks, void * /* select module if not yet selected, then setup the module. */ -int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting) +int til_module_setup(til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { + const til_setting_t *setting; const til_module_t *module; const char *name; - name = til_settings_get_key(settings, 0); + name = til_settings_get_key(settings, 0, &setting); if (!name) { const char *values[nelems(modules) + 1] = {}; const char *annotations[nelems(modules) + 1] = {}; @@ -189,10 +190,12 @@ int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting .preferred = DEFAULT_MODULE, .values = values, .annotations = annotations - }, next_setting); + }, res_desc); if (r < 0) return r; + *res_setting = name ? setting : NULL; + return 1; } @@ -201,7 +204,7 @@ int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting return -EINVAL; if (module->setup) - return module->setup(settings, next_setting); + return module->setup(settings, res_setting, res_desc); return 0; } diff --git a/src/til.h b/src/til.h index 6719693..02f8f2d 100644 --- a/src/til.h +++ b/src/til.h @@ -17,7 +17,7 @@ typedef struct til_module_t { void (*prepare_frame)(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); void (*render_fragment)(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment); void (*finish_frame)(void *context, unsigned ticks, til_fb_fragment_t *fragment); - int (*setup)(const til_settings_t *settings, til_setting_desc_t **next_setting); + int (*setup)(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); size_t (*knobs)(void *context, til_knob_t **res_knobs); char *name; char *description; @@ -32,6 +32,6 @@ const til_module_t * til_lookup_module(const char *name); void til_get_modules(const til_module_t ***res_modules, size_t *res_n_modules); void til_module_render(const til_module_t *module, void *context, unsigned ticks, til_fb_fragment_t *fragment); int til_module_create_context(const til_module_t *module, unsigned ticks, void **res_context); -int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting); +int til_module_setup(til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); #endif diff --git a/src/til_fb.h b/src/til_fb.h index 792c6e3..186324d 100644 --- a/src/til_fb.h +++ b/src/til_fb.h @@ -35,7 +35,7 @@ typedef struct til_fb_t til_fb_t; /* Supply this struct to fb_new() with the appropriate context */ typedef struct til_fb_ops_t { - int (*setup)(const til_settings_t *settings, til_setting_desc_t **next); + int (*setup)(const til_settings_t *settings, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); int (*init)(const til_settings_t *settings, void **res_context); void (*shutdown)(til_fb_t *fb, void *context); int (*acquire)(til_fb_t *fb, void *context, void *page); diff --git a/src/til_settings.c b/src/til_settings.c index e3c8c6c..30156d6 100644 --- a/src/til_settings.c +++ b/src/til_settings.c @@ -31,8 +31,7 @@ char * strndup(const char *s, size_t n) /* Split form of key=value[,key=value...] settings string */ typedef struct til_settings_t { unsigned num; - const char **keys; - const char **values; + til_setting_t **settings; } til_settings_t; typedef enum til_settings_fsm_state_t { @@ -43,16 +42,17 @@ typedef enum til_settings_fsm_state_t { } til_settings_fsm_state_t; -static int add_value(til_settings_t *settings, const char *key, const char *value) +static int add_value(til_settings_t *settings, const char *key, const char *value, const til_setting_desc_t *desc) { assert(settings); settings->num++; /* TODO errors */ - settings->keys = realloc(settings->keys, settings->num * sizeof(const char **)); - settings->values = realloc(settings->values, settings->num * sizeof(const char **)); - settings->keys[settings->num - 1] = key; - settings->values[settings->num - 1] = value; + settings->settings = realloc(settings->settings, settings->num * sizeof(til_setting_t *)); + settings->settings[settings->num - 1] = malloc(sizeof(til_setting_t)); + settings->settings[settings->num - 1]->key = key; + settings->settings[settings->num - 1]->value = value; + settings->settings[settings->num - 1]->desc = desc; return 0; } @@ -83,7 +83,7 @@ til_settings_t * til_settings_new(const char *settings_string) case TIL_SETTINGS_FSM_STATE_KEY: if (*p == '=' || *p == ',' || *p == '\0') { - add_value(settings, strndup(token, p - token), NULL); + add_value(settings, strndup(token, p - token), NULL, NULL); if (*p == '=') state = TIL_SETTINGS_FSM_STATE_EQUAL; @@ -99,7 +99,7 @@ til_settings_t * til_settings_new(const char *settings_string) case TIL_SETTINGS_FSM_STATE_VALUE: if (*p == ',' || *p == '\0') { - settings->values[settings->num - 1] = strndup(token, p - token); + settings->settings[settings->num - 1]->value = strndup(token, p - token); state = TIL_SETTINGS_FSM_STATE_COMMA; } break; @@ -124,12 +124,13 @@ til_settings_t * til_settings_free(til_settings_t *settings) if (settings) { for (unsigned i = 0; i < settings->num; i++) { - free((void *)settings->keys[i]); - free((void *)settings->values[i]); + free((void *)settings->settings[i]->key); + free((void *)settings->settings[i]->value); + til_setting_desc_free((void *)settings->settings[i]->desc); + free((void *)settings->settings[i]); } - free((void *)settings->keys); - free((void *)settings->values); + free((void *)settings->settings); free(settings); } @@ -138,14 +139,18 @@ til_settings_t * til_settings_free(til_settings_t *settings) /* find key= in settings, return dup of value side or NULL if missing */ -const char * til_settings_get_value(const til_settings_t *settings, const char *key) +const char * til_settings_get_value(const til_settings_t *settings, const char *key, const til_setting_t **res_setting) { assert(settings); assert(key); for (int i = 0; i < settings->num; i++) { - if (!strcmp(key, settings->keys[i])) - return settings->values[i]; + if (!strcmp(key, settings->settings[i]->key)) { + if (res_setting) + *res_setting = settings->settings[i]; + + return settings->settings[i]->value; + } } return NULL; @@ -153,27 +158,71 @@ const char * til_settings_get_value(const til_settings_t *settings, const char * /* return positional key from settings */ -const char * til_settings_get_key(const til_settings_t *settings, unsigned pos) +const char * til_settings_get_key(const til_settings_t *settings, unsigned pos, const til_setting_t **res_setting) { assert(settings); - if (pos < settings->num) - return settings->keys[pos]; + if (pos < settings->num) { + if (res_setting) + *res_setting = settings->settings[pos]; + + return settings->settings[pos]->key; + } return NULL; } +/* helper for the common setup case of describing a setting when absent or not yet described. + * returns: + * -1 on error, res_* will be untouched in this case. + * 0 when setting is present and described, res_value and res_setting will be populated w/non-NULL, and res_desc NULL in this case. + * 1 when setting is either present but undescribed, or absent (and undescribed), res_* will be populated but res_{value,setting} may be NULL if absent and simply described. + */ +int til_settings_get_and_describe_value(const til_settings_t *settings, const til_setting_desc_t *desc, const char **res_value, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) +{ + const til_setting_t *setting; + const char *value; + + assert(settings); + assert(desc); + assert(res_value); + assert(res_setting); + assert(res_desc); + + value = til_settings_get_value(settings, desc->key, &setting); + if (!value || !setting->desc) { + int r; + + r = til_setting_desc_clone(desc, res_desc); + if (r < 0) + return r; + + *res_value = value; + *res_setting = value ? setting : NULL; + + return 1; + } + + *res_value = value; + *res_setting = setting; + *res_desc = NULL; + + return 0; +} + + /* add key=value to the settings, * or just key if value is NULL. + * desc may be NULL, it's simply passed along as a passenger. */ /* returns < 0 on error */ -int til_settings_add_value(til_settings_t *settings, const char *key, const char *value) +int til_settings_add_value(til_settings_t *settings, const char *key, const char *value, const til_setting_desc_t *desc) { assert(settings); assert(key); - return add_value(settings, strdup(key), value ? strdup(value) : NULL); + return add_value(settings, strdup(key), value ? strdup(value) : NULL, desc); } @@ -181,43 +230,27 @@ int til_settings_add_value(til_settings_t *settings, const char *key, const char /* returns 0 when input settings are complete */ /* returns 1 when input settings are incomplete, storing the next setting's description needed in *next_setting */ /* returns -errno on error */ -int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, til_setting_desc_t **next_setting) +int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, const til_setting_t **res_setting, const til_setting_desc_t **res_desc) { - til_setting_desc_t *next; - assert(settings); assert(generators); assert(n_generators > 0); - assert(next_setting); + assert(res_setting); + assert(res_desc); for (unsigned i = 0; i < n_generators; i++) { const til_setting_desc_generator_t *g = &generators[i]; - const char *value; - til_setting_desc_t *desc; + const til_setting_desc_t *desc; int r; r = g->func(setup_context, &desc); if (r < 0) return r; - assert(desc); - - value = til_settings_get_value(settings, g->key); - if (value) { - int r; - - r = til_setting_desc_check(desc, value); - til_setting_desc_free(desc); - if (r < 0) - return r; - - if (g->value_ptr) - *g->value_ptr = value; - - continue; - } - - *next_setting = desc; + r = til_settings_get_and_describe_value(settings, desc, g->value_ptr, res_setting, res_desc); + til_setting_desc_free(desc); /* always need to cleanup the desc from g->func(), res_desc gets its own copy */ + if (r) + return r; return 1; } @@ -229,7 +262,7 @@ int til_settings_apply_desc_generators(const til_settings_t *settings, const til /* convenience helper for creating a new setting description */ /* copies of everything supplied are made in newly allocated memory, stored @ res_desc */ /* returns < 0 on error */ -int til_setting_desc_clone(const til_setting_desc_t *desc, til_setting_desc_t **res_desc) +int til_setting_desc_clone(const til_setting_desc_t *desc, const til_setting_desc_t **res_desc) { til_setting_desc_t *d; @@ -280,7 +313,7 @@ int til_setting_desc_clone(const til_setting_desc_t *desc, til_setting_desc_t ** } -til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc) +til_setting_desc_t * til_setting_desc_free(const til_setting_desc_t *desc) { if (desc) { free((void *)desc->name); @@ -300,7 +333,7 @@ til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc) free((void *)desc->annotations); } - free(desc); + free((void *)desc); } return NULL; @@ -310,6 +343,7 @@ til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc) int til_setting_desc_check(const til_setting_desc_t *desc, const char *value) { assert(desc); + assert(value); if (desc->values) { @@ -366,10 +400,10 @@ char * til_settings_as_arg(const til_settings_t *settings) if (i > 0) off += snpf(buf, size, off, ","); - off += snpf(buf, size, off, "%s", settings->keys[i]); + off += snpf(buf, size, off, "%s", settings->settings[i]->key); - if (settings->values[i]) - off += snpf(buf, size, off, "=%s", settings->values[i]); + if (settings->settings[i]->value) + off += snpf(buf, size, off, "=%s", settings->settings[i]->value); } if (!buf) { diff --git a/src/til_settings.h b/src/til_settings.h index 935aa5b..52535fe 100644 --- a/src/til_settings.h +++ b/src/til_settings.h @@ -3,6 +3,9 @@ #include +typedef struct til_setting_t til_setting_t; +typedef struct til_settings_t til_settings_t; + /* Individual setting description */ typedef struct til_setting_desc_t { const char *name; /* long-form/human name for setting */ @@ -18,21 +21,27 @@ typedef struct til_setting_desc_t { typedef struct til_setting_desc_generator_t { const char *key; /* key this generator applies to */ const char **value_ptr; /* where to put the value */ - int (*func)(void *setup_context, til_setting_desc_t **res_desc); + int (*func)(void *setup_context, const til_setting_desc_t **res_desc); } til_setting_desc_generator_t; -typedef struct til_settings_t til_settings_t; +/* Encapsulates a single til_settings_t entry */ +struct til_setting_t { + const char *key; + const char *value; + const til_setting_desc_t *desc; +}; til_settings_t * til_settings_new(const char *settings); til_settings_t * til_settings_free(til_settings_t *settings); -const char * til_settings_get_value(const til_settings_t *settings, const char *key); -const char * til_settings_get_key(const til_settings_t *settings, unsigned pos); -int til_settings_add_value(til_settings_t *settings, const char *key, const char *value); +const char * til_settings_get_value(const til_settings_t *settings, const char *key, const til_setting_t **res_setting); +const char * til_settings_get_key(const til_settings_t *settings, unsigned pos, const til_setting_t **res_setting); +int til_settings_add_value(til_settings_t *settings, const char *key, const char *value, const til_setting_desc_t *desc); +int til_settings_get_and_describe_value(const til_settings_t *settings, const til_setting_desc_t *desc, const char **res_value, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); char * til_settings_as_arg(const til_settings_t *settings); -int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, til_setting_desc_t **next_setting); +int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, const til_setting_t **res_setting, const til_setting_desc_t **res_desc); -int til_setting_desc_clone(const til_setting_desc_t *desc, til_setting_desc_t **res_desc); -til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc); +int til_setting_desc_clone(const til_setting_desc_t *desc, const til_setting_desc_t **res_desc); +til_setting_desc_t * til_setting_desc_free(const til_setting_desc_t *desc); int til_setting_desc_check(const til_setting_desc_t *desc, const char *value); #ifndef TIL_SETTINGS_STR -- cgit v1.2.1