aboutsummaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-11-24 17:40:26 +0100
committerFederico Angelilli <code@fedang.net>2024-11-24 17:40:26 +0100
commit76ad6b0d404d40f08b73d90ac5f66564c29feb95 (patch)
tree59e2c0b0c5ecd0e092a295352f8b7fa0bc15db4e /src/config.c
parent30020a08392c959505bd27388564f7436a04bace (diff)
Refactor config parser
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c269
1 files changed, 152 insertions, 117 deletions
diff --git a/src/config.c b/src/config.c
index f76065c..c8f53f9 100644
--- a/src/config.c
+++ b/src/config.c
@@ -14,13 +14,14 @@
#define ANY_INI_IMPLEMENT
#include "any_ini.h"
-typedef enum {
- CONFIG_SUCCESS,
- CONFIG_INVALID,
- CONFIG_UNKNOWN,
-} config_status_t;
+config_enum_t text_align_enum[] = {
+ { "left", ALIGN_LEFT },
+ { "center", ALIGN_CENTER },
+ { "right", ALIGN_RIGHT },
+ { 0 },
+};
-static const config_entry_t bar_entries[] = {
+const config_entry_t bar_entries[] = {
{ "width", CONFIG_UINT, NULL, offsetof(config_t, width) },
{ "height", CONFIG_UINT, NULL, offsetof(config_t, height) },
{ "font", CONFIG_STRING, NULL, offsetof(config_t, font) },
@@ -31,7 +32,7 @@ static const config_entry_t bar_entries[] = {
{ 0 },
};
-static const config_entry_t block_entries[] = {
+const config_entry_t block_entries[] = {
{ "hidden", CONFIG_BOOL, NULL, offsetof(block_t, hidden) },
{ "color", CONFIG_GRADIENT, NULL, offsetof(block_t, bg_color) },
{ "line-color", CONFIG_GRADIENT, NULL, offsetof(block_t, line_color) },
@@ -45,21 +46,14 @@ static const config_entry_t block_entries[] = {
{ 0 },
};
-static const config_entry_t block_group_entries[] = {
+const config_entry_t block_group_entries[] = {
{ "spacing", CONFIG_UINT, NULL, offsetof(block_group_t, spacing) },
{ "blocks", CONFIG_LIST, NULL, offsetof(block_group_t, children) },
{ "collapse", CONFIG_BOOL, NULL, offsetof(block_group_t, collapse) },
{ 0 },
};
-static config_enum_t text_align_enum[] = {
- { "left", ALIGN_LEFT },
- { "center", ALIGN_CENTER },
- { "right", ALIGN_RIGHT },
- { 0 },
-};
-
-static const config_entry_t block_text_entries[] = {
+const config_entry_t block_text_entries[] = {
{ "text", CONFIG_STRING, NULL, offsetof(block_text_t, text) },
{ "text-color", CONFIG_COLOR, NULL, offsetof(block_text_t, text_color) },
{ "text-size", CONFIG_UINT, NULL, offsetof(block_text_t, text_size) },
@@ -67,6 +61,25 @@ static const config_entry_t block_text_entries[] = {
{ 0 },
};
+const char *config_type_to_string(config_type_t type)
+{
+ static const char *types[] = {
+ "string",
+ "integer",
+ "unsigned integer",
+ "double float",
+ "boolean",
+ "color",
+ "gradient",
+ "enum",
+ "time",
+ "list",
+ };
+
+ assert(type >= CONFIG_STRING && type <= CONFIG_LIST);
+ return types[type];
+}
+
static bool config_read_string(const char *value, char **result)
{
if (value == NULL)
@@ -290,29 +303,98 @@ static bool config_read_list(const char *value, char ***result)
return true;
}
-static config_status_t config_read_entry(const config_entry_t *entries, void *result, const char **type,
- const char *section, const char *key, const char *value)
+static config_status_t config_read_block(const block_scheme_t *scheme, block_t *block, const char **type,
+ const char *key, const char *value)
{
- static const char *types[] = {
- "string",
- "integer",
- "unsigned integer",
- "double float",
- "boolean",
- "color",
- "gradient",
- "enum",
- "time",
- "list",
+ const char *section = "block";
+ size_t index = 0;
+
+ config_status_t status = config_read_entry(block_entries, block, &index, section, block->label, key, value);
+ *type = config_type_to_string(block_entries[index].type);
+
+ if (status != CONFIG_UNKNOWN) return status;
+
+ if (block->type == BLOCK_GROUP)
+ status = config_read_entry(block_group_entries, block, &index, section, block->label, key, value);
+ else if (block->type == BLOCK_TEXT)
+ status = config_read_entry(block_text_entries, block, &index, section, block->label, key, value);
+
+ *type = config_type_to_string(block_entries[index].type);
+ if (status != CONFIG_UNKNOWN || scheme->entries == NULL)
+ return status;
+
+ status = config_read_entry(scheme->entries, block, &index, section, block->label, key, value);
+ *type = config_type_to_string(block_entries[index].type);
+ return status;
+}
+
+static block_t *config_alloc_block(config_t *config, const block_scheme_t *scheme, char *label)
+{
+ config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t *));
+ assert(config->blocks != NULL);
+
+ block_t *block = config->blocks[config->n_blocks - 1] = calloc(1, scheme->size);
+ assert(block != NULL);
+
+ block->label = label;
+ block->scheme = scheme;
+ scheme->init_fn(block);
+
+ return block;
+}
+
+static config_status_t config_read_action(action_t *action, const char *key, const char *value)
+{
+ action_type_t type;
+
+ if (!strcmp(key, "target"))
+ type = ACTION_TARGET;
+ else if (!strncmp(key, "set-", 4))
+ type = ACTION_SET_PAIR;
+ else if (!strcmp(key, "run-script"))
+ type = ACTION_RUN_SCRIPT;
+ else
+ return CONFIG_UNKNOWN;
+
+ action->parts = realloc(action->parts, ++action->length * sizeof(action_part_t));
+ assert(action->parts != NULL);
+
+ action->parts[action->length - 1].type = type;
+ action->parts[action->length - 1].key = strcopy(key);
+ action->parts[action->length - 1].value = strcopy(value);
+
+ return CONFIG_SUCCESS;
+}
+
+// TODO: More robust way to define defaults
+void config_init(config_t *config)
+{
+ const config_t config_default = {
+ .font = "monospace 10",
+ .monitor = NULL,
+ .width = 100,
+ .height = 50,
+ .override_redirect = false,
};
+ memcpy(config, &config_default, sizeof(config_t));
+ config->font = strcopy(config_default.font);
+
+ extern const block_scheme_t block_group_scheme;
+ block_group_t *bar = (block_group_t *)config_alloc_block(config, &block_group_scheme, strcopy("bar"));
+ bar->spacing = 10;
+}
+
+config_status_t config_read_entry(const config_entry_t *entries, void *result, size_t *index,
+ const char *section, const char *label, const char *key, const char *value)
+{
for (size_t i = 0; entries[i].key != NULL; i++) {
if (!strcmp(key, entries[i].key)) {
- if (type != NULL)
- *type = types[entries[i].type];
+ if (index != NULL) *index = i;
result += entries[i].offset;
- bool nullable = type == CONFIG_STRING;
+ bool nullable = entries[i].type == CONFIG_STRING || entries[i].type == CONFIG_LIST;
+
if ((value == NULL || *value == '\0') && !nullable)
return CONFIG_INVALID;
@@ -320,35 +402,45 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
case CONFIG_STRING:
// NOTE: The previous string is freed by config_read_string
if (config_read_string(value, (char **)result)) {
- log_debug("Set '%s.%s' to '%s'", section, key, *(char **)result);
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(char **)result);
return CONFIG_SUCCESS;
}
break;
case CONFIG_INT:
if (config_read_int(value, (int *)result)) {
- log_debug("Set '%s.%s' to '%d'", section, key, *(int *)result);
+ log_debug("Set '%s%s%s.%s' to '%d'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(int *)result);
return CONFIG_SUCCESS;
}
break;
case CONFIG_UINT:
if (config_read_uint(value, (unsigned int *)result)) {
- log_debug("Set '%s.%s' to '%u'", section, key, *(unsigned int *)result);
+ log_debug("Set '%s%s%s.%s' to '%u'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(unsigned int *)result);
return CONFIG_SUCCESS;
}
break;
case CONFIG_DOUBLE:
if (config_read_double(value, (double *)result)) {
- log_debug("Set '%s.%s' to '%lf'", section, key, *(double *)result);
+ log_debug("Set '%s%s%s.%s' to '%g'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(double *)result);
return CONFIG_SUCCESS;
}
break;
case CONFIG_BOOL:
if (config_read_bool(value, (bool *)result)) {
- log_debug("Set '%s.%s' to '%s'", section, key, *(bool *)result ? "true" : "false");
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(bool *)result ? "true" : "false");
return CONFIG_SUCCESS;
}
break;
@@ -356,7 +448,9 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
case CONFIG_COLOR:
if (config_read_color(value, (color_t *)result)) {
char *color = color_to_string((color_t *)result);
- log_debug("Set '%s.%s' to '%s'", section, key, color);
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, color);
free(color);
return CONFIG_SUCCESS;
}
@@ -365,7 +459,9 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
case CONFIG_GRADIENT:
if (config_read_gradient(value, (gradient_t *)result)) {
char *gradient = gradient_to_string((gradient_t *)result);
- log_debug("Set '%s.%s' to '%s'", section, key, gradient);
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, gradient);
free(gradient);
return CONFIG_SUCCESS;
}
@@ -373,21 +469,28 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
case CONFIG_ENUM:
if (config_read_enum(value, (config_enum_t *)entries[i].data, (int *)result)) {
- log_debug("Set '%s.%s' to '%d'", section, key, *(int *)result);
+ log_debug("Set '%s%s%s.%s' to '%d'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, *(int *)result);
return CONFIG_SUCCESS;
}
break;
case CONFIG_TIME:
if (config_read_time(value, (struct timespec *)result)) {
- log_debug("Set '%s.%s' to '%s'", section, key, value);
+ // TODO: Print
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, value);
return CONFIG_SUCCESS;
}
break;
case CONFIG_LIST:
if (config_read_list(value, (char ***)result)) {
- log_debug("Set '%s.%s' to '%s'", section, key, value);
+ log_debug("Set '%s%s%s.%s' to '%s'",
+ section != NULL ? section : "", section != NULL ? "." : "",
+ label, key, value);
return CONFIG_SUCCESS;
}
break;
@@ -403,77 +506,6 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
return CONFIG_UNKNOWN;
}
-static config_status_t config_read_block(const block_scheme_t *scheme, block_t *block, const char **type,
- const char *section, const char *key, const char *value)
-{
- config_status_t status = config_read_entry(block_entries, block, type, section, key, value);
- if (status != CONFIG_UNKNOWN) return status;
-
- status = config_read_entry(block->type == BLOCK_GROUP ? block_group_entries : block_text_entries,
- block, type, section, key, value);
-
- return status != CONFIG_UNKNOWN || scheme == NULL || scheme->entries == NULL
- ? status
- : config_read_entry(scheme->entries, block, type, section, key, value);
-}
-
-static block_t *config_alloc_block(config_t *config, const block_scheme_t *scheme, char *label)
-{
- config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t *));
- assert(config->blocks != NULL);
-
- block_t *block = config->blocks[config->n_blocks - 1] = calloc(1, scheme->size);
- assert(block != NULL);
-
- block->label = label;
- block->scheme = scheme;
- scheme->init_fn(block);
-
- return block;
-}
-
-static config_status_t config_read_action(action_t *action, const char *section, const char *key, const char *value)
-{
- action_type_t type;
-
- if (!strcmp(key, "target"))
- type = ACTION_TARGET;
- else if (!strncmp(key, "set-", 4))
- type = ACTION_SET_PAIR;
- else if (!strcmp(key, "run-script"))
- type = ACTION_RUN_SCRIPT;
- else
- return CONFIG_UNKNOWN;
-
- action->parts = realloc(action->parts, ++action->length * sizeof(action_part_t));
- assert(action->parts != NULL);
-
- action->parts[action->length - 1].type = type;
- action->parts[action->length - 1].key = strcopy(key);
- action->parts[action->length - 1].value = strcopy(value);
-
- return CONFIG_SUCCESS;
-}
-
-// TODO: More robust way to define defaults
-void config_init(config_t *config)
-{
- const config_t config_default = {
- .font = "monospace 10",
- .monitor = NULL,
- .width = 100,
- .height = 50,
- .override_redirect = false,
- };
-
- memcpy(config, &config_default, sizeof(config_t));
- config->font = strcopy(config_default.font);
-
- extern const block_scheme_t block_group_scheme;
- block_group_t *bar = (block_group_t *)config_alloc_block(config, &block_group_scheme, strcopy("bar"));
- bar->spacing = 10;
-}
-
int config_read(config_t *config, FILE *file)
{
any_ini_stream_t ini;
@@ -601,19 +633,22 @@ int config_read(config_t *config, FILE *file)
config_status_t status;
if (bar_section) {
- status = config_read_entry(bar_entries, config, &type, section, key, value);
+ size_t index = 0;
+ status = config_read_entry(bar_entries, config, &index, NULL, "bar", key, value);
// Try the block entries
if (status == CONFIG_UNKNOWN)
block = config->blocks[0];
+ else
+ type = config_type_to_string(bar_entries[index].type);
}
if (block != NULL) {
- status = config_read_block(scheme, block, &type, section, key, value);
+ status = config_read_block(scheme, block, &type, key, value);
}
if (action != NULL) {
- status = config_read_action(action, section, key, value);
+ status = config_read_action(action, key, value);
}
switch (status) {
@@ -672,7 +707,7 @@ int config_validate(config_t *config)
if (scheme->validate_fn == NULL) continue;
log_debug("Validating 'block.%s'", block->label);
- int tmp = scheme->validate_fn(block);
+ int tmp = scheme->validate_fn(block, config);
errors += tmp;
block->validated = tmp == 0;
}