config: verify: expose verification primitives

This commit is contained in:
Daniel Eklöf 2019-01-12 11:46:26 +01:00
parent 6cb2f52328
commit d44db1a6a8
2 changed files with 128 additions and 116 deletions

View file

@ -1,4 +1,4 @@
#include "config-verify.h" #include "config.h"
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@ -8,27 +8,6 @@
#include "log.h" #include "log.h"
#include "tllist.h" #include "tllist.h"
typedef tll(const char *) keychain_t;
struct attr_info {
const char *name;
bool required;
bool (*verify)(keychain_t *chain, const struct yml_node *node);
};
static keychain_t *
chain_push(keychain_t *chain, const char *key)
{
tll_push_back(*chain, key);
return chain;
}
static void
chain_pop(keychain_t *chain)
{
tll_pop_back(*chain);
}
static const char * static const char *
err_prefix(const keychain_t *chain, const struct yml_node *node) err_prefix(const keychain_t *chain, const struct yml_node *node)
{ {
@ -46,8 +25,8 @@ err_prefix(const keychain_t *chain, const struct yml_node *node)
return msg; return msg;
} }
static bool bool
verify_string(keychain_t *chain, const struct yml_node *node) conf_verify_string(keychain_t *chain, const struct yml_node *node)
{ {
const char *s = yml_value_as_string(node); const char *s = yml_value_as_string(node);
if (s == NULL) { if (s == NULL) {
@ -58,8 +37,8 @@ verify_string(keychain_t *chain, const struct yml_node *node)
return true; return true;
} }
static bool bool
verify_int(keychain_t *chain, const struct yml_node *node) conf_verify_int(keychain_t *chain, const struct yml_node *node)
{ {
if (yml_value_is_int(node)) if (yml_value_is_int(node))
return true; return true;
@ -69,9 +48,9 @@ verify_int(keychain_t *chain, const struct yml_node *node)
return false; return false;
} }
static bool bool
verify_enum(keychain_t *chain, const struct yml_node *node, conf_verify_enum(keychain_t *chain, const struct yml_node *node,
const char *values[], size_t count) const char *values[], size_t count)
{ {
const char *s = yml_value_as_string(node); const char *s = yml_value_as_string(node);
if (s == NULL) { if (s == NULL) {
@ -91,9 +70,9 @@ verify_enum(keychain_t *chain, const struct yml_node *node,
return false; return false;
} }
static bool bool
verify_dict(keychain_t *chain, const struct yml_node *node, conf_verify_dict(keychain_t *chain, const struct yml_node *node,
const struct attr_info info[], size_t count) const struct attr_info info[], size_t count)
{ {
if (!yml_is_dict(node)) { if (!yml_is_dict(node)) {
LOG_ERR("%s: must be a dictionary", err_prefix(chain, node)); LOG_ERR("%s: must be a dictionary", err_prefix(chain, node));
@ -146,8 +125,8 @@ verify_dict(keychain_t *chain, const struct yml_node *node,
return true; return true;
} }
static bool bool
verify_color(keychain_t *chain, const struct yml_node *node) conf_verify_color(keychain_t *chain, const struct yml_node *node)
{ {
const char *s = yml_value_as_string(node); const char *s = yml_value_as_string(node);
if (s == NULL) { if (s == NULL) {
@ -168,14 +147,14 @@ verify_color(keychain_t *chain, const struct yml_node *node)
} }
static bool bool
verify_font(keychain_t *chain, const struct yml_node *node) conf_verify_font(keychain_t *chain, const struct yml_node *node)
{ {
static const struct attr_info attrs[] = { static const struct attr_info attrs[] = {
{"family", true, &verify_string}, {"family", true, &conf_verify_string},
}; };
return verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0])); return conf_verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
} }
static bool verify_decoration(keychain_t *chain, const struct yml_node *node); static bool verify_decoration(keychain_t *chain, const struct yml_node *node);
@ -227,12 +206,12 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
} }
static const struct attr_info background[] = { static const struct attr_info background[] = {
{"color", true, &verify_color}, {"color", true, &conf_verify_color},
}; };
static const struct attr_info underline[] = { static const struct attr_info underline[] = {
{"size", true, &verify_int}, {"size", true, &conf_verify_int},
{"color", true, &verify_color}, {"color", true, &conf_verify_color},
}; };
static const struct { static const struct {
@ -248,7 +227,7 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
if (strcmp(decos[i].name, deco_name) != 0) if (strcmp(decos[i].name, deco_name) != 0)
continue; continue;
if (!verify_dict(chain_push(chain, deco_name), if (!conf_verify_dict(chain_push(chain, deco_name),
values, decos[i].attrs, decos[i].count)) values, decos[i].attrs, decos[i].count))
{ {
return false; return false;
@ -263,8 +242,6 @@ verify_decoration(keychain_t *chain, const struct yml_node *node)
return false; return false;
} }
static bool verify_particle(keychain_t *chain, const struct yml_node *node);
static bool static bool
verify_list_items(keychain_t *chain, const struct yml_node *node) verify_list_items(keychain_t *chain, const struct yml_node *node)
{ {
@ -274,7 +251,7 @@ verify_list_items(keychain_t *chain, const struct yml_node *node)
it.node != NULL; it.node != NULL;
yml_list_next(&it)) yml_list_next(&it))
{ {
if (!verify_particle(chain, it.node)) if (!conf_verify_particle(chain, it.node))
return false; return false;
} }
@ -302,7 +279,7 @@ verify_map_values(keychain_t *chain, const struct yml_node *node)
return false; return false;
} }
if (!verify_particle(chain_push(chain, key), it.value)) if (!conf_verify_particle(chain_push(chain, key), it.value))
return false; return false;
chain_pop(chain); chain_pop(chain);
@ -312,7 +289,7 @@ verify_map_values(keychain_t *chain, const struct yml_node *node)
} }
static bool static bool
verify_particle_dictionary(keychain_t *chain, const struct yml_node *node) conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
{ {
assert(yml_is_dict(node)); assert(yml_is_dict(node));
@ -333,10 +310,10 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
} }
#define COMMON_ATTRS \ #define COMMON_ATTRS \
{"margin", false, &verify_int}, \ {"margin", false, &conf_verify_int}, \
{"left-margin", false, &verify_int}, \ {"left-margin", false, &conf_verify_int}, \
{"right-margin", false, &verify_int}, \ {"right-margin", false, &conf_verify_int}, \
{"on-click", false, &verify_string}, {"on-click", false, &conf_verify_string},
static const struct attr_info empty[] = { static const struct attr_info empty[] = {
COMMON_ATTRS COMMON_ATTRS
@ -344,42 +321,42 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
static const struct attr_info list[] = { static const struct attr_info list[] = {
{"items", true, &verify_list_items}, {"items", true, &verify_list_items},
{"spacing", false, &verify_int}, {"spacing", false, &conf_verify_int},
{"left-spacing", false, &verify_int}, {"left-spacing", false, &conf_verify_int},
{"right-spacing", false, &verify_int}, {"right-spacing", false, &conf_verify_int},
COMMON_ATTRS COMMON_ATTRS
}; };
static const struct attr_info map[] = { static const struct attr_info map[] = {
{"tag", true, &verify_string}, {"tag", true, &conf_verify_string},
{"values", true, &verify_map_values}, {"values", true, &verify_map_values},
{"default", false, &verify_particle}, {"default", false, &conf_verify_particle},
COMMON_ATTRS COMMON_ATTRS
}; };
static const struct attr_info progress_bar[] = { static const struct attr_info progress_bar[] = {
{"tag", true, &verify_string}, {"tag", true, &conf_verify_string},
{"length", true, &verify_int}, {"length", true, &conf_verify_int},
/* TODO: make these optional? Default to empty */ /* TODO: make these optional? Default to empty */
{"start", true, &verify_particle}, {"start", true, &conf_verify_particle},
{"end", true, &verify_particle}, {"end", true, &conf_verify_particle},
{"fill", true, &verify_particle}, {"fill", true, &conf_verify_particle},
{"empty", true, &verify_particle}, {"empty", true, &conf_verify_particle},
{"indicator", true, &verify_particle}, {"indicator", true, &conf_verify_particle},
COMMON_ATTRS COMMON_ATTRS
}; };
static const struct attr_info ramp[] = { static const struct attr_info ramp[] = {
{"tag", true, &verify_string}, {"tag", true, &conf_verify_string},
{"items", true, &verify_list_items}, {"items", true, &verify_list_items},
COMMON_ATTRS COMMON_ATTRS
}; };
static const struct attr_info string[] = { static const struct attr_info string[] = {
{"text", true, &verify_string}, {"text", true, &conf_verify_string},
{"max", false, &verify_int}, {"max", false, &conf_verify_int},
{"font", false, &verify_font}, {"font", false, &conf_verify_font},
{"foreground", false, &verify_color}, {"foreground", false, &conf_verify_color},
{"deco", false, &verify_decoration}, {"deco", false, &verify_decoration},
COMMON_ATTRS COMMON_ATTRS
}; };
@ -403,7 +380,7 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
if (strcmp(particles[i].name, particle_name) != 0) if (strcmp(particles[i].name, particle_name) != 0)
continue; continue;
if (!verify_dict(chain_push(chain, particle_name), values, if (!conf_verify_dict(chain_push(chain, particle_name), values,
particles[i].attrs, particles[i].count)) particles[i].attrs, particles[i].count))
{ {
return false; return false;
@ -418,11 +395,11 @@ verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
return false; return false;
} }
static bool bool
verify_particle(keychain_t *chain, const struct yml_node *node) conf_verify_particle(keychain_t *chain, const struct yml_node *node)
{ {
if (yml_is_dict(node)) if (yml_is_dict(node))
return verify_particle_dictionary(chain, node); return conf_verify_particle_dictionary(chain, node);
else if (yml_is_list(node)) else if (yml_is_list(node))
return verify_list_items(chain, node); return verify_list_items(chain, node);
else { else {
@ -453,7 +430,7 @@ verify_i3_content(keychain_t *chain, const struct yml_node *node)
return false; return false;
} }
if (!verify_particle(chain_push(chain, key), it.value)) if (!conf_verify_particle(chain_push(chain, key), it.value))
return false; return false;
chain_pop(chain); chain_pop(chain);
@ -482,73 +459,73 @@ verify_module(keychain_t *chain, const struct yml_node *node)
} }
static const struct attr_info alsa[] = { static const struct attr_info alsa[] = {
{"card", true, &verify_string}, {"card", true, &conf_verify_string},
{"mixer", true, &verify_string}, {"mixer", true, &conf_verify_string},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info backlight[] = { static const struct attr_info backlight[] = {
{"name", true, &verify_string}, {"name", true, &conf_verify_string},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info battery[] = { static const struct attr_info battery[] = {
{"name", true, &verify_string}, {"name", true, &conf_verify_string},
{"poll-interval", false, &verify_int}, {"poll-interval", false, &conf_verify_int},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info clock[] = { static const struct attr_info clock[] = {
{"date-format", false, &verify_string}, {"date-format", false, &conf_verify_string},
{"time-format", false, &verify_string}, {"time-format", false, &conf_verify_string},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info label[] = { static const struct attr_info label[] = {
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info mpd[] = { static const struct attr_info mpd[] = {
{"host", true, &verify_string}, {"host", true, &conf_verify_string},
{"port", false, &verify_int}, {"port", false, &conf_verify_int},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info i3[] = { static const struct attr_info i3[] = {
{"spacing", false, &verify_int}, {"spacing", false, &conf_verify_int},
{"left-spacing", false, &verify_int}, {"left-spacing", false, &conf_verify_int},
{"right-spacing", false, &verify_int}, {"right-spacing", false, &conf_verify_int},
{"content", true, &verify_i3_content}, {"content", true, &verify_i3_content},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info network[] = { static const struct attr_info network[] = {
{"name", true, &verify_string}, {"name", true, &conf_verify_string},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info removables[] = { static const struct attr_info removables[] = {
{"spacing", false, &verify_int}, {"spacing", false, &conf_verify_int},
{"left-spacing", false, &verify_int}, {"left-spacing", false, &conf_verify_int},
{"right-spacing", false, &verify_int}, {"right-spacing", false, &conf_verify_int},
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info xkb[] = { static const struct attr_info xkb[] = {
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
static const struct attr_info xwindow[] = { static const struct attr_info xwindow[] = {
{"content", true, &verify_particle}, {"content", true, &conf_verify_particle},
{"anchors", false, NULL}, {"anchors", false, NULL},
}; };
@ -574,7 +551,7 @@ verify_module(keychain_t *chain, const struct yml_node *node)
if (strcmp(modules[i].name, mod_name) != 0) if (strcmp(modules[i].name, mod_name) != 0)
continue; continue;
if (!verify_dict(chain_push(chain, mod_name), values, if (!conf_verify_dict(chain_push(chain, mod_name), values,
modules[i].attrs, modules[i].count)) modules[i].attrs, modules[i].count))
{ {
return false; return false;
@ -611,21 +588,21 @@ static bool
verify_bar_border(keychain_t *chain, const struct yml_node *node) verify_bar_border(keychain_t *chain, const struct yml_node *node)
{ {
static const struct attr_info attrs[] = { static const struct attr_info attrs[] = {
{"width", true, &verify_int}, {"width", true, &conf_verify_int},
{"color", true, &verify_color}, {"color", true, &conf_verify_color},
}; };
return verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0])); return conf_verify_dict(chain, node, attrs, sizeof(attrs) / sizeof(attrs[0]));
} }
static bool static bool
verify_bar_location(keychain_t *chain, const struct yml_node *node) verify_bar_location(keychain_t *chain, const struct yml_node *node)
{ {
return verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2); return conf_verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2);
} }
bool bool
config_verify_bar(const struct yml_node *bar) conf_verify_bar(const struct yml_node *bar)
{ {
if (!yml_is_dict(bar)) { if (!yml_is_dict(bar)) {
LOG_ERR("bar is not a dictionary"); LOG_ERR("bar is not a dictionary");
@ -636,27 +613,27 @@ config_verify_bar(const struct yml_node *bar)
chain_push(&chain, "bar"); chain_push(&chain, "bar");
static const struct attr_info attrs[] = { static const struct attr_info attrs[] = {
{"height", true, &verify_int}, {"height", true, &conf_verify_int},
{"location", true, &verify_bar_location}, {"location", true, &verify_bar_location},
{"background", true, &verify_color}, {"background", true, &conf_verify_color},
{"spacing", false, &verify_int}, {"spacing", false, &conf_verify_int},
{"left-spacing", false, &verify_int}, {"left-spacing", false, &conf_verify_int},
{"right-spacing", false, &verify_int}, {"right-spacing", false, &conf_verify_int},
{"margin", false, &verify_int}, {"margin", false, &conf_verify_int},
{"left_margin", false, &verify_int}, {"left_margin", false, &conf_verify_int},
{"right_margin", false, &verify_int}, {"right_margin", false, &conf_verify_int},
{"border", false, &verify_bar_border}, {"border", false, &verify_bar_border},
{"font", false, &verify_font}, {"font", false, &conf_verify_font},
{"left", false, &verify_module_list}, {"left", false, &verify_module_list},
{"center", false, &verify_module_list}, {"center", false, &verify_module_list},
{"right", false, &verify_module_list}, {"right", false, &verify_module_list},
}; };
bool ret = verify_dict(&chain, bar, attrs, sizeof(attrs) / sizeof(attrs[0])); bool ret = conf_verify_dict(&chain, bar, attrs, sizeof(attrs) / sizeof(attrs[0]));
tll_free(chain); tll_free(chain);
return ret; return ret;
} }

View file

@ -1,5 +1,40 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include "tllist.h"
#include "yml.h" #include "yml.h"
bool config_verify_bar(const struct yml_node *bar); typedef tll(const char *) keychain_t;
struct attr_info {
const char *name;
bool required;
bool (*verify)(keychain_t *chain, const struct yml_node *node);
};
static inline keychain_t *
chain_push(keychain_t *chain, const char *key)
{
tll_push_back(*chain, key);
return chain;
}
static inline void
chain_pop(keychain_t *chain)
{
tll_pop_back(*chain);
}
bool conf_verify_string(keychain_t *chain, const struct yml_node *node);
bool conf_verify_int(keychain_t *chain, const struct yml_node *node);
bool conf_verify_enum(keychain_t *chain, const struct yml_node *node,
const char *values[], size_t count);
bool conf_verify_dict(keychain_t *chain, const struct yml_node *node,
const struct attr_info info[], size_t count);
bool conf_verify_color(keychain_t *chain, const struct yml_node *node);
bool conf_verify_font(keychain_t *chain, const struct yml_node *node);
bool conf_verify_particle(keychain_t *chain, const struct yml_node *node);