diff options
Diffstat (limited to 'src/config.c')
| -rw-r--r-- | src/config.c | 269 |
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; } |
