]> git.ipfire.org Git - pakfire.git/commitdiff
libpakfire: parser: Handle if statements
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 31 May 2019 02:39:17 +0000 (03:39 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 31 May 2019 02:39:17 +0000 (03:39 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/include/pakfire/parser.h
src/libpakfire/libpakfire.sym
src/libpakfire/parser.c
src/libpakfire/parser/grammar.y
tests/libpakfire/makefile.c

index 160bed6319e360150e0876b14b0ab8c1d55d1e58..fa650b855c10ba2969055752e69d4a0016acf4e8 100644 (file)
@@ -288,7 +288,7 @@ PAKFIRE_EXPORT PakfireArchive pakfire_archive_create(Pakfire pakfire) {
                archive->nrefs = 1;
 
                archive->format = -1;
-               archive->parser = pakfire_parser_create(pakfire);
+               archive->parser = pakfire_parser_create(pakfire, NULL);
                archive->signatures = NULL;
        }
 
index 504e95c799a0ae1f5504eab159b19581de605eac..253d5416d652c3e9a5a1208ed342d0fb0125beba 100644 (file)
 
 #include <pakfire/types.h>
 
-PakfireParser pakfire_parser_create(Pakfire pakfire);
+PakfireParser pakfire_parser_create(Pakfire pakfire, PakfireParser parser);
+PakfireParser pakfire_parser_ref(PakfireParser parser);
 PakfireParser pakfire_parser_unref(PakfireParser parser);
 int pakfire_parser_set_declaration(PakfireParser parser,
                const char* name, const char* value);
 int pakfire_parser_append_declaration(PakfireParser parser,
        const char* name, const char* value);
+
+char* pakfire_parser_expand(PakfireParser parser,
+       const char* namespace, const char* value);
 char* pakfire_parser_get(PakfireParser parser, const char* name);
 
+PakfireParser pakfire_parser_merge(PakfireParser parser1, PakfireParser parser2);
+
 int pakfire_parser_read(PakfireParser parser, FILE* f);
 
 #ifdef PAKFIRE_PRIVATE
@@ -44,6 +50,16 @@ struct pakfire_parser_declaration {
        char* value;
 };
 
+struct pakfire_parser_declarations {
+       struct pakfire_parser_declaration** declarations;
+       unsigned int next;
+       unsigned int num;
+};
+
+struct pakfire_parser_declarations** pakfire_parser_declarations(size_t max);
+struct pakfire_parser_declaration* pakfire_parser_make_declaration(
+       enum pakfire_parser_declaration_operator operator, const char* name, const char* value);
+
 int pakfire_parser_parse_data(PakfireParser parser, const char* data, size_t len);
 
 #endif /* PAKFIRE_PRIVATE */
index 3aa4b30928bc7282a02e57e7ccc1cffdfcd1ed19..a018e1b6ed917d499b7cdbef7ff26f700442e5f5 100644 (file)
@@ -211,9 +211,11 @@ global:
 
        # parser
        pakfire_parser_create;
+       pakfire_parser_expand;
        pakfire_parser_get;
        pakfire_parser_parse_data;
        pakfire_parser_read;
+       pakfire_parser_ref;
        pakfire_parser_unref;
 
        # problem
index 31ad2686d51abbcd7b843b595334332a671becb9..fb4df9e93b5f5c1e47a1bc52c6f720d6bb1040af 100644 (file)
@@ -33,6 +33,7 @@
 
 struct _PakfireParser {
        Pakfire pakfire;
+       struct _PakfireParser* parent;
        int nrefs;
 
        struct pakfire_parser_declaration** declarations;
@@ -40,11 +41,51 @@ struct _PakfireParser {
        unsigned int num_declarations;
 };
 
-PAKFIRE_EXPORT PakfireParser pakfire_parser_create(Pakfire pakfire) {
+#if 0
+struct pakfire_parser_declarations** pakfire_parser_declarations(size_t num) {
+       struct pakfire_parser_declarations* declarations =
+               pakfire_calloc(1, sizeof(*declarations));
+
+
+               pakfire_calloc(num, sizeof(*declarations));
+
+
+
+       return declarations;
+}
+
+void pakfire_parser_declarations_free(struct pakfire_parser_declarations** declarations) {
+       for (unsigned int i = 0; i < declarations->num; i++) {
+               if (declarations->declarations[i])
+                       pakfire_free(declarations->declarations[i]);
+       }
+
+       pakfire_free(declarations);
+}
+
+struct pakfire_parser_declaration* pakfire_parser_make_declaration(
+               enum pakfire_parser_declaration_operator operator, const char* name, const char* value) {
+       struct pakfire_parser_declaration* d = pakfire_calloc(1, sizeof(*d));
+
+       if (d) {
+               d->name  = pakfire_strdup(name);
+               d->value = pakfire_strdup(value);
+               d->operation = operator;
+       }
+
+       return d;
+}
+#endif
+
+PAKFIRE_EXPORT PakfireParser pakfire_parser_create(Pakfire pakfire, PakfireParser parent) {
        PakfireParser parser = pakfire_calloc(1, sizeof(*parser));
        if (parser) {
                parser->pakfire = pakfire_ref(pakfire);
 
+               // Store a reference to the parent parser if we have one
+               if (parent)
+                       parser->parent = pakfire_parser_ref(parent);
+
                parser->num_declarations = NUM_DECLARATIONS;
 
                // Allocate a decent number of declarations
@@ -57,6 +98,12 @@ PAKFIRE_EXPORT PakfireParser pakfire_parser_create(Pakfire pakfire) {
        return parser;
 }
 
+PAKFIRE_EXPORT PakfireParser pakfire_parser_ref(PakfireParser parser) {
+       ++parser->nrefs;
+
+       return parser;
+}
+
 Pakfire pakfire_parser_get_pakfire(PakfireParser parser) {
        return pakfire_ref(parser->pakfire);
 }
@@ -76,6 +123,7 @@ static void pakfire_parser_free(PakfireParser parser) {
 
        pakfire_parser_free_declarations(parser->declarations, parser->num_declarations);
 
+       pakfire_parser_unref(parser->parent);
        pakfire_unref(parser->pakfire);
        pakfire_free(parser);
 }
@@ -105,6 +153,10 @@ static struct pakfire_parser_declaration* pakfire_parser_get_declaration(
                        return d;
        }
 
+       // If nothing was found, we will try finding a match in the parent parser
+       if (parser->parent)
+               return pakfire_parser_get_declaration(parser->parent, name);
+
        return NULL;
 }
 
@@ -232,6 +284,25 @@ static char* pakfire_parser_expand_declaration(PakfireParser parser,
        if (!declaration || !declaration->value)
                return NULL;
 
+       // Get namespace of variable we are expanding
+       char* namespace = pakfire_strdup(declaration->name);
+       pakfire_parser_strip_namespace(namespace);
+
+       // Expand the value
+       char* buffer = pakfire_parser_expand(parser, namespace, declaration->value);
+
+       // Cleanup
+       pakfire_free(namespace);
+
+       return buffer;
+}
+
+PAKFIRE_EXPORT char* pakfire_parser_expand(PakfireParser parser,
+               const char* namespace, const char* value) {
+       // Return NULL when the value is NULL
+       if (!value)
+               return NULL;
+
        // Compile the regular expression
        regex_t preg;
        int r = regcomp(&preg, VARIABLE_PATTERN, REG_EXTENDED);
@@ -245,12 +316,8 @@ static char* pakfire_parser_expand_declaration(PakfireParser parser,
                return NULL;
        }
 
-       // Get namespace of variable we are expanding
-       char* namespace = pakfire_strdup(declaration->name);
-       pakfire_parser_strip_namespace(namespace);
-
        // Create a working copy of the string we are expanding
-       char* buffer = pakfire_strdup(declaration->value);
+       char* buffer = pakfire_strdup(value);
 
        const size_t max_groups = 2;
        regmatch_t groups[max_groups];
@@ -281,12 +348,15 @@ static char* pakfire_parser_expand_declaration(PakfireParser parser,
 
                const char* value = NULL;
                if (v && v->value) {
+                       DEBUG(parser->pakfire, "Replacing %%{%s} with %s = '%s'\n",
+                               variable, v->name, v->value);
+
                        value = v->value;
+               } else {
+                       DEBUG(parser->pakfire, "Replacing %%{%s} with an empty string\n",
+                               variable);
                }
 
-               DEBUG(parser->pakfire, "Replacing %%{%s} with %s = '%s'\n",
-                       variable, v->name, value);
-
                // Reset offsets to the whole matched string
                start = groups[0].rm_so; end = groups[0].rm_eo;
 
@@ -329,6 +399,21 @@ PAKFIRE_EXPORT char* pakfire_parser_get(PakfireParser parser, const char* name)
        return pakfire_parser_expand_declaration(parser, d);
 }
 
+PAKFIRE_EXPORT PakfireParser pakfire_parser_merge(PakfireParser parser1, PakfireParser parser2) {
+       DEBUG(parser1->pakfire, "Merging parsers %p and %p\n", parser1, parser2);
+
+       if (parser2) {
+               for (unsigned int i = 0; i < parser2->num_declarations; i++) {
+                       struct pakfire_parser_declaration* d = parser2->declarations[i];
+
+                       if (d)
+                               pakfire_parser_set_declaration(parser1, d->name, d->value);
+               }
+       }
+
+       return parser1;
+}
+
 PAKFIRE_EXPORT int pakfire_parser_read(PakfireParser parser, FILE* f) {
        char* data;
        size_t len;
index 679803d00b293e66f88829aa396742b34a1cf9b9..7c6b1726fb1491bae5ddc22dc707582e08783770 100644 (file)
@@ -56,6 +56,15 @@ static void cleanup(void);
 
 char* current_block = NULL;
 static char* pakfire_parser_make_canonical_name(const char* name);
+
+enum operator {
+       OP_EQUALS = 0,
+};
+
+static PakfireParser new_parser(PakfireParser parent);
+static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
+       const char* val1, const char* val2, PakfireParser block);
+
 %}
 
 %token                                                 T_APPEND
@@ -75,12 +84,18 @@ static char* pakfire_parser_make_canonical_name(const char* name);
 %type <string>                                 word;
 %type <string>                                 words;
 
+%type <parser>                                 assignment;
+%type <parser>                                 block_assignments;
+%type <parser>                                 block_assignment;
+%type <parser>                                 if_stmt;
+
 %precedence T_WORD
 
 %left T_APPEND
 %left T_ASSIGN
 
 %union {
+       PakfireParser parser;
        char* string;
 }
 
@@ -145,7 +160,8 @@ end                                                 : T_END T_EOL;
 
 if_stmt                                                : T_IF T_WORD T_EQUALS T_WORD T_EOL block_assignments end
                                                        {
-                                                               printf("IF STATEMENT NOT EVALUATED, YET: %s %s\n", $2, $4);
+                                                               $$ = make_if_stmt(parser, OP_EQUALS, $2, $4, $6);
+                                                               pakfire_parser_unref($6);
                                                        };
 
 block_opening                          : variable T_EOL
@@ -162,11 +178,18 @@ block_closing                             : end
 block                                          : block_opening block_assignments block_closing;
 
 block_assignments                      : block_assignments block_assignment
+                                                       {
+                                                               $$ = pakfire_parser_merge($1, $2);
+                                                               pakfire_parser_unref($2);
+                                                       }
                                                        | block_assignment;
 
 block_assignment                       : assignment
                                                        | if_stmt
-                                                       | empty;
+                                                       | empty
+                                                       {
+                                                               $$ = new_parser(parser);
+                                                       };
 
 assignment                                     : variable T_ASSIGN value T_EOL
                                                        {
@@ -174,11 +197,17 @@ assignment                                        : variable T_ASSIGN value T_EOL
                                                                if (!name)
                                                                        ABORT;
 
-                                                               int r = pakfire_parser_set_declaration(parser, name, $3);
+                                                               // Allocate a new parser
+                                                               // XXX should not inherit from parser
+                                                               $$ = new_parser(parser);
+
+                                                               int r = pakfire_parser_set_declaration($$, name, $3);
                                                                pakfire_free(name);
 
-                                                               if (r < 0)
+                                                               if (r < 0) {
+                                                                       pakfire_parser_unref($$);
                                                                        ABORT;
+                                                               }
                                                        }
                                                        | variable T_APPEND value T_EOL
                                                        {
@@ -186,11 +215,17 @@ assignment                                        : variable T_ASSIGN value T_EOL
                                                                if (!name)
                                                                        ABORT;
 
-                                                               int r = pakfire_parser_append_declaration(parser, name, $3);
+                                                               // Allocate a new parser
+                                                               // XXX should not inherit from parser
+                                                               $$ = new_parser(parser);
+
+                                                               int r = pakfire_parser_append_declaration($$, name, $3);
                                                                pakfire_free(name);
 
-                                                               if (r < 0)
+                                                               if (r < 0) {
+                                                                       pakfire_parser_unref($$);
                                                                        ABORT;
+                                                               }
                                                        }
                                                        | define text end
                                                        {
@@ -198,11 +233,17 @@ assignment                                        : variable T_ASSIGN value T_EOL
                                                                if (!name)
                                                                        ABORT;
 
-                                                               int r = pakfire_parser_set_declaration(parser, name, $2);
+                                                               // Allocate a new parser
+                                                               // XXX should not inherit from parser
+                                                               $$ = new_parser(parser);
+
+                                                               int r = pakfire_parser_set_declaration($$, name, $2);
                                                                pakfire_free(name);
 
-                                                               if (r < 0)
+                                                               if (r < 0) {
+                                                                       pakfire_parser_unref($$);
                                                                        ABORT;
+                                                               }
                                                        };
 
 define                                         : T_DEFINE variable T_EOL
@@ -257,3 +298,50 @@ void yyerror(PakfireParser parser, const char* s) {
 
        pakfire_unref(pakfire);
 }
+
+static PakfireParser new_parser(PakfireParser parent) {
+       Pakfire pakfire = pakfire_parser_get_pakfire(parent);
+
+       PakfireParser parser = pakfire_parser_create(pakfire, parent);
+       pakfire_unref(pakfire);
+
+       return parser;
+}
+
+static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
+               const char* val1, const char* val2, PakfireParser block) {
+       Pakfire pakfire = pakfire_parser_get_pakfire(parser);
+
+       switch (op) {
+               case OP_EQUALS:
+                       DEBUG(pakfire, "Evaluating if statement: %s == %s?\n", val1, val2);
+                       break;
+       }
+
+       const char* namespace = current_block;
+
+       // Expand values
+       char* v1 = pakfire_parser_expand(parser, namespace, val1);
+       char* v2 = pakfire_parser_expand(parser, namespace, val2);
+
+       PakfireParser result = NULL;
+
+       switch (op) {
+               case OP_EQUALS:
+                       DEBUG(pakfire, "  '%s' == '%s'?\n", v1, v2);
+
+                       if (strcmp(v1, v2) == 0)
+                               result = block;
+
+                       break;
+       }
+
+       pakfire_unref(pakfire);
+       pakfire_free(v1);
+       pakfire_free(v2);
+
+       if (result)
+               result = pakfire_parser_ref(result);
+
+       return result;
+}
index 28dceb6e62ffad5d2936c0f12c6618f9f0d4bf53..6e85c7adb0b1e08f32f4345965374621198a3840 100644 (file)
@@ -32,7 +32,7 @@ int test_parse(const test_t* t) {
        FILE* f = fopen(path, "r");
        assert_return(f, EXIT_FAILURE);
 
-       PakfireParser parser = pakfire_parser_create(t->pakfire);
+       PakfireParser parser = pakfire_parser_create(t->pakfire, NULL);
 
        int r = pakfire_parser_read(parser, f);
        assert_return(r == 0, EXIT_FAILURE);