summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/common.c b/common.c
index 0981ed5..c4e9f08 100644
--- a/common.c
+++ b/common.c
@@ -488,6 +488,18 @@ toupper_ascii (int c)
return c >= 'A' && c <= 'Z' ? c : c - ('a' - 'A');
}
+static void
+split_str (const char *s, char delimiter, struct str_vector *out)
+{
+ const char *begin = s, *end;
+ while ((end = strchr (begin, delimiter)))
+ {
+ str_vector_add_owned (out, xstrndup (begin, end - begin));
+ begin = ++end;
+ }
+ str_vector_add (out, begin);
+}
+
// --- Advanced configuration --------------------------------------------------
// This is a new configuration format, superseding the one currently present
@@ -718,10 +730,33 @@ config_item_set_from (struct config_item_ *self, struct config_item_ *source,
}
static struct config_item_ *
-config_item_get (struct config_item_ *self, const char *path)
+config_item_get (struct config_item_ *self, const char *path, struct error **e)
{
hard_assert (self->type == CONFIG_ITEM_OBJECT);
- // TODO
+
+ struct str_vector v;
+ str_vector_init (&v);
+ split_str (path, '.', &v);
+
+ struct config_item_ *result = NULL;
+ size_t i = 0;
+ while (true)
+ {
+ const char *key = v.vector[i];
+ if (!*key)
+ error_set (e, "empty path element");
+ else if (!(self = str_map_find (&self->value.object, key)))
+ error_set (e, "`%s' not found in object", key);
+ else if (++i == v.len)
+ result = self;
+ else if (self->type != CONFIG_ITEM_OBJECT)
+ error_set (e, "`%s' is not an object", key);
+ else
+ continue;
+ break;
+ }
+ str_vector_free (&v);
+ return result;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -