From c6dc8e969c84b1980dcebd5dc3a59d112fa61c53 Mon Sep 17 00:00:00 2001 From: Federico Angelilli Date: Fri, 12 Jul 2024 23:08:30 +0200 Subject: Start parsing blocks --- src/config.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 182 insertions(+), 50 deletions(-) (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c index bb9c1d2..1f2698b 100644 --- a/src/config.c +++ b/src/config.c @@ -13,6 +13,12 @@ #define ANY_INI_IMPLEMENT #include "any_ini.h" +typedef enum { + CONFIG_SUCCESS, + CONFIG_INVALID, + CONFIG_UNKNOWN, +} config_status_t; + static const config_entry_t bar_entries[] = { { "width", CONFIG_UINT, offsetof(config_t, width) }, { "height", CONFIG_UINT, offsetof(config_t, height) }, @@ -23,15 +29,39 @@ static const config_entry_t bar_entries[] = { { 0 }, }; -//static const config_entry_t block_entries[] = { -// { "type", CONFIG_INT, offsetof(config_block_t, type) }, -// { "x-padding", CONFIG_UINT, offsetof(config_block_t, x_padding) }, -// { "y-padding", CONFIG_UINT, offsetof(config_block_t, y_padding) }, -// { "text-color", CONFIG_STRING, offsetof(config_block_t, text_color) }, -// { "text", CONFIG_STRING, offsetof(config_block_t, text) }, -// { "color", CONFIG_STRING, offsetof(config_block_t, color) }, -// { 0 }, -//}; +static const config_entry_t block_entries[] = { + { "hidden", CONFIG_BOOL, offsetof(block_t, hidden) }, + { "color", CONFIG_COLOR, offsetof(block_t, color) }, + { "line-color", CONFIG_COLOR, offsetof(block_t, line_color) }, + { "line-width", CONFIG_INT, offsetof(block_t, line_width) }, + { "x-padding", CONFIG_INT, offsetof(block_t, x_padding) }, + { "y-padding", CONFIG_INT, offsetof(block_t, y_padding) }, + { "min-width", CONFIG_INT, offsetof(block_t, min_width) }, + { "max-width", CONFIG_INT, offsetof(block_t, max_width) }, + { 0 }, +}; + +static const config_entry_t block_text_entries[] = { + { "text", CONFIG_STRING, offsetof(block_t, text.text) }, + { "text-color", CONFIG_COLOR, offsetof(block_t, text.text_color) }, + { "text-size", CONFIG_INT, offsetof(block_t, text.text_size) }, +}; + +static const config_block_t block_infos[] = { + { + .type_name = "text", + .type_size = 0, + .base = { 0 }, + .entries = block_text_entries, + .apply = NULL, + }, + //{ + // "group", + // 0, + // block_group_entries, + //}, + { 0 } +}; static bool config_read_string(const char *value, char **result) { @@ -143,8 +173,8 @@ static bool config_read_color(const char *value, color_t *result) return false; } -static bool config_read_entry(const config_entry_t *entries, void *result, int line, - const char *section, const char *key, const char *value) +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) { const char *types[] = { "string", @@ -155,16 +185,12 @@ static bool config_read_entry(const config_entry_t *entries, void *result, int l for (int i = 0; entries[i].key != NULL; i++) { if (!strcmp(key, entries[i].key)) { - bool nullable = entries[i].type == CONFIG_STRING; + if (type != NULL) + *type = types[entries[i].type]; - if ((value == NULL || *value == '\0') && !nullable) { - log_value_error("Invalid empty entry", - "s:section", section, - "s:key", key, - "s:expected_type", types[entries[i].type], - "i:line", line); - return false; - } + bool nullable = entries[i].type == CONFIG_STRING; + if ((value == NULL || *value == '\0') && !nullable) + return CONFIG_INVALID; result += entries[i].offset; switch (entries[i].type) { @@ -172,35 +198,35 @@ static bool config_read_entry(const config_entry_t *entries, void *result, int l // 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); - return true; + 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); - return true; + 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); - return true; + 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); - return true; + 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"); - return true; + return CONFIG_SUCCESS; } break; @@ -209,32 +235,30 @@ static bool config_read_entry(const config_entry_t *entries, void *result, int l char *color = color_to_string((color_t *)result); log_debug("Set '%s.%s' to '%s'", section, key, color); free(color); - return true; + return CONFIG_SUCCESS; } break; default: - log_panic("Unreachable"); + unreachable(); } - log_value_error("Invalid entry", - "s:section", section, - "s:key", key, - "s:value", value, - "s:expected_type", types[entries[i].type], - "i:line", line); - - return false; + return CONFIG_INVALID; } } - log_value_warn("Unknown entry", - "s:section", section, - "s:key", key, - "s:value", value, - "i:line", line); + return CONFIG_UNKNOWN; +} + +static config_status_t config_read_block(const config_block_t *info, block_t *block, void *result, 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); - return true; + if (status == CONFIG_INVALID) + return status; + + return config_read_entry(info->entries, result, type, section, key, value); } void config_init(config_t *config) @@ -257,17 +281,71 @@ void config_read(config_t *config, FILE *file) any_ini_stream_t ini; any_ini_file_init(&ini, file); - int errors = 0; + int n_errors = 0; char *section = NULL; do { + char *key = NULL, *value = NULL; + int errors = 0; + + const config_block_t *info = NULL; const config_entry_t *entries = NULL; void *result = NULL; + block_t *block = NULL; if (section != NULL) { if (!strncmp(section, "block.", 6)) { - // TODO + config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t)); + assert(config->blocks != NULL); + block = &config->blocks[config->n_blocks - 1]; + + char *label = strcopy(section + 6); + if (*label == '\0') { + ++errors; + log_value_error("Block section must have a non-empty label", + "s:section", section, + "i:line", ini.line); + free(label); + } else + block->label = label; + + if ((key = any_ini_stream_next_key(&ini)) == NULL || strcmp(key, "type")) { + ++errors; + log_value_error("Block section must start with a 'type' pair", + "s:section", section, + "s:wrong_key", key, + "i:line", ini.line); + goto skip_pair; + } + + value = any_ini_stream_next_value(&ini); + if (value == NULL) { + ++errors; + log_value_error("Block type must be non-empty", + "s:section", section, + "i:line", ini.line); + goto skip_pair; + } + + for (int i = 0; block_infos[i].type_name != NULL; i++) { + if (strcmp(block_infos[i].type_name, value)) + continue; + info = &block_infos[i]; + memcpy(block, &info->base, sizeof(block_t)); + result = !strcmp(value, "text") + ? block + : malloc(info->type_size); + + goto skip_pair; + } + + ++errors; + log_value_error("Block type not supported", + "s:section", section, + "s:type", value, + "i:line", ini.line); + goto skip_pair; } else if (!strncmp(section, "action.", 7)) { // TODO } else if (!strcmp(section, "bar")) { @@ -277,9 +355,8 @@ void config_read(config_t *config, FILE *file) log_warn("Unknown section '%s'", section); } - char *key; while ((key = any_ini_stream_next_key(&ini)) != NULL) { - char *value = any_ini_stream_next_value(&ini); + value = any_ini_stream_next_value(&ini); log_value_trace("Reading entry", "s:section", section, @@ -287,23 +364,74 @@ void config_read(config_t *config, FILE *file) "s:value", value, "i:line", ini.line); - if (entries != NULL) - errors += !config_read_entry(entries, result, ini.line, section, key, value); + const char *type; + config_status_t status; + + if (block != NULL) + status = config_read_block(info, &config->blocks[config->n_blocks - 1], result, + &type, section, key, value); + else if (entries != NULL) + status = config_read_entry(entries, result, &type, section, key, value); + + if (block != NULL || entries != NULL) { + switch (status) { + case CONFIG_SUCCESS: + break; + + case CONFIG_INVALID: + errors++; + log_value_error("Invalid entry", + "s:section", section, + "s:key", key, + "s:value", value, + "s:type", type, + "i:line", ini.line); + break; + + case CONFIG_UNKNOWN: + log_value_warn("Unknown entry", + "s:section", section, + "s:key", key, + "s:value", value, + "i:line", ini.line); + break; + + default: + unreachable(); + } + } + +skip_pair: free(key); free(value); } + if (block != NULL && info->apply != NULL) { + if (errors != 0) + log_trace("Skipped '%s' apply for '%s'", info->type_name, section); + else + errors += !info->apply(block, result); + } + free(section); + n_errors += errors; } while ((section = any_ini_stream_next_section(&ini)) != NULL); - if (errors > 0) - log_panic("Config file contained %d errors", errors); + if (n_errors > 0) + log_panic("Config file contained %d errors", n_errors); } void config_resolve(config_t *config, block_t *block) { - int errors = 1; + int errors = 0; + + block->type = BLOCK_GROUP; + block->group.n_children = config->n_blocks; + block->group.children = malloc(config->n_blocks * sizeof(block_t *)); + + for (int i = 0; i < config->n_blocks; i++) + block->group.children[i] = &config->blocks[i]; if (errors > 0) log_panic("Config could not be resolved"); @@ -311,6 +439,10 @@ void config_resolve(config_t *config, block_t *block) void config_free(config_t *config) { + for (int i = 0; i < config->n_blocks; i++) + block_free(&config->blocks[i]); + + free(config->blocks); free(config->font); free(config->monitor); } -- cgit v1.2.3