]> git.ipfire.org Git - pakfire.git/commitdiff
util: Implement a function that replace patterns in a string
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 3 Mar 2021 00:32:17 +0000 (00:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 3 Mar 2021 00:32:17 +0000 (00:32 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/util.h
src/libpakfire/libpakfire.sym
src/libpakfire/util.c
tests/libpakfire/util.c

index 5e107b03dd0b94202f4cca83ae44169aa75dbd42..2f99489862bf9f9bd4ef4e32e8a6d85ef197ac04 100644 (file)
@@ -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);
index a8e259697289b486056b50fca731ddf1f57e6526..ba24d0acf4ed50d59d90d3b007eb4da3ce1d019a 100644 (file)
@@ -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;
 
index b894de5e10af30be0e16f5bf53d4d0f65d2b28a3..70c04da6ff6db7b9553dfc743906eacec2046eb7 100644 (file)
@@ -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++;
index 942641c1b0719b6b437dd0eb859893632aeca065..e78b135a4eb2c46ad703d608a2eae7e5d73eec13 100644 (file)
@@ -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();
 }