From 8a3e5705367b13af9cdf50ba4bcb3c2b67d39428 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 11 Oct 2022 13:00:48 +0000 Subject: [PATCH] config: Extend parser to support multiline files Signed-off-by: Michael Tremer --- src/libpakfire/config.c | 86 +++++++++++++++++++++++++++++++++++---- tests/libpakfire/config.c | 33 +++++++++++++++ 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/libpakfire/config.c b/src/libpakfire/config.c index ac1e26d56..22fbe892b 100644 --- a/src/libpakfire/config.c +++ b/src/libpakfire/config.c @@ -169,6 +169,32 @@ int pakfire_config_set(struct pakfire_config* config, return pakfire_string_set(entry->value, value); } +static int pakfire_config_append(struct pakfire_config* config, + const char* section, const char* key, const char* value2) { + char* buffer = NULL; + int r; + + // Fetch the current value + const char* value1 = pakfire_config_get(config, section, key, NULL); + + // Short cut if value1 is empty + if (!value1 || !*value1) + return pakfire_config_set(config, section, key, value2); + + // Join both values together + r = asprintf(&buffer, "%s\n%s", value1, value2); + if (r < 0) + return 1; + + // Set the new value + r = pakfire_config_set(config, section, key, buffer); + + if (buffer) + free(buffer); + + return r; +} + 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); @@ -287,7 +313,7 @@ int pakfire_config_has_section(struct pakfire_config* config, const char* sectio return 0; } -static ssize_t strip(char* s) { +static ssize_t lstrip(char* s) { if (!s) return 0; @@ -297,6 +323,15 @@ static ssize_t strip(char* s) { while (isspace(s[0])) memmove(s, s + 1, l--); + return l; +} + +static ssize_t rstrip(char* s) { + if (!s) + return 0; + + size_t l = strlen(s); + // Remove trailing space while (isspace(s[l - 1])) s[l-- - 1] = '\0'; @@ -304,8 +339,19 @@ static ssize_t strip(char* s) { return l; } +static ssize_t strip(char* s) { + ssize_t l = lstrip(s); + + if (l) + l = rstrip(s); + + return l; +} + int pakfire_config_read(struct pakfire_config* config, FILE* f) { char section[SECTION_MAX_LENGTH] = ""; + char key[KEY_MAX_LENGTH] = ""; + int r; char* line = NULL; size_t l = 0; @@ -327,7 +373,7 @@ int pakfire_config_read(struct pakfire_config* config, FILE* f) { } // Remove trailing space - length = strip(line); + length = rstrip(line); // Skip empty lines if (*line == '\0') @@ -337,13 +383,34 @@ int pakfire_config_read(struct pakfire_config* config, FILE* f) { if (line[0] == '[' && line[length - 1] == ']') { line[length - 1] = '\0'; - int r = pakfire_string_set(section, line + 1); + // Clear the previous key + *key = '\0'; + + r = pakfire_string_set(section, line + 1); if (r) - return r; + goto ERROR; continue; } + // Check if this is a multiline value + if (isspace(*line)) { + // We cannot assign this value anywhere + if (!*key) { + errno = EINVAL; + r = 1; + goto ERROR; + } + + // Strip any leading whitespace + lstrip(line); + + // Append the value to the existing one + r = pakfire_config_append(config, section, key, line); + if (r) + goto ERROR; + } + // Handle any assignments // Find the separator @@ -358,13 +425,18 @@ int pakfire_config_read(struct pakfire_config* config, FILE* f) { strip(line); strip(value); - int r = pakfire_config_set(config, section, line, value); + // Update the key + pakfire_string_set(key, line); + + // Store the value + r = pakfire_config_set(config, section, key, value); if (r) - return r; + goto ERROR; } +ERROR: if (line) free(line); - return 0; + return r; } diff --git a/tests/libpakfire/config.c b/tests/libpakfire/config.c index 9773224d3..8ac2571d9 100644 --- a/tests/libpakfire/config.c +++ b/tests/libpakfire/config.c @@ -144,9 +144,42 @@ FAIL: return r; } +static int test_parse_multiline(const struct test* t) { + int r = EXIT_FAILURE; + + char* TEST_INPUT = + "key1 =\n" + " value1\n" + " value2\n" + "\n" + "key2 = value1\n"; + + FILE* f = fmemopen(TEST_INPUT, strlen(TEST_INPUT), "r"); + ASSERT(f); + + struct pakfire_config* config = NULL; + + ASSERT_SUCCESS(pakfire_config_create(&config)); + ASSERT_SUCCESS(pakfire_config_read(config, f)); + + ASSERT_STRING_EQUALS(pakfire_config_get(config, "", "key1", NULL), "value1\nvalue2"); + ASSERT_STRING_EQUALS(pakfire_config_get(config, "", "key2", NULL), "value1"); + + // Everything passed + r = EXIT_SUCCESS; + +FAIL: + if (f) + fclose(f); + pakfire_config_unref(config); + + return r; +} + int main(int argc, const char* argv[]) { testsuite_add_test(test_get_and_set); testsuite_add_test(test_parse); + testsuite_add_test(test_parse_multiline); return testsuite_run(argc, argv); } -- 2.39.5