]>
git.ipfire.org Git - pakfire.git/blob - src/libpakfire/dependencies.c
1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
26 #include <solv/pool.h>
28 #include <pakfire/dependencies.h>
29 #include <pakfire/logging.h>
30 #include <pakfire/package.h>
31 #include <pakfire/pakfire.h>
32 #include <pakfire/string.h>
33 #include <pakfire/util.h>
35 const struct pakfire_dep pakfire_deps
[] = {
36 { PAKFIRE_PKG_PROVIDES
, "provides" },
37 { PAKFIRE_PKG_PREREQUIRES
, "prerequires" },
38 { PAKFIRE_PKG_REQUIRES
, "requires" },
39 { PAKFIRE_PKG_CONFLICTS
, "conflicts" },
40 { PAKFIRE_PKG_OBSOLETES
, "obsoletes" },
41 { PAKFIRE_PKG_RECOMMENDS
, "recommends" },
42 { PAKFIRE_PKG_SUGGESTS
, "suggests" },
43 { PAKFIRE_PKG_SUPPLEMENTS
, "supplements" },
44 { PAKFIRE_PKG_ENHANCES
, "enhances" },
48 static const struct pakfire_rich_operation
{
51 } pakfire_rich_operations
[] = {
55 { "unless ", REL_UNLESS
},
56 { "else ", REL_ELSE
},
57 { "with ", REL_WITH
},
58 { "without ", REL_WITHOUT
},
62 const char* pakfire_dep2str(struct pakfire
* pakfire
, Id id
) {
63 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
67 return pool_dep2str(pool
, id
);
71 Reads the string until the next space is found.
73 This function considers opening and closing brackets.
75 static size_t skip(const char** s
, const char** n
) {
85 // End on space, =, >, <, or comma
93 // Increment counter on opening bracket
98 // End on the last closing bracket
105 // Move to next character
112 // Return the length of the skipped string
117 This function parses any namespaced dependencies
119 static Id
pakfire_parse_namespace(Pool
* pool
, const char* s
) {
120 const char* p
= strchr(s
, '(');
124 // Store the namespace ID
125 Id
namespace = pool_strn2id(pool
, s
, p
- s
, 1);
127 // Find the end of the string
132 Id id
= pool_strn2id(pool
, p
+ 1, s
- p
- 1, 1);
134 // Bring it all together
135 return pool_rel2id(pool
, namespace, id
, REL_NAMESPACE
, 1);
139 This function parses a simple dependency like "foo = 1.2.3"
141 static Id
pakfire_parse_dep(struct pakfire
* pakfire
, const char** s
) {
150 const char* n
= NULL
;
152 // Ignore empty strings
156 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
158 // Consume any leading space
162 // Find the first part
163 size_t l
= skip(&p
, &n
);
166 if (pakfire_string_startswith(n
, "pakfire("))
167 id
= pakfire_parse_namespace(pool
, n
);
169 id
= pool_strn2id(pool
, n
, l
, 1);
171 // Consume any more space
175 if (*p
== '<' || *p
== '=' || *p
== '>') {
191 // Consume any more space
195 // Find the length of EVR
199 if (pakfire_string_startswith(n
, "0:"))
203 Id evr
= pool_strn2id(pool
, n
, l
, 1);
205 // Combine everything
206 id
= pool_rel2id(pool
, id
, evr
, flags
, 1);
215 This function parses any rich dependencies
217 static Id
pakfire_parse_rich_dep(struct pakfire
* pakfire
, const char** dep
, int flags
) {
218 const char* p
= *dep
;
221 // Do not try parsing empty strings
225 // Must be starting with an opening bracket
226 if (!flags
&& *p
++ != '(')
230 // A new rich dependency
232 id
= pakfire_parse_rich_dep(pakfire
, &p
, 0);
241 // Parse a regular dependency
243 id
= pakfire_parse_dep(pakfire
, &p
);
253 // If we have successfully parsed something, we would expect a closing bracket
259 // Search for a keyword
260 for (const struct pakfire_rich_operation
* op
= pakfire_rich_operations
; op
->keyword
; op
++) {
261 if (pakfire_string_startswith(p
, op
->keyword
)) {
263 p
+= strlen(op
->keyword
);
271 // If there was no keyword, we are done
275 // Parse the next bit
276 Id evr
= pakfire_parse_rich_dep(pakfire
, &p
, flags
);
278 // Abort if there was a problem
282 // Store until where we have parsed the string
285 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
287 // Combine everything
288 return pool_rel2id(pool
, id
, evr
, flags
, 1);
291 Id
pakfire_str2dep(struct pakfire
* pakfire
, const char* s
) {
300 // Ignore empty strings
304 // Consume any leading space
308 // Ignore any comments
312 // Parse any rich dependencies
314 id
= pakfire_parse_rich_dep(pakfire
, &s
, 0);
316 id
= pakfire_parse_dep(pakfire
, &s
);
318 // Return nothing if we could not parse the entire string
325 int pakfire_str2deps(struct pakfire
* pakfire
, struct pakfire_package
* pkg
,
326 const enum pakfire_package_key key
, const char* deps
) {
330 // Check for valid inputs
336 // Copy deps into a working buffer
337 char* buffer
= strdup(deps
);
341 char* dep
= strtok_r(buffer
, "\n", &p
);
343 // Walk through the buffer line by line
345 DEBUG(pakfire
, "Found dep '%s'\n", dep
);
347 // Add the dependency
348 r
= pakfire_package_add_dep(pkg
, key
, dep
);
352 // Move on to next token
353 dep
= strtok_r(NULL
, "\n", &p
);