}
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) {