diff --git a/src/lib/eina/eina_strbuf.h b/src/lib/eina/eina_strbuf.h index da94435c2d..15d6294349 100644 --- a/src/lib/eina/eina_strbuf.h +++ b/src/lib/eina/eina_strbuf.h @@ -608,6 +608,19 @@ EAPI Eina_Bool eina_strbuf_replace(Eina_Strbuf *buf, const char *str, const char */ #define eina_strbuf_replace_first(buf, str, with) eina_strbuf_replace(buf, str, with, 1) +/** + * @brief Replaces the last occurrence of a substring with another string. + * + * @param[in,out] buf The string buffer. + * @param[in] str The text to match. + * @param[in] with The replacement string. + * @return #EINA_TRUE on success, #EINA_FALSE on failure. + * + * This function replaces the last occurrence of @p str in @p buf with + * @p with. + */ +EAPI Eina_Bool eina_strbuf_replace_last(Eina_Strbuf *buf, const char *str, const char *with) EINA_ARG_NONNULL(1, 2, 3); + /** * @brief Replaces all matching substrings with another string. * diff --git a/src/lib/eina/eina_strbuf_common.c b/src/lib/eina/eina_strbuf_common.c index b4d3427a39..9a1d27d8ce 100644 --- a/src/lib/eina/eina_strbuf_common.c +++ b/src/lib/eina/eina_strbuf_common.c @@ -980,6 +980,61 @@ eina_strbuf_replace(Eina_Strbuf *buf, return EINA_TRUE; } +EAPI Eina_Bool +eina_strbuf_replace_last(Eina_Strbuf *buf, + const char *str, + const char *with) +{ + size_t len1, len2; + char *spos, *spos_next; + size_t pos; + + EINA_SAFETY_ON_NULL_RETURN_VAL( str, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(with, EINA_FALSE); + EINA_MAGIC_CHECK_STRBUF(buf, 0); + + spos = NULL; + spos_next = strstr(buf->buf, str); + while (spos_next && *spos_next) + { + spos = spos_next; + spos_next = strstr(spos + 1, str); + } + + if (!spos) return EINA_FALSE; + + pos = spos - (const char *)buf->buf; + len1 = strlen(str); + len2 = strlen(with); + + /* This is a read only buffer which need change to be made */ + if (buf->ro) + { + char *dest; + + dest = malloc(buf->size); + if (!dest) return 0; + memcpy(dest, buf->buf, buf->len); + buf->buf = dest; + } + + if (len1 != len2) + { + /* resize the buffer if necessary */ + if (EINA_UNLIKELY(!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf, + buf->len - len1 + len2))) + return EINA_FALSE; /* move the existing text */ + memmove(((unsigned char *)(buf->buf)) + pos + len2, + ((unsigned char *)(buf->buf)) + pos + len1, + buf->len - pos - len1); + } + /* and now insert the given string */ + memcpy(((unsigned char *)(buf->buf)) + pos, with, len2); + buf->len += len2 - len1; + memset(((unsigned char *)(buf->buf)) + buf->len, 0, 1); + return EINA_TRUE; +} + EAPI int eina_strbuf_replace_all(Eina_Strbuf *buf, const char *str, const char *with) { diff --git a/src/tests/eina/eina_test_strbuf.c b/src/tests/eina/eina_test_strbuf.c index 1d9f52c0d2..ac99992a31 100644 --- a/src/tests/eina/eina_test_strbuf.c +++ b/src/tests/eina/eina_test_strbuf.c @@ -303,8 +303,12 @@ EFL_START_TEST(eina_test_strbuf_replace) fail_if(strlen(eina_strbuf_string_get(buf)) != eina_strbuf_length_get(buf)); fail_if(strcmp(eina_strbuf_string_get(buf), "baaaab")); + fail_if(eina_strbuf_replace_last(buf, "a", "x") == 0); + fail_if(strlen(eina_strbuf_string_get(buf)) != eina_strbuf_length_get(buf)); + fail_if(strcmp(eina_strbuf_string_get(buf), "baaaxb")); + fail_if(eina_strbuf_replace_first(buf, "a", "b") == 0); - fail_if(strcmp(eina_strbuf_string_get(buf), "bbaaab")); + fail_if(strcmp(eina_strbuf_string_get(buf), "bbaaxb")); eina_strbuf_free(buf);