From: Michael Tremer Date: Fri, 16 Apr 2021 12:08:27 +0000 (+0000) Subject: libpakfire: Add a simple config file tool X-Git-Tag: 0.9.28~1285^2~353 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95b07a7f6010334616b3f02005a9df638c3ec310;p=pakfire.git libpakfire: Add a simple config file tool Signed-off-by: Michael Tremer --- diff --git a/.gitignore b/.gitignore index 8a58e7ac8..915a046b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /.vscode /Makefile /build-aux +/config.h +/config.h.in /intltool-* /libtool /missing @@ -14,6 +16,7 @@ /tests/libpakfire/archive /tests/libpakfire/cgroup /tests/libpakfire/compress +/tests/libpakfire/config /tests/libpakfire/db /tests/libpakfire/downloader /tests/libpakfire/execute @@ -47,8 +50,6 @@ .libs Makefile.in aclocal.m4 -config.h -config.h.in config.log config.status configure diff --git a/Makefile.am b/Makefile.am index 745b14c41..e82b4abb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -258,6 +258,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/archive.c \ src/libpakfire/cgroup.c \ src/libpakfire/compress.c \ + src/libpakfire/config.c \ src/libpakfire/db.c \ src/libpakfire/dist.c \ src/libpakfire/downloader.c \ @@ -292,6 +293,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/archive.h \ src/libpakfire/include/pakfire/cgroup.h \ src/libpakfire/include/pakfire/compress.h \ + src/libpakfire/include/pakfire/config.h \ src/libpakfire/include/pakfire/constants.h \ src/libpakfire/include/pakfire/db.h \ src/libpakfire/include/pakfire/dist.h \ @@ -375,6 +377,7 @@ check_PROGRAMS += \ tests/libpakfire/archive \ tests/libpakfire/cgroup \ tests/libpakfire/compress \ + tests/libpakfire/config \ tests/libpakfire/db \ tests/libpakfire/downloader \ tests/libpakfire/execute \ @@ -448,6 +451,18 @@ tests_libpakfire_compress_LDADD = \ $(LZMA_LIBS) \ $(ZSTD_LIBS) +dist_tests_libpakfire_config_SOURCES = \ + tests/libpakfire/config.c \ + src/libpakfire/config.c + +tests_libpakfire_config_CPPFLAGS = \ + $(TESTSUITE_CPPFLAGS) \ + -DPAKFIRE_PRIVATE + +tests_libpakfire_config_LDADD = \ + $(TESTSUITE_LDADD) \ + $(PAKFIRE_LIBS) + tests_libpakfire_db_SOURCES = \ tests/libpakfire/db.c diff --git a/src/libpakfire/config.c b/src/libpakfire/config.c new file mode 100644 index 000000000..148887253 --- /dev/null +++ b/src/libpakfire/config.c @@ -0,0 +1,201 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include +#include + +#include +#include + +struct pakfire_config_entry { + STAILQ_ENTRY(pakfire_config_entry) nodes; + + // Section name + char section[32]; + + // Key & Value + char key[32]; + char value[1024]; +}; + +struct pakfire_config { + STAILQ_HEAD(entries, pakfire_config_entry) entries; +}; + +int pakfire_config_create(struct pakfire_config** config) { + struct pakfire_config* c = calloc(1, sizeof(*c)); + if (!c) + return ENOMEM; + + // Initialise entries + STAILQ_INIT(&c->entries); + + *config = c; + return 0; +} + +static void pakfire_config_entry_free(struct pakfire_config_entry* entry) { + free(entry); +} + +void pakfire_config_free(struct pakfire_config* config) { + while (!STAILQ_EMPTY(&config->entries)) { + struct pakfire_config_entry* entry = STAILQ_FIRST(&config->entries); + STAILQ_REMOVE_HEAD(&config->entries, nodes); + + pakfire_config_entry_free(entry); + } + + free(config); +} + +static struct pakfire_config_entry* pakfire_config_create_entry( + struct pakfire_config* config, const char* section, const char* key) { + struct pakfire_config_entry* entry = calloc(1, sizeof(*entry)); + if (!entry) + return NULL; + + int r; + + // Store section + r = pakfire_string_set(entry->section, section); + if (r < 0) { + errno = ENOBUFS; + goto ERROR; + } + + // Store key + r = pakfire_string_set(entry->key, key); + if (r < 0) { + errno = ENOBUFS; + goto ERROR; + } + + // Append it to the list of entries + STAILQ_INSERT_TAIL(&config->entries, entry, nodes); + + return entry; + +ERROR: + pakfire_config_entry_free(entry); + return NULL; +} + +static struct pakfire_config_entry* pakfire_config_find(struct pakfire_config* config, + const char* section, const char* key) { + struct pakfire_config_entry* entry; + + // Check for valid input + if (!section || !key) + return NULL; + + STAILQ_FOREACH(entry, &config->entries, nodes) { + // Section must match + if (strcmp(entry->section, section) != 0) + continue; + + // Key must match + if (strcmp(entry->key, key) != 0) + continue; + + // Match! + return entry; + } + + // No match + return NULL; +} + +int pakfire_config_set(struct pakfire_config* config, + const char* section, const char* key, const char* value) { + // Check if this entry exists + struct pakfire_config_entry* entry = pakfire_config_find(config, section, key); + + // Create a new entry if it doesn't + if (!entry) { + entry = pakfire_config_create_entry(config, section, key); + if (!entry) + return ENOMEM; + } + + // Store the value + int r = pakfire_string_set(entry->value, value); + if (r < 0) + return r; + + return 0; +} + +const char* pakfire_config_get(struct pakfire_config* config, + const char* section, const char* key, const char* _default) { + struct pakfire_config_entry* entry = pakfire_config_find(config, section, key); + + // Return the value if set + if (entry && *entry->value) + return entry->value; + + // Otherwise return the default value + return _default; +} + +long int pakfire_config_get_int(struct pakfire_config* config, + const char* section, const char* key, long int _default) { + struct pakfire_config_entry* entry = pakfire_config_find(config, section, key); + + // Return the value if set + if (entry && *entry->value) + return strtol(entry->value, NULL, 10); + + // Otherwise return the default value + return _default; +} + +int pakfire_config_get_bool(struct pakfire_config* config, + const char* section, const char* key, int _default) { + struct pakfire_config_entry* entry = pakfire_config_find(config, section, key); + + // Return the value if set + if (entry && *entry->value) { + static const struct boolean { + const char* string; + int ret; + } booleans[] = { + { "true", 1 }, + { "yes", 1 }, + { "on", 1 }, + { "1", 1 }, + { "false", 1 }, + { "no", 1 }, + { "off", 1 }, + { "0", 1 }, + { NULL, 0 }, + }; + + for (const struct boolean* boolean = booleans; boolean->string; boolean++) { + if (strcmp(entry->value, boolean->string) == 0) + return boolean->ret; + } + } + + // Otherwise return the default value + return _default; +} diff --git a/src/libpakfire/include/pakfire/config.h b/src/libpakfire/include/pakfire/config.h new file mode 100644 index 000000000..9edeeb15a --- /dev/null +++ b/src/libpakfire/include/pakfire/config.h @@ -0,0 +1,43 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_CONFIG_H +#define PAKFIRE_CONFIG_H + +#ifdef PAKFIRE_PRIVATE + +struct pakfire_config; + +int pakfire_config_create(struct pakfire_config** config); +void pakfire_config_free(struct pakfire_config* config); + +int pakfire_config_set(struct pakfire_config* config, + const char* section, const char* key, const char* value); + +const char* pakfire_config_get(struct pakfire_config* config, + const char* section, const char* key, const char* _default); +long int pakfire_config_get_int(struct pakfire_config* config, + const char* section, const char* key, long int _default); +int pakfire_config_get_bool(struct pakfire_config* config, + const char* section, const char* key, int _default); + +#endif + +#endif /* PAKFIRE_CONFIG_H */ diff --git a/tests/libpakfire/config.c b/tests/libpakfire/config.c new file mode 100644 index 000000000..f4b04ca3e --- /dev/null +++ b/tests/libpakfire/config.c @@ -0,0 +1,71 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include "../testsuite.h" + +static int test_get_and_set(const struct test* t) { + struct pakfire_config* config; + + ASSERT_SUCCESS(pakfire_config_create(&config)); + + // Set some values + ASSERT_SUCCESS(pakfire_config_set(config, "section1", "A", "1")); + ASSERT_SUCCESS(pakfire_config_set(config, "section1", "B", "2")); + ASSERT_SUCCESS(pakfire_config_set(config, "section1", "C", "3")); + + // And some more in another section + ASSERT_SUCCESS(pakfire_config_set(config, "section2", "A", "1")); + ASSERT_SUCCESS(pakfire_config_set(config, "section2", "B", "2")); + ASSERT_SUCCESS(pakfire_config_set(config, "section2", "C", "3")); + + // Try reading back the values + ASSERT_STRING_EQUALS(pakfire_config_get(config, "section1", "A", NULL), "1"); + ASSERT_STRING_EQUALS(pakfire_config_get(config, "section2", "A", NULL), "1"); + + // Read other data types + ASSERT(pakfire_config_get_int(config, "section1", "A", 0) == 1); + ASSERT(pakfire_config_get_int(config, "section1", "B", 0) == 2); + ASSERT(pakfire_config_get_int(config, "section1", "C", 0) == 3); + ASSERT(pakfire_config_get_bool(config, "section1", "A", 0) == 1); + ASSERT(pakfire_config_get_bool(config, "section1", "B", 0) == 0); + ASSERT(pakfire_config_get_bool(config, "section1", "C", 0) == 0); + + // Change a value + ASSERT_SUCCESS(pakfire_config_set(config, "section1", "A", "ABC")); + ASSERT_STRING_EQUALS(pakfire_config_get(config, "section1", "A", NULL), "ABC"); + + // Try to access a non-existant value + ASSERT_NULL(pakfire_config_get(config, "section1", "D", NULL)); + + // Return default instead of NULL + ASSERT_STRING_EQUALS(pakfire_config_get(config, "section1", "D", "XXX"), "XXX"); + + pakfire_config_free(config); + + return EXIT_SUCCESS; +} + +int main(int argc, char** argv) { + testsuite_add_test(test_get_and_set); + + return testsuite_run(); +}