From f28dd96c30c1b27efcbb836724f73f0797aa88e8 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 27 Mar 2017 12:38:19 +0200 Subject: [PATCH] added json_to_config in order to support JSON as new config file format --- lib/utils.c | 86 ++++++++++++++++++++++++++++++++-- tests/unit/Makefile.inc | 2 +- tests/unit/config_json.c | 99 ++++++++++++++++++++++++++++++++++++++++ tools/Makefile.inc | 19 +++++++- tools/conf2json.c | 51 +++++++++++++++++++++ 5 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 tests/unit/config_json.c create mode 100644 tools/conf2json.c diff --git a/lib/utils.c b/lib/utils.c index f43e6f78c..83111f891 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -241,6 +241,22 @@ char *cpulist_create(char *str, size_t len, cpu_set_t *set) } #ifdef WITH_JANSSON +static int json_to_config_type(int type) +{ + switch (type) { + case JSON_OBJECT: return CONFIG_TYPE_GROUP; + case JSON_ARRAY: return CONFIG_TYPE_LIST; + case JSON_STRING: return CONFIG_TYPE_STRING; + case JSON_INTEGER: return CONFIG_TYPE_INT64; + case JSON_REAL: return CONFIG_TYPE_FLOAT; + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: return CONFIG_TYPE_BOOL; + } + + return -1; +} + json_t * config_to_json(config_setting_t *cfg) { switch (config_setting_type(cfg)) { @@ -263,19 +279,83 @@ json_t * config_to_json(config_setting_t *cfg) case CONFIG_TYPE_GROUP: { json_t *json = json_object(); - for (int i = 0; i < config_setting_length(cfg); i++) + for (int i = 0; i < config_setting_length(cfg); i++) { json_object_set_new(json, config_setting_name(config_setting_get_elem(cfg, i)), config_to_json(config_setting_get_elem(cfg, i)) ); - + } + return json; } - + default: return json_object(); } } + +int json_to_config(json_t *json, config_setting_t *parent) +{ + config_setting_t *cfg; + int ret, type; + + if (config_setting_is_root(parent)) { + if (!json_is_object(json)) + return -1; /* The root must be an object! */ + } + + switch (json_typeof(json)) { + case JSON_OBJECT: { + const char *key; + json_t *json_value; + + json_object_foreach(json, key, json_value) { + type = json_to_config_type(json_typeof(json_value)); + + cfg = config_setting_add(parent, key, type); + ret = json_to_config(json_value, cfg); + if (ret) + return ret; + } + break; + } + + case JSON_ARRAY: { + size_t i; + json_t *json_value; + + json_array_foreach(json, i, json_value) { + type = json_to_config_type(json_typeof(json_value)); + + cfg = config_setting_add(parent, NULL, type); + ret = json_to_config(json_value, cfg); + if (ret) + return ret; + } + break; + } + + case JSON_STRING: + config_setting_set_string(parent, json_string_value(json)); + break; + + case JSON_INTEGER: + config_setting_set_int64(parent, json_integer_value(json)); + break; + + case JSON_REAL: + config_setting_set_float(parent, json_real_value(json)); + break; + + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + config_setting_set_bool(parent, json_is_true(json)); + break; + } + + return 0; +} #endif void * alloc(size_t bytes) diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc index 165f1e950..98b54dd77 100644 --- a/tests/unit/Makefile.inc +++ b/tests/unit/Makefile.inc @@ -3,7 +3,7 @@ TEST_OBJS = $(patsubst %.c,$(BUILDDIR)/%.o,$(TEST_SRCS)) TEST_CFLAGS = $(CFLAGS) TEST_LDFLAGS = $(LDFLAGS) -Wl,-rpath,'$$ORIGIN' -TEST_LDLIBS = $(LDLIBS) -lcriterion -lvillas -pthread +TEST_LDLIBS = $(LDLIBS) -lcriterion -lvillas -pthread -ljansson unit-tests: $(BUILDDIR)/unit-tests diff --git a/tests/unit/config_json.c b/tests/unit/config_json.c new file mode 100644 index 000000000..10c67ff32 --- /dev/null +++ b/tests/unit/config_json.c @@ -0,0 +1,99 @@ +/** Unit tests libconfig to jansson converters. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#include + +#include +#include + +#include "utils.h" + +const char *cfg_example = "test : \n" + "{\n" + " hallo = 1L;\n" + "};\n" + "liste = ( 1.1, 2L, 3L, 4L, \n" + " {\n" + " objekt : \n" + " {\n" + " key = \"value\";\n" + " };\n" + " } );\n"; + +const char *json_example = "{\n" + " \"test\": {\n" + " \"hallo\": 1\n" + " },\n" + " \"liste\": [\n" + " 1.1000000000000001,\n" + " 2,\n" + " 3,\n" + " 4,\n" + " {\n" + " \"objekt\": {\n" + " \"key\": \"value\"\n" + " }\n" + " }\n" + " ]\n" + "}"; + +Test(utils, config_to_json) +{ + int ret; + config_t cfg; + config_setting_t *cfg_root; + json_t *json; + + config_init(&cfg); + + ret = config_read_string(&cfg, cfg_example); + cr_assert_eq(ret, CONFIG_TRUE); + + cfg_root = config_root_setting(&cfg); + + json = config_to_json(cfg_root); + cr_assert_not_null(json); + + char *str = json_dumps(json, JSON_INDENT(2)); + + //printf("%s\n", str); + + json_decref(json); + + cr_assert_str_eq(str, json_example); + + config_destroy(&cfg); +} + +Test(utils, json_to_config) +{ + config_t cfg; + config_setting_t *cfg_root; + json_t *json; + + /* For config_write() */ + FILE *f; + char str[1024]; + + config_init(&cfg); + + cfg_root = config_root_setting(&cfg); + + json = json_loads(json_example, 0, NULL); + cr_assert_not_null(json); + + json_to_config(json, cfg_root); + + //config_write(&cfg, stdout); + + f = fmemopen(str, sizeof(str), "w+"); + config_write(&cfg, f); + fclose(f); + + cr_assert_str_eq(str, cfg_example); + + json_decref(json); +} \ No newline at end of file diff --git a/tools/Makefile.inc b/tools/Makefile.inc index 6a9229bb5..5a671854d 100644 --- a/tools/Makefile.inc +++ b/tools/Makefile.inc @@ -1,8 +1,23 @@ -tools: +TOOLS = $(BUILDDIR)/conf2json + +TOOLS_CFLAGS = $(CFLAGS) +TOOLS_LDLIBS = -lconfig -ljansson -lvillas + +# Compile executable objects +$(BUILDDIR)/tools/%.o: tools/%.c | $$(dir $$@) + $(CC) $(TOOLS_CFLAGS) -c $< -o $@ + +# Link target executables +$(TOOLS): $(BUILDDIR)/%: $(BUILDDIR)/tools/%.o | $(LIBS) + $(CC) $(TOOLS_LDFLAGS) $^ $(TOOLS_LDLIBS) -o $@ + +tools: $(TOOLS) clean-tools: + rm -rf $(BUILDDIR)/tools $(TOOLS) -install-tools: +install-tools: $(TOOLS) install -m 0755 tools/villas.sh $(PREFIX)/bin/villas + install -m 0755 -D -t $(DESTDIR)$(PREFIX)/bin $(TOOLS) .PHONY: tools clean-tools install-tools \ No newline at end of file diff --git a/tools/conf2json.c b/tools/conf2json.c new file mode 100644 index 000000000..2e442a1f6 --- /dev/null +++ b/tools/conf2json.c @@ -0,0 +1,51 @@ +/** Convert old style config to new JSON format. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#include +#include + +#include + +void usage() +{ + printf("Usage: conf2json < input.conf > output.json\n\n"); + + print_copyright(); +} + +int main(int argc, char *argv[]) +{ + int ret; + config_t cfg; + config_setting_t *cfg_root; + json_t *json; + + if (argc != 1) { + usage(); + exit(EXIT_FAILURE); + } + + config_init(&cfg); + + ret = config_read(&cfg, stdin); + if (ret != CONFIG_TRUE) + return ret; + + cfg_root = config_root_setting(&cfg); + + json = config_to_json(cfg_root); + if (!json) + return -1; + + ret = json_dumpf(json, stdout, JSON_INDENT(2)); fflush(stdout); + if (ret) + return ret; + + json_decref(json); + config_destroy(&cfg); + + return 0; +} \ No newline at end of file