From: Michael Tremer Date: Wed, 3 Mar 2021 11:43:20 +0000 (+0000) Subject: parser: Improve performance of expanding strings X-Git-Tag: 0.9.28~1285^2~657 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38fa33053a17a0eead459816471dd787366fbdaf;p=pakfire.git parser: Improve performance of expanding strings By using pakfire_string_replace, all occurrences of a variable will be replaced at once until no variables are being left. It can still happen, that the same variable is being matched later again (multiple times even), but it looks to me like adding any caching mechanism adds a lot more overhead. Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/parser.c b/src/libpakfire/parser.c index 44bf29aa0..cceaed924 100644 --- a/src/libpakfire/parser.c +++ b/src/libpakfire/parser.c @@ -319,6 +319,21 @@ static struct pakfire_parser_declaration* pakfire_parser_find_declaration( return d; } +static char* extract_string(const char* buffer, const regmatch_t* match) { + // Determine the length of the string + size_t l = match->rm_eo - match->rm_so; + + // Allocate sufficient memory + char* s = malloc(l + 1); + if (!s) + return NULL; + + // Copy string + snprintf(s, l + 1, "%s", buffer + match->rm_so); + + return s; +} + PAKFIRE_EXPORT char* pakfire_parser_expand(PakfireParser parser, const char* namespace, const char* value) { // Return NULL when the value is NULL @@ -345,6 +360,8 @@ PAKFIRE_EXPORT char* pakfire_parser_expand(PakfireParser parser, // Create a working copy of the string we are expanding char* buffer = strdup(value); + char* variable = NULL; + char* pattern = NULL; const size_t max_groups = 2; regmatch_t groups[max_groups]; @@ -359,58 +376,68 @@ PAKFIRE_EXPORT char* pakfire_parser_expand(PakfireParser parser, break; } - // Set offsets to the matched variable name - off_t start = groups[1].rm_so, end = groups[1].rm_eo; - - // Get the name of the variable - char* variable = malloc(end - start + 1); - snprintf(variable, end - start + 1, "%s", buffer + start); + // Find the variable name + variable = extract_string(buffer, &groups[1]); + if (!variable) + goto ERROR; DEBUG(parser->pakfire, "Expanding variable: %s\n", variable); // Search for a declaration of this variable - struct pakfire_parser_declaration* v = + struct pakfire_parser_declaration* d = pakfire_parser_find_declaration(parser, namespace, variable); - const char* value = NULL; - if (v && v->value) { - DEBUG(parser->pakfire, "Replacing %%{%s} with %s = '%s'\n", - variable, v->name, v->value); + // What is its value? + const char* repl = NULL; + if (d && d->value) { + DEBUG(parser->pakfire, "Replacing %%{%s} with %s.%s = '%s'\n", variable, + d->namespace, d->name, d->value); - value = v->value; + repl = d->value; } else { - DEBUG(parser->pakfire, "Replacing %%{%s} with an empty string\n", - variable); + DEBUG(parser->pakfire, "Replacing %%{%s} with an empty string\n", variable); + + repl = ""; } - // Reset offsets to the whole matched string - start = groups[0].rm_so; end = groups[0].rm_eo; + // Find the entire matched pattern + pattern = extract_string(buffer, &groups[0]); + if (!pattern) + goto ERROR; - // Length of the new buffer - size_t length = strlen(buffer) - (end - start) + ((value) ? strlen(value) : 0); + // Replace all occurrences + char* tmp = pakfire_string_replace(buffer, pattern, repl); + if (!tmp) + goto ERROR; - char* b = malloc(length + 1); + // Replace buffer + free(buffer); + buffer = tmp; - // Copy buffer up to the beginning of the match - snprintf(b, start + 1, "%s", buffer); + // Free resources + free(variable); + free(pattern); + variable = pattern = NULL; - // Append the new value (if any) - if (value) - strcat(b, value); - - // Append the rest of the buffer - if (buffer + end) - strcat(b, buffer + end); + DEBUG(parser->pakfire, "New buffer: %s\n", buffer); + } - DEBUG(parser->pakfire, "New buffer: %s\n", b); + goto OUT; - // Drop old buffer +ERROR: + if (buffer) { free(buffer); - buffer = b; + buffer = NULL; } +OUT: regfree(&preg); + if (variable) + free(variable); + if (pattern) + free(pattern); + return buffer; }