From: Michael Tremer Date: Wed, 17 Aug 2022 22:14:18 +0000 (+0000) Subject: Move dependency functions into an own file X-Git-Tag: 0.9.28~453 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a623cf880e64775bc8e805fb9f1306269d854ff;p=pakfire.git Move dependency functions into an own file Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 1b0ba47a1..79735f6a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -224,6 +224,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/compress.c \ src/libpakfire/config.c \ src/libpakfire/db.c \ + src/libpakfire/dependencies.c \ src/libpakfire/dist.c \ src/libpakfire/downloader.c \ src/libpakfire/file.c \ @@ -261,6 +262,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/config.h \ src/libpakfire/include/pakfire/constants.h \ src/libpakfire/include/pakfire/db.h \ + src/libpakfire/include/pakfire/dependencies.h \ src/libpakfire/include/pakfire/dist.h \ src/libpakfire/include/pakfire/downloader.h \ src/libpakfire/include/pakfire/file.h \ diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 2ab442337..9a77fc407 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index 88781a049..377d1a19f 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/src/libpakfire/db.c b/src/libpakfire/db.c index 828518e1d..1a92d7dcf 100644 --- a/src/libpakfire/db.c +++ b/src/libpakfire/db.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/src/libpakfire/dependencies.c b/src/libpakfire/dependencies.c new file mode 100644 index 000000000..904c4c3b7 --- /dev/null +++ b/src/libpakfire/dependencies.c @@ -0,0 +1,338 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2022 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 +#include +#include +#include +#include + +static const struct pakfire_rich_operation { + const char* keyword; + const int flags; +} pakfire_rich_operations[] = { + { "and ", REL_AND }, + { "or ", REL_OR }, + { "if ", REL_COND }, + { "unless ", REL_UNLESS }, + { "else ", REL_ELSE }, + { "with ", REL_WITH }, + { "without ", REL_WITHOUT }, + { NULL, 0 }, +}; + +const char* pakfire_dep2str(struct pakfire* pakfire, Id id) { + Pool* pool = pakfire_get_solv_pool(pakfire); + if (!pool) + return NULL; + + return pool_dep2str(pool, id); +} + +/* + Reads the string until the next space is found. + + This function considers opening and closing brackets. +*/ +static size_t skip(const char** s, const char** n) { + const char* p = *s; + + // Store p in n + *n = p; + + int brackets = 0; + + while (*p) { + switch (*p) { + // End on space or comma + case ' ': + case ',': + goto END; + + // Increment counter on opening bracket + case '(': + brackets++; + break; + + // End on the last closing bracket + case ')': + if (brackets-- <= 0) + goto END; + break; + } + + // Move to next character + p++; + } + +END: + *s = p; + + // Return the length of the skipped string + return p - *n; +} + +/* + This function parses any namespaced dependencies +*/ +static Id pakfire_parse_namespace(Pool* pool, const char* s) { + const char* p = strchr(s, '('); + if (!p) + return 0; + + // Store the namespace ID + Id namespace = pool_strn2id(pool, s, p - s, 1); + + // Find the end of the string + s = strrchr(p, ')'); + if (!s) + return 0; + + Id id = pool_strn2id(pool, p + 1, s - p - 1, 1); + + // Bring it all together + return pool_rel2id(pool, namespace, id, REL_NAMESPACE, 1); +} + +/* + This function parses a simple dependency like "foo = 1.2.3" +*/ +static Id pakfire_parse_dep(struct pakfire* pakfire, const char** s) { + Id id = ID_NULL; + + if (!s) { + errno = EINVAL; + return 0; + } + + const char* p = *s; + const char* n = NULL; + + // Ignore empty strings + if (!p) + return ID_NULL; + + Pool* pool = pakfire_get_solv_pool(pakfire); + + // Consume any leading space + if (isspace(*p)) + p++; + + // Find the first part + size_t l = skip(&p, &n); + + // Add name to pool + if (pakfire_string_startswith(n, "pakfire(")) + id = pakfire_parse_namespace(pool, n); + else + id = pool_strn2id(pool, n, l, 1); + + // Consume any more space + if (isspace(*p)) + p++; + + if (*p == '<' || *p == '=' || *p == '>') { + int flags = 0; + + while (1) { + if (*p == '<') + flags |= REL_LT; + else if (*p == '=') + flags |= REL_EQ; + else if (*p == '>') + flags |= REL_GT; + else + break; + + p++; + } + + // Consume any more space + if (isspace(*p)) + p++; + + // Find the length of EVR + l = skip(&p, &n); + + // Strip zero epoch + if (pakfire_string_startswith(n, "0:")) + n += 2; + + // Add EVR to pool + Id evr = pool_strn2id(pool, n, l, 1); + + // Combine everything + id = pool_rel2id(pool, id, evr, flags, 1); + } + + *s = p; + + return id; +} + +/* + This function parses any rich dependencies +*/ +static Id pakfire_parse_rich_dep(struct pakfire* pakfire, const char** dep, int flags) { + const char* p = *dep; + Id id; + + // Do not try parsing empty strings + if (!*p) + return ID_NULL; + + // Must be starting with an opening bracket + if (!flags && *p++ != '(') + return ID_NULL; + + switch (*p) { + // A new rich dependency + case '(': + id = pakfire_parse_rich_dep(pakfire, &p, 0); + if (!id) + return id; + break; + + // End + case ')': + return ID_NULL; + + // Parse a regular dependency + default: + id = pakfire_parse_dep(pakfire, &p); + if (!id) + return id; + break; + } + + // Consume any space + if (isspace(*p)) + p++; + + // If we have successfully parsed something, we would expect a closing bracket + if (*p == ')') { + *dep = p + 1; + return id; + } + + // Search for a keyword + for (const struct pakfire_rich_operation* op = pakfire_rich_operations; op->keyword; op++) { + if (pakfire_string_startswith(p, op->keyword)) { + // Skip the keyword + p += strlen(op->keyword); + + // Store the flags + flags = op->flags; + break; + } + } + + // If there was no keyword, we are done + if (!flags) + return ID_NULL; + + // Parse the next bit + Id evr = pakfire_parse_rich_dep(pakfire, &p, flags); + + // Abort if there was a problem + if (!evr) + return ID_NULL; + + // Store until where we have parsed the string + *dep = p; + + Pool* pool = pakfire_get_solv_pool(pakfire); + + // Combine everything + return pool_rel2id(pool, id, evr, flags, 1); +} + +Id pakfire_str2dep(struct pakfire* pakfire, const char* s) { + Id id = ID_NULL; + + // Invalid input + if (!s) { + errno = EINVAL; + return id; + } + + // Ignore empty strings + if (!*s) + return id; + + // Consume any leading space + if (isspace(*s)) + s++; + + // Ignore any comments + if (*s == '#') + return id; + + // Parse any rich dependencies + if (*s == '(') + id = pakfire_parse_rich_dep(pakfire, &s, 0); + else + id = pakfire_parse_dep(pakfire, &s); + + // Return nothing if we could not parse the entire string + if (id && *s) + id = ID_NULL; + + return id; +} + +int pakfire_str2deps(struct pakfire* pakfire, struct pakfire_package* pkg, + void (callback)(struct pakfire_package* pkg, const char* dep), const char* deps) { + char* p = NULL; + + // Check for valid inputs + if (!callback || !deps) { + errno = EINVAL; + return 1; + } + + // Copy deps into a working buffer + char* buffer = strdup(deps); + if (!buffer) + return 1; + + char* dep = strtok_r(buffer, "\n", &p); + + // Walk through the buffer line by line + while (dep) { + DEBUG(pakfire, "Found dep '%s'\n", dep); + + // Add the dependency + callback(pkg, dep); + + // Move on to next token + dep = strtok_r(NULL, "\n", &p); + } + + free(buffer); + return 0; +} diff --git a/src/libpakfire/include/pakfire/dependencies.h b/src/libpakfire/include/pakfire/dependencies.h new file mode 100644 index 000000000..01bbeb0f7 --- /dev/null +++ b/src/libpakfire/include/pakfire/dependencies.h @@ -0,0 +1,35 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2022 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_DEPENDENCIES_H +#define PAKFIRE_DEPENDENCIES_H + +#include + +#include +#include + +const char* pakfire_dep2str(struct pakfire* pakfire, Id id); +Id pakfire_str2dep(struct pakfire* pakfire, const char* s); + +int pakfire_str2deps(struct pakfire* pakfire, struct pakfire_package* pkg, + void (callback)(struct pakfire_package* pkg, const char* dep), const char* deps); + +#endif /* PAKFIRE_DEPENDENCIES_H */ diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index 8c65fc6c7..d8cbc2cbc 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -28,12 +28,7 @@ #include -#include - -const char* pakfire_dep2str(struct pakfire* pakfire, Id id); -Id pakfire_str2dep(struct pakfire* pakfire, const char* s); -int pakfire_str2deps(struct pakfire* pakfire, struct pakfire_package* pkg, - void (*callback)(struct pakfire_package* pkg, const char* dep), const char* deps); +#include #define pakfire_string_format(s, fmt, ...) snprintf(s, sizeof(s) - 1, fmt, __VA_ARGS__) #define pakfire_string_set(s, value) pakfire_string_format(s, "%s", value) diff --git a/src/libpakfire/package.c b/src/libpakfire/package.c index 1e0d46f18..24a9be74f 100644 --- a/src/libpakfire/package.c +++ b/src/libpakfire/package.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index a4a61ff9c..d0ecb100b 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libpakfire/parser.c b/src/libpakfire/parser.c index 39e074514..fbea82c1c 100644 --- a/src/libpakfire/parser.c +++ b/src/libpakfire/parser.c @@ -30,6 +30,7 @@ #define PCRE2_CODE_UNIT_WIDTH 8 #include +#include #include #include #include diff --git a/src/libpakfire/problem.c b/src/libpakfire/problem.c index 7c0a6a5c1..1bcddc4fa 100644 --- a/src/libpakfire/problem.c +++ b/src/libpakfire/problem.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/src/libpakfire/request.c b/src/libpakfire/request.c index 2cdbb342c..79b618603 100644 --- a/src/libpakfire/request.c +++ b/src/libpakfire/request.c @@ -34,6 +34,7 @@ #endif #include +#include #include #include #include diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index e051d3abc..0ff1107bd 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -18,7 +18,6 @@ # # #############################################################################*/ -#include #include #include #include @@ -37,7 +36,6 @@ #include #include #include -#include #include #include @@ -48,312 +46,6 @@ #define BUFFER_SIZE 64 * 1024 #define NSEC_PER_SEC 1000000000 -static const struct pakfire_rich_operation { - const char* keyword; - const int flags; -} pakfire_rich_operations[] = { - { "and ", REL_AND }, - { "or ", REL_OR }, - { "if ", REL_COND }, - { "unless ", REL_UNLESS }, - { "else ", REL_ELSE }, - { "with ", REL_WITH }, - { "without ", REL_WITHOUT }, - { NULL, 0 }, -}; - -const char* pakfire_dep2str(struct pakfire* pakfire, Id id) { - Pool* pool = pakfire_get_solv_pool(pakfire); - if (!pool) - return NULL; - - return pool_dep2str(pool, id); -} - -/* - Reads the string until the next space is found. - - This function considers opening and closing brackets. -*/ -static size_t skip(const char** s, const char** n) { - const char* p = *s; - - // Store p in n - *n = p; - - int brackets = 0; - - while (*p) { - switch (*p) { - // End on space or comma - case ' ': - case ',': - goto END; - - // Increment counter on opening bracket - case '(': - brackets++; - break; - - // End on the last closing bracket - case ')': - if (brackets-- <= 0) - goto END; - break; - } - - // Move to next character - p++; - } - -END: - *s = p; - - // Return the length of the skipped string - return p - *n; -} - -/* - This function parses any namespaced dependencies -*/ -static Id pakfire_parse_namespace(Pool* pool, const char* s) { - const char* p = strchr(s, '('); - if (!p) - return 0; - - // Store the namespace ID - Id namespace = pool_strn2id(pool, s, p - s, 1); - - // Find the end of the string - s = strrchr(p, ')'); - if (!s) - return 0; - - Id id = pool_strn2id(pool, p + 1, s - p - 1, 1); - - // Bring it all together - return pool_rel2id(pool, namespace, id, REL_NAMESPACE, 1); -} - -/* - This function parses a simple dependency like "foo = 1.2.3" -*/ -static Id pakfire_parse_dep(struct pakfire* pakfire, const char** s) { - Id id = ID_NULL; - - if (!s) { - errno = EINVAL; - return 0; - } - - const char* p = *s; - const char* n = NULL; - - // Ignore empty strings - if (!p) - return ID_NULL; - - Pool* pool = pakfire_get_solv_pool(pakfire); - - // Consume any leading space - if (isspace(*p)) - p++; - - // Find the first part - size_t l = skip(&p, &n); - - // Add name to pool - if (pakfire_string_startswith(n, "pakfire(")) - id = pakfire_parse_namespace(pool, n); - else - id = pool_strn2id(pool, n, l, 1); - - // Consume any more space - if (isspace(*p)) - p++; - - if (*p == '<' || *p == '=' || *p == '>') { - int flags = 0; - - while (1) { - if (*p == '<') - flags |= REL_LT; - else if (*p == '=') - flags |= REL_EQ; - else if (*p == '>') - flags |= REL_GT; - else - break; - - p++; - } - - // Consume any more space - if (isspace(*p)) - p++; - - // Find the length of EVR - l = skip(&p, &n); - - // Strip zero epoch - if (pakfire_string_startswith(n, "0:")) - n += 2; - - // Add EVR to pool - Id evr = pool_strn2id(pool, n, l, 1); - - // Combine everything - id = pool_rel2id(pool, id, evr, flags, 1); - } - - *s = p; - - return id; -} - -/* - This function parses any rich dependencies -*/ -static Id pakfire_parse_rich_dep(struct pakfire* pakfire, const char** dep, int flags) { - const char* p = *dep; - Id id; - - // Do not try parsing empty strings - if (!*p) - return ID_NULL; - - // Must be starting with an opening bracket - if (!flags && *p++ != '(') - return ID_NULL; - - switch (*p) { - // A new rich dependency - case '(': - id = pakfire_parse_rich_dep(pakfire, &p, 0); - if (!id) - return id; - break; - - // End - case ')': - return ID_NULL; - - // Parse a regular dependency - default: - id = pakfire_parse_dep(pakfire, &p); - if (!id) - return id; - break; - } - - // Consume any space - if (isspace(*p)) - p++; - - // If we have successfully parsed something, we would expect a closing bracket - if (*p == ')') { - *dep = p + 1; - return id; - } - - // Search for a keyword - for (const struct pakfire_rich_operation* op = pakfire_rich_operations; op->keyword; op++) { - if (pakfire_string_startswith(p, op->keyword)) { - // Skip the keyword - p += strlen(op->keyword); - - // Store the flags - flags = op->flags; - break; - } - } - - // If there was no keyword, we are done - if (!flags) - return ID_NULL; - - // Parse the next bit - Id evr = pakfire_parse_rich_dep(pakfire, &p, flags); - - // Abort if there was a problem - if (!evr) - return ID_NULL; - - // Store until where we have parsed the string - *dep = p; - - Pool* pool = pakfire_get_solv_pool(pakfire); - - // Combine everything - return pool_rel2id(pool, id, evr, flags, 1); -} - -Id pakfire_str2dep(struct pakfire* pakfire, const char* s) { - Id id = ID_NULL; - - // Invalid input - if (!s) { - errno = EINVAL; - return id; - } - - // Ignore empty strings - if (!*s) - return id; - - // Consume any leading space - if (isspace(*s)) - s++; - - // Ignore any comments - if (*s == '#') - return id; - - // Parse any rich dependencies - if (*s == '(') - id = pakfire_parse_rich_dep(pakfire, &s, 0); - else - id = pakfire_parse_dep(pakfire, &s); - - // Return nothing if we could not parse the entire string - if (id && *s) - id = ID_NULL; - - return id; -} - -int pakfire_str2deps(struct pakfire* pakfire, struct pakfire_package* pkg, - void (callback)(struct pakfire_package* pkg, const char* dep), const char* deps) { - char* p = NULL; - - // Check for valid inputs - if (!callback || !deps) { - errno = EINVAL; - return 1; - } - - // Copy deps into a working buffer - char* buffer = strdup(deps); - if (!buffer) - return 1; - - char* dep = strtok_r(buffer, "\n", &p); - - // Walk through the buffer line by line - while (dep) { - DEBUG(pakfire, "Found dep '%s'\n", dep); - - // Add the dependency - callback(pkg, dep); - - // Move on to next token - dep = strtok_r(NULL, "\n", &p); - } - - free(buffer); - return 0; -} - int pakfire_string_startswith(const char* s, const char* prefix) { // Validate input if (!s || !prefix) { diff --git a/tests/libpakfire/dependencies.c b/tests/libpakfire/dependencies.c index 409a47631..04d278eda 100644 --- a/tests/libpakfire/dependencies.c +++ b/tests/libpakfire/dependencies.c @@ -22,6 +22,7 @@ #include #include +#include #include #include