mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-05-08 04:38:03 +02:00
util: add a strreplace function
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
4b3b48291b
commit
43be3ddc89
2 changed files with 95 additions and 0 deletions
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "util-strings.h"
|
||||
|
||||
/**
|
||||
|
|
@ -156,6 +158,71 @@ strv_join(char **strv, const char *joiner)
|
|||
return str;
|
||||
}
|
||||
|
||||
char *
|
||||
strreplace(const char *string, const char *separator, const char *replacement)
|
||||
{
|
||||
assert(string != NULL);
|
||||
assert(string[0] != '\0');
|
||||
|
||||
/* Enough to replace every character in the string with the
|
||||
* replacement. This will blow up on extremely long strings with long
|
||||
* replacements, but meh. It saves us having to write resizing code.
|
||||
*/
|
||||
size_t slen = strlen(string);
|
||||
size_t splen = strlen(separator);
|
||||
|
||||
const char *current = string;
|
||||
const char *next;
|
||||
|
||||
next = strstr(current, separator);
|
||||
if (!next) /* No separator found */
|
||||
return xstrdup(string);
|
||||
|
||||
size_t rlen = strlen(replacement);
|
||||
size_t max = slen * max(rlen, 1);
|
||||
char *r = calloc(max + 1, 1); /* the result, one extra for terminating \0 */
|
||||
char *destptr = r;
|
||||
|
||||
/* our strncpy calls truncate the second argument, we know... */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
while (next) {
|
||||
size_t len = next - current;
|
||||
/* silently truncate because we really don't care about this
|
||||
* case */
|
||||
if (destptr + len > r + max)
|
||||
break;
|
||||
|
||||
/* Copy the source string over, then append the separator */
|
||||
strncpy(destptr, current, len);
|
||||
destptr += len;
|
||||
if (destptr + rlen > r + max)
|
||||
break;
|
||||
strncpy(destptr, replacement, rlen);
|
||||
destptr += rlen;
|
||||
|
||||
current = next + splen;
|
||||
if (current > string + max)
|
||||
break;
|
||||
next = strstr(current, separator);
|
||||
|
||||
}
|
||||
|
||||
size_t len = strlen(current);
|
||||
/* silently truncate because we really don't care about this
|
||||
* case */
|
||||
if (destptr + len <= r + max) {
|
||||
strncpy(destptr, current, len);
|
||||
destptr += len;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
void *tmp = realloc(r, (destptr - r) + 1);
|
||||
assert(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
#if _enable_tests_
|
||||
#include "util-munit.h"
|
||||
|
||||
|
|
@ -377,4 +444,30 @@ MUNIT_TEST(test_strendswith)
|
|||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_strreplace)
|
||||
{
|
||||
struct strtest {
|
||||
const char *string;
|
||||
const char *separator;
|
||||
const char *replacement;
|
||||
const char *expected;
|
||||
} tests[] = {
|
||||
{ "teststring", "-", ".", "teststring" },
|
||||
{ "test-string", "-", ".", "test.string" },
|
||||
{ "test.string.", ".", "xyz", "testxyzstringxyz" },
|
||||
{ "ftestfstringf", "f", "", "teststring" },
|
||||
{ "xxx", "x", "y", "yyy" },
|
||||
{ "xyz", "x", "y", "yyz" },
|
||||
{ "xyz", "xy", "y", "yz" },
|
||||
{ .string = NULL },
|
||||
};
|
||||
|
||||
for (struct strtest *t = tests; t->string; t++) {
|
||||
_cleanup_free_ char *s = strreplace(t->string, t->separator, t->replacement);
|
||||
munit_assert_string_equal(t->expected, s);
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -257,6 +257,8 @@ strv_free(char **strv) {
|
|||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char **, strv_free);
|
||||
|
||||
char * strreplace(const char *string, const char *separator, const char *replacement);
|
||||
|
||||
struct key_value_str{
|
||||
char *key;
|
||||
char *value;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue