diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2023-08-03 00:55:59 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2023-08-03 00:55:59 -0700 |
commit | 81f6fd2208cbed6ac8f7e77b2f0b8dd7ac741fe3 (patch) | |
tree | fccb815ca92e9983f086f3c39ddcd05c3a5f38f8 | |
parent | 70cc48ba418d69127e3a1d82415785c5964d9448 (diff) |
til_settings: introduce til_setting_t.nocheck
This adds a setting value syntax for bypassing checks; ':' prefix
e.g.
--module=:experimental_module
Would result in the value experimental_module added, and no
verification performed of its presence in the module setting's
values list.
Two new til_settings api functions are introduced as well for
setting and getting the raw values including any prefix syntax:
til_setting_get_raw_value()
til_setting_set_raw_value()
these are needed because the til_setting_t.value member will
continue to point at the "cooked" form of the value with the
prefix stripped out, so the general cases of needing the value
won't have to worry about the presence of prefixes. They have
the til_setting_t.nocheck member to see if the setting was a
nocheck-prefixed value.
The nocheck prefix is preserved across serialization as well. So
using a serialized form to seed a derivative settings instance
won't spuriously start failing checks because the ':' prefixes
are gone where they were necessary. They'll be kept wherever
they were previously.
There will probably be some more random fixes needed here and
there where code is directly manipulating til_setting_t.value and
must now go through the "raw" getter/setter api.
-rw-r--r-- | src/til_settings.c | 93 | ||||
-rw-r--r-- | src/til_settings.h | 3 |
2 files changed, 89 insertions, 7 deletions
diff --git a/src/til_settings.c b/src/til_settings.c index 907e114..eca937b 100644 --- a/src/til_settings.c +++ b/src/til_settings.c @@ -49,7 +49,7 @@ typedef enum til_settings_fsm_state_t { } til_settings_fsm_state_t; -static til_setting_t * add_setting(til_settings_t *settings, const char *key, const char *value) +static til_setting_t * add_setting(til_settings_t *settings, const char *key, const char *value, int nocheck) { til_setting_t **new_entries; til_setting_t *s; @@ -63,6 +63,7 @@ static til_setting_t * add_setting(til_settings_t *settings, const char *key, co s->parent = settings; s->key = key; s->value = value; + s->nocheck = nocheck; new_entries = realloc(settings->entries, (settings->num + 1) * sizeof(til_setting_t *)); if (!new_entries) { @@ -123,10 +124,16 @@ til_settings_t * til_settings_new(const char *prefix, const til_settings_t *pare else if (*p == '=' || *p == ',' || *p == '\0') { if (*p == '=') { /* key= */ - (void) add_setting(settings, til_str_to_buf(value_str, NULL), NULL); + (void) add_setting(settings, til_str_to_buf(value_str, NULL), NULL, 0); state = TIL_SETTINGS_FSM_STATE_EQUAL; } else { /* bare value */ - (void) add_setting(settings, NULL, til_str_to_buf(value_str, NULL)); + char *v = til_str_to_buf(value_str, NULL); + int nocheck = v[0] == ':' ? 1 : 0; + + if (nocheck) + v++; + + (void) add_setting(settings, NULL, v, nocheck); state = TIL_SETTINGS_FSM_STATE_COMMA; } } else @@ -150,7 +157,14 @@ til_settings_t * til_settings_new(const char *prefix, const til_settings_t *pare if (*p == '\\') state = TIL_SETTINGS_FSM_STATE_VALUE_ESCAPED; else if (*p == ',' || *p == '\0') { - settings->entries[settings->num - 1]->value = til_str_to_buf(value_str, NULL); + char *v = til_str_to_buf(value_str, NULL); + int r; + + r = til_setting_set_raw_value(settings->entries[settings->num - 1], v); + free(v); + if (r < 0) + goto _err; + state = TIL_SETTINGS_FSM_STATE_COMMA; } else til_str_appendf(value_str, "%c", *p); /* FIXME: errors */ @@ -196,7 +210,11 @@ til_settings_t * til_settings_free(til_settings_t *settings) til_settings_free(settings->entries[i]->value_as_nested_settings); free((void *)settings->entries[i]->key); - free((void *)settings->entries[i]->value); + if (settings->entries[i]->value) { + if (settings->entries[i]->nocheck) + settings->entries[i]->value--; + free((void *)settings->entries[i]->value); + } til_setting_desc_free((void *)settings->entries[i]->desc); free((void *)settings->entries[i]); } @@ -340,11 +358,23 @@ int til_settings_get_and_describe_value(const til_settings_t *settings, const ti /* returns the added setting, or NULL on error (ENOMEM) */ til_setting_t * til_settings_add_value(til_settings_t *settings, const char *key, const char *value) { + int nocheck = 0; + char *v; + assert(settings); assert(value); /* XXX: ^^ non-NULL values makes til_settings_get_value_by_idx() NULL-return-for-end-of-settings OK */ - return add_setting(settings, key ? strdup(key) : NULL, strdup(value)); + v = strdup(value); + if (!v) + return NULL; + + if (v[0] == ':') { + nocheck = 1; + v++; + } + + return add_setting(settings, key ? strdup(key) : NULL, v, nocheck); } @@ -572,6 +602,53 @@ int til_setting_spec_check(const til_setting_spec_t *spec, const char *value) } +/* helper for changing the "raw" value of a setting, maintains til_setting_t.nocheck */ +int til_setting_set_raw_value(til_setting_t *setting, const char *value) +{ + int nocheck = 0; + const char *v; + + assert(setting); + assert(value); + + v = strdup(value); + if (!v) + return -ENOMEM; + + if (v[0] == ':') { + nocheck = 1; + v++; + } + + if (setting->value) { + if (setting->nocheck) + setting->value--; + free((void *)setting->value); + } + + setting->value = v; + setting->nocheck = nocheck; + + return 0; +} + + +/* helper for accessing the "raw" value for a setting, which presently just means + * if a value was added as a "nocheck" value with a ':' prefix, this will return the + * prefixed form. Otherwise you just get the same thing as setting->value. + */ +const char * til_setting_get_raw_value(til_setting_t *setting) +{ + assert(setting); + + if (setting->nocheck) + return setting->value - 1; + + return setting->value; +} + + + static inline void fputc_escaped(til_str_t *out, int c, unsigned depth) { unsigned escapes = 0; @@ -627,7 +704,9 @@ static int settings_as_arg(const til_settings_t *settings, int unfiltered, unsig if (settings->entries[i]->value_as_nested_settings) { settings_as_arg(settings->entries[i]->value_as_nested_settings, unfiltered, depth + 1, out); } else if (settings->entries[i]->value) { - fputs_escaped(out, settings->entries[i]->value, depth); + const char *v = til_setting_get_raw_value(settings->entries[i]); + + fputs_escaped(out, v, depth); } j++; } diff --git a/src/til_settings.h b/src/til_settings.h index 85df105..95b2ac4 100644 --- a/src/til_settings.h +++ b/src/til_settings.h @@ -43,6 +43,7 @@ struct til_setting_t { const char *value; const til_setting_desc_t *desc; void *user_data; + unsigned nocheck:1; /* set when user explicitly set the value outside the guards */ }; til_settings_t * til_settings_new(const char *prefix, const til_settings_t *parent, const char *label, const char *settings); @@ -65,6 +66,8 @@ til_setting_desc_t * til_setting_desc_free(const til_setting_desc_t *desc); int til_setting_desc_strprint_path(const til_setting_desc_t *desc, til_str_t *str); int til_setting_desc_fprint_path(const til_setting_desc_t *desc, FILE *out); int til_setting_spec_check(const til_setting_spec_t *spec, const char *value); +int til_setting_set_raw_value(til_setting_t *setting, const char *value); +const char * til_setting_get_raw_value(til_setting_t *setting); int til_settings_label_setting(const til_settings_t *settings, const til_setting_t *setting, char **res_label); int til_settings_strprint_path(const til_settings_t *settings, til_str_t *str); int til_settings_fprint_path(const til_settings_t *settings, FILE *out); |