]> git.ipfire.org Git - pakfire.git/commitdiff
config: Refactor data model and iterating over sections
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 25 Sep 2023 19:02:56 +0000 (19:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 25 Sep 2023 19:02:56 +0000 (19:02 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/config.c
src/libpakfire/include/pakfire/config.h
src/libpakfire/repo.c
tests/libpakfire/config.c

index 5dd8c266c2811eed81f47cedb92b9ce2c61065c1..b5650e7901ec35ddf1d88e8577f6917975405f87 100644 (file)
 #define SECTION_MAX_LENGTH     256
 #define LINE_MAX_LENGTH                1024
 
-struct pakfire_config_entry {
-       STAILQ_ENTRY(pakfire_config_entry) nodes;
+struct pakfire_config_section {
+       STAILQ_ENTRY(pakfire_config_section) nodes;
 
        // Section name
-       char section[SECTION_MAX_LENGTH];
+       char name[SECTION_MAX_LENGTH];
+
+       // Entries
+       STAILQ_HEAD(entries, pakfire_config_entry) entries;
+};
+
+struct pakfire_config_entry {
+       STAILQ_ENTRY(pakfire_config_entry) nodes;
 
        // Key & Value
        char key[KEY_MAX_LENGTH];
@@ -47,7 +54,7 @@ struct pakfire_config_entry {
 struct pakfire_config {
        int nrefs;
 
-       STAILQ_HEAD(entries, pakfire_config_entry) entries;
+       STAILQ_HEAD(sections, pakfire_config_section) sections;
 };
 
 int pakfire_config_create(struct pakfire_config** config) {
@@ -59,22 +66,39 @@ int pakfire_config_create(struct pakfire_config** config) {
        c->nrefs = 1;
 
        // Initialise entries
-       STAILQ_INIT(&c->entries);
+       STAILQ_INIT(&c->sections);
 
        *config = c;
        return 0;
 }
 
-static void pakfire_config_entry_free(struct pakfire_config_entry* entry) {
+static void pakfire_config_free_entry(struct pakfire_config_entry* entry) {
        free(entry);
 }
 
+static void pakfire_config_free_section(struct pakfire_config_section* section) {
+       struct pakfire_config_entry* entry = NULL;
+
+       // Free all entries
+       while (!STAILQ_EMPTY(&section->entries)) {
+               entry = STAILQ_FIRST(&section->entries);
+               STAILQ_REMOVE_HEAD(&section->entries, nodes);
+
+               pakfire_config_free_entry(entry);
+       }
+
+       free(section);
+}
+
 static 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);
+       struct pakfire_config_section* section = NULL;
+
+       // Free all sections
+       while (!STAILQ_EMPTY(&config->sections)) {
+               section = STAILQ_FIRST(&config->sections);
+               STAILQ_REMOVE_HEAD(&config->sections, nodes);
 
-               pakfire_config_entry_free(entry);
+               pakfire_config_free_section(section);
        }
 
        free(config);
@@ -94,6 +118,50 @@ struct pakfire_config* pakfire_config_unref(struct pakfire_config* config) {
        return NULL;
 }
 
+static struct pakfire_config_section* pakfire_config_create_section(
+               struct pakfire_config* config, const char* name) {
+       struct pakfire_config_section* section = NULL;
+       int r;
+
+       // Allocate a new section
+       section = calloc(1, sizeof(*section));
+       if (!section)
+               goto ERROR;
+
+       // Initialize entries
+       STAILQ_INIT(&section->entries);
+
+       // Store name
+       r = pakfire_string_set(section->name, name);
+       if (r)
+               goto ERROR;
+
+       // Append it to the list of sections
+       STAILQ_INSERT_TAIL(&config->sections, section, nodes);
+
+       // Return the section
+       return section;
+
+ERROR:
+       if (section)
+               pakfire_config_free_section(section);
+
+       return NULL;
+}
+
+static struct pakfire_config_section* pakfire_config_get_section(
+               struct pakfire_config* config, const char* name) {
+       struct pakfire_config_section* section = NULL;
+
+       // Find an existing section
+       STAILQ_FOREACH(section, &config->sections, nodes) {
+               if (strcmp(section->name, name) == 0)
+                       return section;
+       }
+
+       return NULL;
+}
+
 static int pakfire_config_entry_is_multiline(const struct pakfire_config_entry* entry) {
        const char* p = strchr(entry->value, '\n');
 
@@ -104,16 +172,14 @@ static int pakfire_config_entry_is_multiline(const struct pakfire_config_entry*
 }
 
 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;
-
+               struct pakfire_config* config, const char* name, const char* key) {
+       struct pakfire_config_section* section = NULL;
+       struct pakfire_config_entry* entry = NULL;
        int r;
 
-       // Store section
-       r = pakfire_string_set(entry->section, section);
-       if (r)
+       // Allocate a new entry
+       entry = calloc(1, sizeof(*entry));
+       if (!entry)
                goto ERROR;
 
        // Store key
@@ -121,18 +187,29 @@ static struct pakfire_config_entry* pakfire_config_create_entry(
        if (r)
                goto ERROR;
 
+       // Fetch the section
+       section = pakfire_config_get_section(config, name);
+       if (!section) {
+               section = pakfire_config_create_section(config, name);
+               if (!section)
+                       goto ERROR;
+       }
+
        // Append it to the list of entries
-       STAILQ_INSERT_TAIL(&config->entries, entry, nodes);
+       STAILQ_INSERT_TAIL(&section->entries, entry, nodes);
 
        return entry;
 
 ERROR:
-       pakfire_config_entry_free(entry);
+       if (entry)
+               pakfire_config_free_entry(entry);
+
        return NULL;
 }
 
 static struct pakfire_config_entry* pakfire_config_find(struct pakfire_config* config,
-               const char* section, const char* key) {
+               const char* name, const char* key) {
+       struct pakfire_config_section* section = NULL;
        struct pakfire_config_entry* entry = NULL;
 
        // Check for valid input
@@ -142,20 +219,17 @@ static struct pakfire_config_entry* pakfire_config_find(struct pakfire_config* c
        }
 
        // Treat NULL as an empty section
-       if (!section)
-               section = "";
+       if (!name)
+               name = "";
 
-       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;
+       // Fetch the section
+       section = pakfire_config_get_section(config, name);
+       if (!section)
+               return NULL;
 
-               // Match!
-               return entry;
+       STAILQ_FOREACH(entry, &section->entries, nodes) {
+               if (strcmp(entry->key, key) == 0)
+                       return entry;
        }
 
        // No match
@@ -305,54 +379,44 @@ FILE* pakfire_config_get_fopen(struct pakfire_config* config,
        return NULL;
 }
 
-static int pakfire_section_in_sections(const char** sections, const char* section) {
-       if (!sections)
-               return 0;
-
-       for (const char** s = sections; *s; s++) {
-               if (strcmp(section, *s) == 0)
-                       return 1;
-       }
-
-       return 0;
-}
-
-const char** pakfire_config_sections(struct pakfire_config* config) {
-       struct pakfire_config_entry* entry = NULL;
+int pakfire_config_walk_sections(struct pakfire_config* config,
+               pakfire_config_walk_callback callback, void* p) {
+       struct pakfire_config_section* default_section = NULL;
+       struct pakfire_config_section* section = NULL;
+       int r = 0;
 
-       const char** sections = NULL;
-       size_t num_sections = 0;
+       // Try to fetch the default section
+       default_section = pakfire_config_get_section(config, "");
 
-       STAILQ_FOREACH(entry, &config->entries, nodes) {
-               // Skip empty sections
-               if (!*entry->section)
-                       continue;
+       // Run the default section first
+       if (default_section) {
+               r = callback(config, default_section->name, p);
+               if (r)
+                       goto ERROR;
+       }
 
-               // Skip if this section is already on the list
-               if (pakfire_section_in_sections(sections, entry->section))
+       // Then iterate over all other sections
+       STAILQ_FOREACH(section, &config->sections, nodes) {
+               // Skip the default section
+               if (section == default_section)
                        continue;
 
-               // Make space in the array
-               sections = reallocarray(sections, sizeof(*sections), ++num_sections + 1);
-               if (!sections)
-                       return NULL;
-
-               sections[num_sections - 1] = entry->section;
-
-               // Terminate the array
-               sections[num_sections] = NULL;
+               r = callback(config, section->name, p);
+               if (r)
+                       goto ERROR;
        }
 
-       return sections;
+ERROR:
+       return r;
 }
 
-int pakfire_config_has_section(struct pakfire_config* config, const char* section) {
-       struct pakfire_config_entry* entry = NULL;
+int pakfire_config_has_section(struct pakfire_config* config, const char* name) {
+       struct pakfire_config_section* section = NULL;
 
-       STAILQ_FOREACH(entry, &config->entries, nodes) {
-               if (strcmp(entry->section, section) == 0)
-                       return 1;
-       }
+       // Fetch the section
+       section = pakfire_config_get_section(config, name);
+       if (section)
+               return 1;
 
        return 0;
 }
@@ -540,25 +604,30 @@ static int pakfire_config_dump_entry(struct pakfire_config_entry* entry, FILE* f
 }
 
 static int pakfire_config_dump_section(struct pakfire_config* config,
-               const char* section, FILE* f) {
+               const char* name, void* p) {
+       struct pakfire_config_section* section = NULL;
        struct pakfire_config_entry* entry = NULL;
        int r = 0;
 
+       FILE* f = (FILE*)p;
+
+       // Fetch the section
+       section = pakfire_config_get_section(config, name);
+       if (!section)
+               return -errno;
+
        // Print the section name
-       if (*section) {
-               r = fprintf(f, "\n[%s]\n", section);
+       if (*name) {
+               r = fprintf(f, "\n[%s]\n", name);
                if (r <= 0)
                        goto ERROR;
        }
 
        // Iterate over all entries
-       STAILQ_FOREACH(entry, &config->entries, nodes) {
-               // Dump all entries that match this section
-               if (strcmp(entry->section, section) == 0) {
-                       r = pakfire_config_dump_entry(entry, f);
-                       if (r)
-                               goto ERROR;
-               }
+       STAILQ_FOREACH(entry, &section->entries, nodes) {
+               r = pakfire_config_dump_entry(entry, f);
+               if (r)
+                       goto ERROR;
        }
 
        // Success
@@ -569,28 +638,5 @@ ERROR:
 }
 
 int pakfire_config_dump(struct pakfire_config* config, FILE* f) {
-       int r;
-
-       // Fetch a list of all available sections
-       const char** sections = pakfire_config_sections(config);
-
-       // Dump the default section
-       r = pakfire_config_dump_section(config, "", f);
-       if (r)
-               goto ERROR;
-
-       // Dump all sections
-       if (sections) {
-               for (const char** section = sections; *section; section++) {
-                       r = pakfire_config_dump_section(config, *section, f);
-                       if (r)
-                               goto ERROR;
-               }
-       }
-
-ERROR:
-       if (sections)
-               free(sections);
-
-       return r;
+       return pakfire_config_walk_sections(config, pakfire_config_dump_section, f);
 }
index 9fca5c8f8cb33a65e46c3b17dfe7951cf19c6cd6..aeea5e7ef1686ae3050b23957c80c4bdd0a5c139 100644 (file)
@@ -47,7 +47,12 @@ size_t pakfire_config_get_bytes(struct pakfire_config* config,
 FILE* pakfire_config_get_fopen(struct pakfire_config* config,
        const char* section, const char* key);
 
-const char** pakfire_config_sections(struct pakfire_config* config);
+// Walk
+typedef int (*pakfire_config_walk_callback)
+       (struct pakfire_config* config, const char* name, void* p);
+int pakfire_config_walk_sections(struct pakfire_config* config,
+       pakfire_config_walk_callback callback, void* p);
+
 int pakfire_config_has_section(struct pakfire_config* config, const char* section);
 
 int pakfire_config_read(struct pakfire_config* config, FILE* f);
index e26d8c724bbd03811343cc90dec3069819776f0f..eb948a3cdd4606e3c276e6209ed4c969fed9558b 100644 (file)
@@ -229,90 +229,92 @@ ERROR:
        return r;
 }
 
-int pakfire_repo_import(struct pakfire* pakfire, struct pakfire_config* config) {
-       const char** sections = pakfire_config_sections(config);
-
-       // The configuration seems to be empty
-       if (!sections)
-               return 0;
-
+static int __pakfire_repo_import( struct pakfire_config* config, const char* section, void* p) {
+       struct pakfire* pakfire = (struct pakfire*)p;
        struct pakfire_repo* repo = NULL;
        int r = 0;
 
-       // Walk through all sections
-       for (const char** section = sections; *section; section++) {
-               // Skip sections that do not start with "repo:"
-               if (!pakfire_string_startswith(*section, "repo:"))
-                       continue;
+       // Ignore if the section does not start with "repo:"
+       if (!pakfire_string_startswith(section, "repo:"))
+               return 0;
 
-               const char* name = (*section) + strlen("repo:");
-               if (!*name)
-                       continue;
+       // Extract the name
+       const char* name = section + strlen("repo:");
 
-               DEBUG(pakfire, "Creating repository %s\n", name);
+       // Skip if the name is empty
+       if (!*name)
+               return 0;
 
-               // Create a new repository
-               r = pakfire_repo_create(&repo, pakfire, name);
-               if (r) {
-                       ERROR(pakfire, "Could not create repository '%s': %m\n", name);
-                       goto ERROR;
-               }
+       DEBUG(pakfire, "Creating repository %s\n", name);
 
-               // Enabled
-               int enabled = pakfire_config_get_bool(config, *section, "enabled", 1);
-               pakfire_repo_set_enabled(repo, enabled);
+       // Create a new repository
+       r = pakfire_repo_create(&repo, pakfire, name);
+       if (r) {
+               ERROR(pakfire, "Could not create repository '%s': %m\n", name);
+               goto ERROR;
+       }
 
-               // Priority
-               int priority = pakfire_config_get_int(config, *section, "priority", 0);
-               if (priority)
-                       pakfire_repo_set_priority(repo, priority);
+       // Enabled
+       int enabled = pakfire_config_get_bool(config, section, "enabled", 1);
+       pakfire_repo_set_enabled(repo, enabled);
 
-               // Description
-               const char* description = pakfire_config_get(config, *section, "description", NULL);
-               if (description)
-                       pakfire_repo_set_description(repo, description);
+       // Priority
+       int priority = pakfire_config_get_int(config, section, "priority", 0);
+       if (priority)
+               pakfire_repo_set_priority(repo, priority);
 
-               // baseurl
-               const char* baseurl = pakfire_config_get(config, *section, "baseurl", NULL);
-               if (baseurl) {
-                       r = pakfire_repo_set_baseurl(repo, baseurl);
-                       if (r)
-                               goto ERROR;
-               }
+       // Description
+       const char* description = pakfire_config_get(config, section, "description", NULL);
+       if (description)
+               pakfire_repo_set_description(repo, description);
 
-               // Refresh Interval
-               const char* refresh = pakfire_config_get(config, *section, "refresh", NULL);
-               if (refresh)
-                       repo->appdata->refresh = pakfire_string_parse_interval(refresh);
+       // baseurl
+       const char* baseurl = pakfire_config_get(config, section, "baseurl", NULL);
+       if (baseurl) {
+               r = pakfire_repo_set_baseurl(repo, baseurl);
+               if (r)
+                       goto ERROR;
+       }
 
-               // mirrors
-               const char* mirrors = pakfire_config_get(config, *section, "mirrors", NULL);
-               if (mirrors)
-                       pakfire_repo_set_mirrorlist_url(repo, mirrors);
+       // Refresh Interval
+       const char* refresh = pakfire_config_get(config, section, "refresh", NULL);
+       if (refresh)
+               repo->appdata->refresh = pakfire_string_parse_interval(refresh);
 
-               // Key
-               const char* key = pakfire_config_get(config, *section, "key", NULL);
-               if (key) {
-                       r = pakfire_repo_import_key(repo, key);
-                       if (r) {
-                               pakfire_repo_unref(repo);
-                               goto ERROR;
-                       }
-               }
+       // mirrors
+       const char* mirrors = pakfire_config_get(config, section, "mirrors", NULL);
+       if (mirrors)
+               pakfire_repo_set_mirrorlist_url(repo, mirrors);
 
-               pakfire_repo_unref(repo);
+       // Key
+       const char* key = pakfire_config_get(config, section, "key", NULL);
+       if (key) {
+               r = pakfire_repo_import_key(repo, key);
+               if (r)
+                       goto ERROR;
        }
 
+ERROR:
+       if (repo)
+               pakfire_repo_unref(repo);
+
+       return r;
+}
+
+int pakfire_repo_import(struct pakfire* pakfire, struct pakfire_config* config) {
+       int r;
+
+       // Import all repositories from the configuration
+       r = pakfire_config_walk_sections(config, __pakfire_repo_import, pakfire);
+       if (r)
+               return r;
+
        // Refresh repositories
        r = pakfire_refresh(pakfire, 0);
        if (r)
-               goto ERROR;
-
-ERROR:
-       if (sections)
-               free(sections);
+               return r;
 
-       return r;
+       return 0;
 }
 
 Id pakfire_repo_add_solvable(struct pakfire_repo* repo) {
index 946fd2ba9031eab9144c244ff69e95e0d4567b70..de2493e2508c6c425d7b039c3c3c167fcfea01c1 100644 (file)
@@ -122,6 +122,7 @@ static int test_parse(const struct test* t) {
        // Check for a non-existant key
        ASSERT(pakfire_config_get_bytes(config, "bytes", "keyXX", 123) == 123);
 
+#if 0
        // Get sections
        char** sections = pakfire_config_sections(config);
        ASSERT(sections);
@@ -138,6 +139,7 @@ static int test_parse(const struct test* t) {
        ASSERT_STRING_EQUALS(sections[1], "section2");
        ASSERT_STRING_EQUALS(sections[2], "bytes");
        ASSERT_NULL(sections[3]);
+#endif
 
        // Everything passed
        r = EXIT_SUCCESS;