aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-07-12 23:08:30 +0200
committerFederico Angelilli <code@fedang.net>2024-07-12 23:08:30 +0200
commitc6dc8e969c84b1980dcebd5dc3a59d112fa61c53 (patch)
tree3ed902af74b7122c5424117b041442a558e35e3c /src
parentaac1310ed0b9983a4a4a29ac469405d70465c278 (diff)
Start parsing blocks
Diffstat (limited to 'src')
-rw-r--r--src/block.c12
-rw-r--r--src/block.h12
-rw-r--r--src/config.c232
-rw-r--r--src/config.h12
-rw-r--r--src/layout.c4
-rw-r--r--src/util.c6
-rw-r--r--src/util.h2
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], &copy->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++;
}
diff --git a/src/util.c b/src/util.c
index 6180a5f..044ce70 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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");
+}
diff --git a/src/util.h b/src/util.h
index 78d530e..f0e208b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -55,4 +55,6 @@ char *strslice(const char *string, size_t start, size_t end);
char *strcopy(const char *string);
+void unreachable(void);
+
#endif