]> git.ipfire.org Git - pakfire.git/commitdiff
string: Refactor replace function
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 25 Sep 2023 16:54:28 +0000 (16:54 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 25 Sep 2023 16:54:28 +0000 (16:54 +0000)
The old version was slightly over-engineered and the static analyzer was
not too happy with it. Instead of debugging any problems, I wrote this
version which is a lot easier and should be more bug-free.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/string.c

index cf04f05b3d738c6fe727754c3b8dec2fdbe93959..db4783aaeec74fe2dd0d13c37b352fa5c0ee8efe 100644 (file)
@@ -121,93 +121,54 @@ int pakfire_string_partition(const char* s, const char* delim, char** s1, char**
 }
 
 char* pakfire_string_replace(const char* s, const char* pattern, const char* repl) {
-       // Return NULL on no input or no pattern
-       if (!s || !pattern) {
+       const char* m = NULL;
+       char* buffer = "";
+       size_t l = 0;
+       int r;
+
+       // Check inputs
+       if (!s || !pattern || !repl) {
                errno = EINVAL;
                return NULL;
        }
 
-       // Replace with nothing when repl is NULL
-       if (!repl)
-               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;
+       // Walk through the string...
+       for (const char* p = s; *p;) {
+               // Search for the pattern
+               m = strstr(p, pattern);
 
-       // 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;
-       }
+               // Pattern does not exist in the remaining string
+               if (!m) {
+                       // Copy the remaining string
+                       r = asprintf(&buffer, "%s%s", buffer, p);
+                       if (r < 0)
+                               goto ERROR;
 
-       // 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;
+                       break;
+               }
 
-       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 of the string up to the match
+               l = m - p;
 
-               // Determine the length between two matches
-               l = cache[i+1] - (cache[i] + pattern_length);
+               // Copy the read string up to pattern and the replacement into the buffer
+               r = asprintf(&buffer, "%s%.*s%s", buffer, (int)l, p, repl);
+               if (r < 0)
+                       goto ERROR;
 
-               memcpy(r, p, l);
-               r += l;
-               p += l;
+               // Advance p
+               p += l + pattern_length;
        }
 
-       // Terminate the string
-       result[length] = '\0';
+       // Return the buffer
+       return buffer;
 
 ERROR:
-       if (cache)
-               free(cache);
+       if (buffer)
+               free(buffer);
 
-       return result;
+       return NULL;
 }
 
 static unsigned int pakfire_chrcnt(const char* s, char delim) {