diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/block.c | 12 | ||||
| -rw-r--r-- | src/block.h | 12 | ||||
| -rw-r--r-- | src/config.c | 232 | ||||
| -rw-r--r-- | src/config.h | 12 | ||||
| -rw-r--r-- | src/layout.c | 4 | ||||
| -rw-r--r-- | src/util.c | 6 | ||||
| -rw-r--r-- | src/util.h | 2 |
7 files changed, 218 insertions, 62 deletions
diff --git a/src/block.c b/src/block.c index 2b31de8..bfe2ec5 100644 --- a/src/block.c +++ b/src/block.c @@ -22,7 +22,7 @@ void block_update(block_t *block) if (block->type == BLOCK_GROUP) { for (int i = 0; i < block->group.n_children; i++) - block_update(&block->group.children[i]); + block_update(block->group.children[i]); } } @@ -36,10 +36,12 @@ void block_copy(block_t *copy, const block_t *block) if (block->type == BLOCK_TEXT) { copy->text.text = strcopy(block->text.text); } else if (block->type == BLOCK_GROUP) { - copy->group.children = calloc(block->group.n_children, sizeof(block_t)); + copy->group.children = calloc(block->group.n_children, sizeof(block_t *)); - for (int i = 0; i < block->group.n_children; i++) - block_copy(&block->group.children[i], ©->group.children[i]); + for (int i = 0; i < block->group.n_children; i++) { + block->group.children[i] = malloc(sizeof(block_t)); + block_copy(block->group.children[i], copy->group.children[i]); + } } } @@ -51,7 +53,7 @@ void block_free(block_t *block) free(block->text.text); } else if (block->type == BLOCK_GROUP) { for (int i = 0; i < block->group.n_children; i++) - block_free(&block->group.children[i]); + block_free(block->group.children[i]); free(block->group.children); } diff --git a/src/block.h b/src/block.h index 9468373..9c663b1 100644 --- a/src/block.h +++ b/src/block.h @@ -38,16 +38,18 @@ typedef void (*block_update_t)(block_t *block); struct block { block_type_t type; char *label; + bool active; + struct timespec update_interval; + struct timespec update_last; + block_update_t update_cb; + block_event_t event_cb; + bool hidden; color_t color; color_t line_color; int line_width; int x_padding, y_padding; int min_width, max_width; - struct timespec update_interval; - struct timespec update_last; - block_update_t update_cb; - block_event_t event_cb; union { struct { char *text; @@ -58,7 +60,7 @@ struct block { struct { int spacing; int n_children; - struct block *children; + struct block **children; } group; }; }; 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); } diff --git a/src/config.h b/src/config.h index 70c828c..d76c515 100644 --- a/src/config.h +++ b/src/config.h @@ -21,7 +21,19 @@ typedef struct { size_t offset; } config_entry_t; +typedef bool (*config_block_apply_t)(block_t *block, void *result); + +typedef struct { + const char *type_name; + size_t type_size; + block_t base; + const config_entry_t *entries; + config_block_apply_t apply; +} config_block_t; + typedef struct { + size_t n_blocks; + block_t *blocks; char *font; char *monitor; uint32_t height; diff --git a/src/layout.c b/src/layout.c index ce6b281..0b0f826 100644 --- a/src/layout.c +++ b/src/layout.c @@ -24,10 +24,10 @@ void layout_init(layout_t *layout, block_t *block, layout_info_t info) layout->children = calloc(block->group.n_children, sizeof(layout_t)); for (int i = 0; i < block->group.n_children; i++) { - if (block->group.children[i].hidden) + if (block->group.children[i]->hidden) continue; - layout_init(&layout->children[layout->n_children], &block->group.children[i], info); + layout_init(&layout->children[layout->n_children], block->group.children[i], info); info.x_offset += layout->children[layout->n_children].width + block->group.spacing; layout->n_children++; } @@ -4,6 +4,7 @@ #include <stdio.h> #include "util.h" +#include "any_log.h" void pair_copy(pair_t *copy, const pair_t *pair) { @@ -106,3 +107,8 @@ char *strcopy(const char *string) return strslice(string, 0, strlen(string)); } + +void unreachable(void) +{ + log_panic("Unreachable"); +} @@ -55,4 +55,6 @@ char *strslice(const char *string, size_t start, size_t end); char *strcopy(const char *string); +void unreachable(void); + #endif |
