From: Michael Tremer Date: Wed, 3 Mar 2021 00:32:17 +0000 (+0000) Subject: util: Implement a function that replace patterns in a string X-Git-Tag: 0.9.28~1285^2~659 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8377a9fbabc4f197d5072c3148a554510dbb56b;p=pakfire.git util: Implement a function that replace patterns in a string Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index 5e107b03d..2f9948986 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -30,6 +30,7 @@ int pakfire_string_startswith(const char* s, const char* prefix); 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); char* pakfire_format_size(double size); char* pakfire_format_date(time_t t); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index a8e259697..ba24d0acf 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -412,6 +412,7 @@ global: pakfire_read_file_into_buffer; pakfire_split_string; pakfire_string_partition; + pakfire_string_replace; pakfire_string_startswith; pakfire_string_to_size; diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index b894de5e1..70c04da6f 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -72,6 +72,87 @@ PAKFIRE_EXPORT int pakfire_string_partition( return 0; } +PAKFIRE_EXPORT char* pakfire_string_replace( + const char* s, const char* pattern, const char* repl) { + char* result = NULL; + const char** cache = NULL; + unsigned int count = 0; + + const size_t pattern_length = strlen(pattern); + + // Working pointer + const char* p = s; + + // Find all occurrences of pattern and store their location + while (1) { + const char* needle = strstr(p, pattern); + if (!needle) + break; + + // Make space in the cache + cache = reallocarray(cache, sizeof(*cache), count + 1); + cache[count++] = needle; + + // Move p forward + p = needle + pattern_length; + } + + // Copy the string if no occurence was found + if (count == 0) { + result = strdup(s); + goto ERROR; + } + + // Store the end pointer + cache = reallocarray(cache, sizeof(*cache), count + 1); + cache[count] = s + strlen(s); + + const size_t repl_length = strlen(repl); + + // Determine the length of the final string + const size_t length = strlen(s) + ((repl_length - pattern_length) * count); + + // Allocate enough memory for the result + result = malloc(length + 1); + if (!result) + goto ERROR; + + // Reset p + p = s; + + // Working pointer for the result + char* r = result; + + // Copy everything up to the first match + ssize_t l = cache[0] - s; + memcpy(r, p, l); + r += l; + p += l; + + for (unsigned int i = 0; i < count; i++) { + // Put replacement here + memcpy(r, repl, repl_length); + r += repl_length; + p += pattern_length; + + // Determine the length between two matches + l = cache[i+1] - (cache[i] + pattern_length); + + memcpy(r, p, l); + r += l; + p += l; + } + + // Terminate the string + result[length] = '\0'; + +ERROR: + if (cache) + free(cache); + + return result; +} + char* pakfire_lstrip(const char* s) { while (*s && isspace(*s)) s++; diff --git a/tests/libpakfire/util.c b/tests/libpakfire/util.c index 942641c1b..e78b135a4 100644 --- a/tests/libpakfire/util.c +++ b/tests/libpakfire/util.c @@ -107,11 +107,21 @@ static int test_string_partition(const struct test* t) { return EXIT_SUCCESS; } +static int test_string_replace(const struct test* t) { + const char* result = pakfire_string_replace( + "ABCABCABCABC", "AB", "CC" + ); + ASSERT_STRING_EQUALS(result, "CCCCCCCCCCCC"); + + return EXIT_SUCCESS; +} + int main(int argc, char** argv) { testsuite_add_test(test_basename); testsuite_add_test(test_dirname); testsuite_add_test(test_string_startswith); testsuite_add_test(test_string_partition); + testsuite_add_test(test_string_replace); return testsuite_run(); }