]> git.ipfire.org Git - people/ric9/pakfire.git/commitdiff
parser: Compile regular expressions only once
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 11 Jan 2025 14:05:56 +0000 (14:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 11 Jan 2025 14:05:56 +0000 (14:05 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/parser.c

index 77c1491b094d1737663c79973b775c0800c8b6e5..b6a862f149e10bc1a77d3d40edc12143d8799f8b 100644 (file)
 // Enable to get more debugging output
 //#define PAKFIRE_DEBUG_PARSER
 
+// Regular expressions
+static struct pakfire_parser_regexes {
+       pcre2_code* variable;
+       pcre2_code* command;
+} regexes = {};
+
 struct pakfire_parser {
        struct pakfire_ctx* ctx;
        struct pakfire* pakfire;
@@ -56,34 +62,8 @@ struct pakfire_parser {
 
        struct pakfire_parser_declaration** declarations;
        size_t num_declarations;
-
-       // Regular expressions
-       pcre2_code* regex_command;
-       pcre2_code* regex_variable;
 };
 
-static int pakfire_parser_compile_regexes(struct pakfire_parser* parser) {
-       int r;
-
-       // Commands
-       if (!parser->regex_command && (parser->flags & PAKFIRE_PARSER_FLAGS_EXPAND_COMMANDS)) {
-               r = pakfire_compile_regex(parser->ctx, &parser->regex_command,
-                       "%(\\(((?>[^()]|(?1))*)\\))");
-               if (r)
-                       return r;
-       }
-
-       // Variables
-       if (!parser->regex_variable) {
-               r = pakfire_compile_regex(parser->ctx, &parser->regex_variable,
-                       "%\\{([A-Za-z0-9_\\-]+)\\}");
-               if (r)
-                       return r;
-       }
-
-       return 0;
-}
-
 static void pakfire_parser_free_declaration(struct pakfire_parser_declaration* d) {
        if (d->value)
                free(d->value);
@@ -101,12 +81,6 @@ static void pakfire_parser_free_declarations(struct pakfire_parser* parser) {
 }
 
 static void pakfire_parser_free(struct pakfire_parser* parser) {
-       // Release regular expressions
-       if (parser->regex_variable)
-               pcre2_code_free(parser->regex_variable);
-       if (parser->regex_command)
-               pcre2_code_free(parser->regex_command);
-
        pakfire_parser_free_declarations(parser);
 
        if (parser->namespace)
@@ -503,26 +477,35 @@ int pakfire_parser_append(struct pakfire_parser* parser,
 }
 
 static int pakfire_parser_expand_commands(struct pakfire_parser* parser, char** buffer) {
-       int r = 0;
+       pcre2_match_data* match = NULL;
        PCRE2_UCHAR* command = NULL;
        PCRE2_SIZE command_length;
        PCRE2_UCHAR* pattern = NULL;
        PCRE2_SIZE pattern_length;
+       int r = 0;
 
        DEBUG(parser->ctx, "Searching for commands in:\n%s\n", *buffer);
 
+       // Compile the regular expression
+       if (!regexes.command) {
+               r = pakfire_compile_regex(parser->ctx, &regexes.command, "%(\\(((?>[^()]|(?1))*)\\))");
+               if (r < 0) {
+                       ERROR(parser->ctx, "Failed to compile the command regex: %s\n", strerror(-r));
+                       goto ERROR;
+               }
+       }
+
        // Allocate memory for results
-       pcre2_match_data* match = pcre2_match_data_create_from_pattern(
-               parser->regex_command, NULL);
+       match = pcre2_match_data_create_from_pattern(regexes.command, NULL);
 
        // Arguments passed to pakfire_execute
        const char* argv[4] = {
                "/bin/sh", "-c", NULL /* will be replaced by command later */, NULL,
        };
 
-       while (1) {
+       for (;;) {
                // Perform matching
-               r = pcre2_jit_match(parser->regex_command,
+               r = pcre2_jit_match(regexes.command,
                        (PCRE2_UCHAR*)*buffer, strlen(*buffer), 0, 0, match, NULL);
 
                // End loop when we have expanded all variables
@@ -593,8 +576,8 @@ static int pakfire_parser_expand_commands(struct pakfire_parser* parser, char**
        }
 
 ERROR:
-       pcre2_match_data_free(match);
-
+       if (match)
+               pcre2_match_data_free(match);
        if (command)
                pcre2_substring_free(command);
        if (pattern)
@@ -605,6 +588,7 @@ ERROR:
 
 static int pakfire_parser_expand_variables(struct pakfire_parser* parser,
                const char* namespace, char** buffer) {
+       pcre2_match_data* match = NULL;
        PCRE2_UCHAR* variable = NULL;
        PCRE2_SIZE variable_length = 0;
        PCRE2_UCHAR* pattern = NULL;
@@ -619,14 +603,22 @@ static int pakfire_parser_expand_variables(struct pakfire_parser* parser,
        else if (!*buffer)
                return 0;
 
+       // Compile the regular expression
+       if (!regexes.variable) {
+               r = pakfire_compile_regex(parser->ctx, &regexes.variable, "%\\{([A-Za-z0-9_\\-]+)\\}");
+               if (r < 0) {
+                       ERROR(parser->ctx, "Failed to compile the variable regex: %s\n", strerror(-r));
+                       goto ERROR;
+               }
+       }
+
        // Allocate memory for results
-       pcre2_match_data* match = pcre2_match_data_create_from_pattern(
-               parser->regex_variable, NULL);
+       match = pcre2_match_data_create_from_pattern(regexes.variable, NULL);
 
        // Search for any variables
-       while (1) {
+       for (;;) {
                // Perform matching
-               r = pcre2_jit_match(parser->regex_variable,
+               r = pcre2_jit_match(regexes.variable,
                        (PCRE2_UCHAR*)*buffer, strlen(*buffer), 0, 0, match, NULL);
 
                // End loop when we have expanded all variables
@@ -711,6 +703,8 @@ ERROR:
 
 char* pakfire_parser_expand(struct pakfire_parser* parser,
                const char* namespace, const char* value) {
+       int r;
+
        // Return NULL when the value is NULL
        if (!value)
                return NULL;
@@ -723,13 +717,6 @@ char* pakfire_parser_expand(struct pakfire_parser* parser,
        if (!pos)
                return buffer;
 
-       // Compile all regular expressions
-       int r = pakfire_parser_compile_regexes(parser);
-       if (r) {
-               DEBUG(parser->ctx, "Could not compile regular expressions: %m\n");
-               goto ERROR;
-       }
-
        // Expand all variables
        r = pakfire_parser_expand_variables(parser, namespace, &buffer);
        if (r) {