aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/block.h2
-rw-r--r--src/config.c271
-rw-r--r--src/config.h8
3 files changed, 197 insertions, 84 deletions
diff --git a/src/block.h b/src/block.h
index 715e6c4..845ccfd 100644
--- a/src/block.h
+++ b/src/block.h
@@ -44,7 +44,7 @@ typedef void (*block_finalize_t)(block_t *block);
struct block {
block_type_t type;
char *label;
- bool active;
+ bool resolved;
bool hidden;
void *state;
struct timespec update_interval;
diff --git a/src/config.c b/src/config.c
index cea99af..93d123f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -23,10 +23,12 @@ typedef enum {
static const config_entry_t bar_entries[] = {
{ "width", CONFIG_UINT, NULL, offsetof(config_t, width) },
{ "height", CONFIG_UINT, NULL, offsetof(config_t, height) },
+ { "spacing", CONFIG_UINT, NULL, offsetof(config_t, spacing) },
{ "font", CONFIG_STRING, NULL, offsetof(config_t, font) },
{ "monitor", CONFIG_STRING, NULL, offsetof(config_t, monitor) },
{ "override-redirect", CONFIG_BOOL, NULL, offsetof(config_t, override_redirect) },
{ "background", CONFIG_COLOR, NULL, offsetof(config_t, background) },
+ { "blocks", CONFIG_LIST, NULL, offsetof(config_t, children) },
{ 0 },
};
@@ -44,7 +46,8 @@ static const config_entry_t block_entries[] = {
};
static const config_entry_t block_group_entries[] = {
- { "spacing", CONFIG_INT, NULL, offsetof(block_t, group.spacing) },
+ { "spacing", CONFIG_INT, NULL, offsetof(block_t, group.spacing) },
+ { "blocks", CONFIG_LIST, NULL, offsetof(block_t, group.children) },
{ 0 },
};
@@ -197,10 +200,124 @@ static bool config_read_time(const char *value, struct timespec *result)
return false;
}
+// TODO: Handle quotation marks
+static bool config_read_list(const char *value, char ***result)
+{
+ size_t count = 0;
+ for (size_t i = 0; value[i] != '\0'; ++i)
+ count += value[i] == ',';
+
+ char **list = calloc(count + 2, sizeof(char *));
+ size_t n = 0;
+
+ char *state, *copy = strcopy(value);
+ for (char *string = copy; ; string = NULL) {
+ char *token = strtok_r(string, ",", &state);
+
+ if (token == NULL)
+ break;
+
+ while (isspace(*token)) token++;
+ char *end = token + strlen(token);
+ while (isspace(*end)) end--;
+ *end = '\0';
+
+ if (!config_read_string(token, &list[n++])) {
+ free(list);
+ return false;
+ }
+ }
+
+ list[n] = NULL;
+ *result = list;
+ return true;
+}
+
+static config_status_t config_read_any(void *result, config_type_t type, void *data,
+ const char *section, const char *key, const char *value)
+{
+ bool nullable = type == CONFIG_STRING;
+ if ((value == NULL || *value == '\0') && !nullable)
+ return CONFIG_INVALID;
+
+ switch (type) {
+ 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);
+ 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 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 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 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 CONFIG_SUCCESS;
+ }
+ break;
+
+ 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);
+ free(color);
+ return CONFIG_SUCCESS;
+ }
+ break;
+
+ case CONFIG_ENUM:
+ if (config_read_enum(value, (config_enum_t *)data, (int *)result)) {
+ log_debug("Set '%s.%s' to '%d'", section, 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);
+ return CONFIG_SUCCESS;
+ }
+ break;
+
+ case CONFIG_LIST:
+ if (config_read_list(value, (char ***)result)) {
+ log_debug("Set '%s.%s' to '%s'", section, key, value);
+ return CONFIG_SUCCESS;
+ }
+ break;
+
+ default:
+ unreachable();
+ }
+
+ return CONFIG_INVALID;
+}
+
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[] = {
+ static const char *types[] = {
"string",
"integer",
"unsigned integer",
@@ -209,6 +326,7 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
"color",
"enum",
"time",
+ "list",
};
for (int i = 0; entries[i].key != NULL; i++) {
@@ -216,76 +334,8 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re
if (type != NULL)
*type = types[entries[i].type];
- bool nullable = entries[i].type == CONFIG_STRING;
- if ((value == NULL || *value == '\0') && !nullable)
- return CONFIG_INVALID;
-
result += entries[i].offset;
- switch (entries[i].type) {
- 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);
- 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 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 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 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 CONFIG_SUCCESS;
- }
- break;
-
- 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);
- free(color);
- return CONFIG_SUCCESS;
- }
- break;
-
- 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);
- 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);
- return CONFIG_SUCCESS;
- }
- break;
-
- default:
- unreachable();
- }
-
- return CONFIG_INVALID;
+ return config_read_any(result, entries[i].type, entries[i].data, section, key, value);
}
}
@@ -313,6 +363,7 @@ void config_init(config_t *config)
.monitor = NULL,
.height = 50,
.width = 100,
+ .spacing = 10,
.override_redirect = false,
};
@@ -344,12 +395,20 @@ void config_read(config_t *config, FILE *file)
block = &config->blocks[config->n_blocks - 1];
char *label = strcopy(section + 6);
- if (label == NULL || *label == '\0') {
+ if (label == NULL || *label == '\0' || !strcmp(label, "bar")) {
++errors;
- log_value_error("Block section must have a non-empty label",
+ log_value_error("Block section must have a valid label",
"s:section", section,
"i:line", ini.line);
- free(label);
+ } else {
+ for (size_t i = 0; i < config->n_blocks - 1; i++) {
+ if (!strcmp(label, config->blocks[i].label)) {
+ ++errors;
+ log_value_error("Block section must have a unique label",
+ "s:section", section,
+ "i:line", ini.line);
+ }
+ }
}
if ((key = any_ini_stream_next_key(&ini)) == NULL || strcmp(key, "type")) {
@@ -468,19 +527,69 @@ skip_pair:
log_panic("Config file contained %d errors", n_errors);
}
+static bool config_resolve_children(config_t *config, block_t *block)
+{
+ block->resolved = true;
+ if (block->type == BLOCK_TEXT)
+ return true;
+
+ char **children = (char **)block->group.children;
+ block->group.children = NULL;
+ block->group.n_children = 0;
+
+ if (children == NULL)
+ return true;
+
+ size_t n = 0;
+ for ( ; children[n] != NULL; n++);
+
+ block->group.n_children = n;
+ block->group.children = malloc(n * sizeof(block_t *));
+
+ for (size_t i = 0; i < n; i++) {
+ for (size_t j = 0; j < config->n_blocks; j++) {
+ if (&config->blocks[j] == block)
+ continue;
+
+ if (!strcmp(children[i], config->blocks[j].label)) {
+ if (config->blocks[j].resolved) {
+ log_error("Block '%s' can only be referenced by one block", config->blocks[j].label);
+ return false;
+ }
+
+ log_debug("Block '%s' is parent to '%s'", block->label, config->blocks[j].label);
+ block->group.children[i] = &config->blocks[j];
+
+ if (!config_resolve_children(config, &config->blocks[j]))
+ return false;
+ goto next;
+ }
+ }
+
+ log_error("Block '%s' not found", children[i]);
+ return false;
+next:
+ }
+
+ return true;
+}
+
void config_resolve(config_t *config, block_t *block)
{
int errors = 0;
- block->label = strcopy("main");
+ block->label = strcopy("bar");
block->type = BLOCK_GROUP;
block->min_width = block->max_width = config->width;
- block->group.spacing = 10;
- 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];
+ block->group.spacing = config->spacing;
+ block->group.children = (void *)config->children;
+
+ if (config->children == NULL) {
+ errors++;
+ log_error("Config should specify at least one block");
+ } else {
+ errors += !config_resolve_children(config, block);
+ }
if (errors > 0)
log_panic("Config could not be resolved");
diff --git a/src/config.h b/src/config.h
index 1e674d9..726006e 100644
--- a/src/config.h
+++ b/src/config.h
@@ -17,6 +17,7 @@ typedef enum {
CONFIG_COLOR,
CONFIG_ENUM,
CONFIG_TIME,
+ CONFIG_LIST,
} config_type_t;
typedef struct {
@@ -31,10 +32,13 @@ typedef struct {
block_t *blocks;
char *font;
char *monitor;
- uint32_t height;
- uint32_t width;
bool override_redirect;
color_t background;
+
+ uint32_t height;
+ uint32_t width;
+ uint32_t spacing;
+ char **children;
} config_t;
typedef struct {