summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2022-03-12 17:29:26 -0800
committerVito Caputo <vcaputo@pengaru.com>2022-03-12 23:22:51 -0800
commit7ff8ef94c05ae6386463b63f3ba25add52340d8b (patch)
tree585b67df6590acac86d287e42a6bffb0bf995639
parent009f16f93b2a055ec0e14751e6d779849f87ab04 (diff)
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.
-rw-r--r--src/drm_fb.c16
-rw-r--r--src/main.c23
-rw-r--r--src/modules/compose/compose.c40
-rw-r--r--src/modules/drizzle/drizzle.c36
-rw-r--r--src/modules/flui2d/flui2d.c103
-rw-r--r--src/modules/rtv/rtv.c206
-rw-r--r--src/modules/sparkler/sparkler.c127
-rw-r--r--src/modules/stars/stars.c24
-rw-r--r--src/modules/submit/submit.c46
-rw-r--r--src/sdl_fb.c74
-rw-r--r--src/setup.c65
-rw-r--r--src/setup.h2
-rw-r--r--src/til.c11
-rw-r--r--src/til.h4
-rw-r--r--src/til_fb.h2
-rw-r--r--src/til_settings.c136
-rw-r--r--src/til_settings.h25
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 <stdio.h>
+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
© All Rights Reserved