diff --git a/src/ddsrt/include/dds/ddsrt/string.h b/src/ddsrt/include/dds/ddsrt/string.h index 7fca58c..5c8d600 100644 --- a/src/ddsrt/include/dds/ddsrt/string.h +++ b/src/ddsrt/include/dds/ddsrt/string.h @@ -176,6 +176,25 @@ ddsrt_strerror_r( char *buf, size_t buflen); +/** + * @brief Replace substring of null terminated string + * + * @param[in] str pointer to string + * @param[in] srch non-empty string to replace + * @param[in] subst string to substitute character "srch" with + * @param[in] max maximum number of times to replace search, or 0 for unlimited + * + * @returns Pointer to newly allocated string with max occurrences of srch replaced, or + * NULL on allocation failure or if srch is an empty string. + */ +DDS_EXPORT char * +ddsrt_str_replace( + const char *str, + const char *srch, + const char *subst, + size_t max) +ddsrt_nonnull_all; + #if defined (__cplusplus) } #endif diff --git a/src/ddsrt/include/dds/ddsrt/strtol.h b/src/ddsrt/include/dds/ddsrt/strtol.h index c4cb059..07860c2 100644 --- a/src/ddsrt/include/dds/ddsrt/strtol.h +++ b/src/ddsrt/include/dds/ddsrt/strtol.h @@ -21,6 +21,19 @@ extern "C" { #endif +/** + * @brief Convert a character to an integer value + * + * Translates the numeric value of the provided character. For characters in range + * '0' to '9' the returned integer value is 0-9. For the range 'a' to 'z' and 'A' + * to 'Z', the numeric return value is 10-36. + * + * @param[in] chr The character + * + * @returns The integer value for the character, or -1 in case @chr cannot be translated to a numeric value + */ +DDS_EXPORT int32_t ddsrt_todigit(const int chr); + /** * @brief Convert a string to a long long integer. * diff --git a/src/ddsrt/src/string.c b/src/ddsrt/src/string.c index d048e5f..e625535 100644 --- a/src/ddsrt/src/string.c +++ b/src/ddsrt/src/string.c @@ -15,7 +15,9 @@ #include #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" int ddsrt_strcasecmp( @@ -162,3 +164,41 @@ ddsrt_strdup( return ddsrt_memdup(str, strlen(str) + 1); } + +char * +ddsrt_str_replace( + const char *str, + const char *srch, + const char *subst, + size_t max) +{ + const size_t lsrch = strlen(srch); + if (lsrch == 0) /* empty search string is treated as failure */ + return NULL; + + const size_t lsubst = strlen(subst); + const size_t lstr = strlen(str); + const char *cur = str; + char *res; + size_t cnt; + + if (max == 0) + max = SIZE_MAX; + for (cnt = 0; (cur = strstr(cur, srch)) != NULL && cnt < max; cnt++) + cur += lsrch; + if ((res = ddsrt_malloc(lstr + cnt * (lsubst - lsrch) + 1)) == NULL) + return NULL; + char *tmp = res; + cur = str; + while (cnt--) + { + const char *found = strstr(cur, srch); + const size_t skip = (size_t)(found - cur); + memcpy(tmp, cur, skip); + memcpy(tmp + skip, subst, lsubst); + tmp += skip + lsubst; + cur += skip + lsrch; + } + memcpy(tmp, cur, lstr - (size_t) (cur - str) + 1); + return res; +} diff --git a/src/ddsrt/src/strtol.c b/src/ddsrt/src/strtol.c index 5269d96..f8d4223 100644 --- a/src/ddsrt/src/strtol.c +++ b/src/ddsrt/src/strtol.c @@ -16,7 +16,7 @@ #include "dds/ddsrt/strtol.h" -static int ddsrt_todigit(const int chr) +int32_t ddsrt_todigit(const int chr) { if (chr >= '0' && chr <= '9') { return chr - '0'; diff --git a/src/ddsrt/tests/string.c b/src/ddsrt/tests/string.c index eae2cc7..babe9af 100644 --- a/src/ddsrt/tests/string.c +++ b/src/ddsrt/tests/string.c @@ -12,6 +12,7 @@ #include #include "CUnit/Theory.h" +#include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" typedef enum { eq, lt, gt } eq_t; @@ -67,3 +68,26 @@ CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0)); } +CU_TheoryDataPoints(ddsrt_str_replace, basic) = { + CU_DataPoints(const char *, "", "a", "aaa", "aaa", "aaa", "aaa", "a", "aa", "acaca", "aacaacaa", "aaa"), + CU_DataPoints(const char *, "a", "", "a", "a", "a", "aa", "aaa", "a", "a", "aa", "a"), + CU_DataPoints(const char *, "b", "b", "b", "bb", "bb", "b", "b", "b", "bb", "b", ""), + CU_DataPoints(size_t, 0, 0, 0, 1, 2, 0, 0, 10, 0, 2, 0), + CU_DataPoints(const char *, "", NULL, "bbb", "bbaa", "bbbba", "ba", "a", "bb", "bbcbbcbb", "bcbcaa", ""), +}; + +CU_Theory((const char *str, const char *srch, const char *subst, size_t max, const char * exp), ddsrt_str_replace, basic) +{ + char * r = ddsrt_str_replace(str, srch, subst, max); + if (exp != NULL) + { + CU_ASSERT_FATAL(r != NULL); + CU_ASSERT(strcmp(r, exp) == 0); + ddsrt_free(r); + } + else + { + CU_ASSERT_FATAL(r == NULL); + } +} +