From: Michael Tremer Date: Fri, 31 May 2019 02:39:17 +0000 (+0100) Subject: libpakfire: parser: Handle if statements X-Git-Tag: 0.9.28~1285^2~1025 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d310f14c83164d9d28af943772d2d148ce21f26d;p=pakfire.git libpakfire: parser: Handle if statements Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 160bed631..fa650b855 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -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; } diff --git a/src/libpakfire/include/pakfire/parser.h b/src/libpakfire/include/pakfire/parser.h index 504e95c79..253d5416d 100644 --- a/src/libpakfire/include/pakfire/parser.h +++ b/src/libpakfire/include/pakfire/parser.h @@ -25,14 +25,20 @@ #include -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 */ diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 3aa4b3092..a018e1b6e 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -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 diff --git a/src/libpakfire/parser.c b/src/libpakfire/parser.c index 31ad2686d..fb4df9e93 100644 --- a/src/libpakfire/parser.c +++ b/src/libpakfire/parser.c @@ -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; diff --git a/src/libpakfire/parser/grammar.y b/src/libpakfire/parser/grammar.y index 679803d00..7c6b1726f 100644 --- a/src/libpakfire/parser/grammar.y +++ b/src/libpakfire/parser/grammar.y @@ -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 word; %type words; +%type assignment; +%type block_assignments; +%type block_assignment; +%type 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; +} diff --git a/tests/libpakfire/makefile.c b/tests/libpakfire/makefile.c index 28dceb6e6..6e85c7adb 100644 --- a/tests/libpakfire/makefile.c +++ b/tests/libpakfire/makefile.c @@ -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);