# #
#############################################################################*/
-#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <archive.h>
#include <archive_entry.h>
#include <json.h>
-#include <solv/pool.h>
#include <uuid/uuid.h>
#include <pakfire/constants.h>
#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) {