]> git.ipfire.org Git - pakfire.git/commitdiff
parser: Implement fetching recursive variables
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 May 2021 13:00:17 +0000 (13:00 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 May 2021 13:00:17 +0000 (13:00 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/util.h
src/libpakfire/parser.c
src/libpakfire/parser/grammar.y
src/libpakfire/util.c

index 74c4f5f339da948160de165117bba7651efee2b9..e861c61f08696b8f0eeccb4bc0cb7e931063e24b 100644 (file)
@@ -41,6 +41,7 @@ void pakfire_parse_deps(Pakfire pakfire, PakfirePackage pkg,
 
 int pakfire_string_startswith(const char* s, const char* prefix);
 int pakfire_string_endswith(const char* s, const char* suffix);
+int pakfire_string_matches(const char* s, const char* pattern);
 char* pakfire_unquote_in_place(char* s);
 int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2);
 char* pakfire_string_replace(const char* s, const char* pattern, const char* repl);
index 2ac99392514487bd6fcbc5b42fee0a943ade6fd0..99991038cecad188ace820f38a6eeb2868311d34 100644 (file)
@@ -202,6 +202,11 @@ static struct pakfire_parser_declaration* pakfire_parser_get_declaration(
        if (!namespace)
                namespace = "";
 
+       if (namespace)
+               DEBUG(parser->pakfire, "Looking up %s.%s\n", namespace, name);
+       else
+               DEBUG(parser->pakfire, "Looking up %s\n", name);
+
        struct pakfire_parser_declaration* d;
        for (unsigned i = 0; i < parser->num_declarations; i++) {
                d = parser->declarations[i];
@@ -305,7 +310,7 @@ static const char* pakfire_parser_get_raw(PakfireParser parser, const char* name
        d = pakfire_parser_get_declaration(parser, namespace, name);
 
        // Return a match when it actually contains a string
-       if (d)
+       if (d && d->value)
                return d->value;
 
        // We are done, if the namespace is empty
@@ -321,7 +326,7 @@ static const char* pakfire_parser_get_raw(PakfireParser parser, const char* name
 
                if (*template) {
                        d = pakfire_parser_get_declaration(parser, template, name);
-                       if (d)
+                       if (d && d->value)
                                return d->value;
                }
        }
@@ -334,7 +339,7 @@ static const char* pakfire_parser_get_raw(PakfireParser parser, const char* name
                pakfire_parser_strip_namespace(&n);
 
                d = pakfire_parser_get_declaration(parser, n, name);
-               if (d)
+               if (d && d->value)
                        return d->value;
 
                // End if we have exhausted the namespace
@@ -504,6 +509,11 @@ static int pakfire_parser_expand_variables(PakfireParser parser,
                        break;
                }
 
+               // Find the entire matched pattern
+               r = pcre2_substring_get_bynumber(match, 0, &pattern, &pattern_length);
+               if (r)
+                       goto ERROR;
+
                // Find the variable name
                r = pcre2_substring_get_bynumber(match, 1, &variable, &variable_length);
                if (r)
@@ -514,6 +524,23 @@ static int pakfire_parser_expand_variables(PakfireParser parser,
                // Search for a declaration of this variable
                const char* repl = pakfire_parser_get_raw(parser, namespace, (const char*)variable);
 
+               // Is this a recursive pattern?
+               if (repl && pakfire_string_matches(repl, (const char*)pattern)) {
+                       DEBUG(parser->pakfire, "Recursion detected in %s\n", pattern);
+
+                       // Move up one step and lookup there
+                       if (namespace && *namespace) {
+                               char* parent_namespace = strdupa(namespace);
+                               pakfire_parser_strip_namespace(&parent_namespace);
+
+                               repl = pakfire_parser_get_raw(parser, parent_namespace, (const char*)variable);
+
+                       // If we have already reached the top namespace, we replace with an empty string
+                       } else {
+                               repl = NULL;
+                       }
+               }
+
                // What is its value?
                if (repl) {
                        DEBUG(parser->pakfire, "Replacing %%{%s} with '%s'\n", variable, repl);
@@ -521,11 +548,6 @@ static int pakfire_parser_expand_variables(PakfireParser parser,
                        DEBUG(parser->pakfire, "Replacing %%{%s} with an empty string\n", variable);
                }
 
-               // Find the entire matched pattern
-               r = pcre2_substring_get_bynumber(match, 0, &pattern, &pattern_length);
-               if (r)
-                       goto ERROR;
-
                // Replace all occurrences
                char* tmp = pakfire_string_replace(*buffer, (const char*)pattern, (repl) ? repl : "");
                if (!tmp)
index 83ca76c594b973f07aaf39b7e58ef0909831971c..b94b11b0d426beb117ad0622c39c996f6397b290 100644 (file)
@@ -314,11 +314,7 @@ subparser                                  : subparser_name T_EOL block T_END T_EOL
                                                                int r = pakfire_string_partition($1, ":", &key, &value);
                                                                if (r == 0) {
                                                                        if (strcmp("package", key) == 0) {
-                                                                               char* name = pakfire_parser_expand($$, NULL, value);
-                                                                               if (name) {
-                                                                                       pakfire_parser_set($$, NULL, "name", name);
-                                                                                       free(name);
-                                                                               }
+                                                                               pakfire_parser_set($$, NULL, "name", value);
                                                                        }
 
                                                                        if (key)
index fd29b683bca092c2ef27198bd6f2654af57247b6..3833599970d528b31e354f6163f610bac50ca973 100644 (file)
@@ -164,6 +164,10 @@ int pakfire_string_endswith(const char* s, const char* suffix) {
        return !strcmp(s + strlen(s) - strlen(suffix), suffix);
 }
 
+int pakfire_string_matches(const char* s, const char* pattern) {
+       return !!strstr(s, pattern);
+}
+
 char* pakfire_unquote_in_place(char* s) {
        if (!s || !*s)
                return s;