/** * @internal * @brief Append a character to a string buffer, reallocating as * necessary. * * @param csize the character size * @param buf The string buffer to append to. * @param c The char to append. * @return #EINA_TRUE on success, #EINA_FALSE on failure. * * This function inserts @p c to @p buf. If it can not insert it, #EINA_FALSE * is returned, otherwise #EINA_TRUE is returned. */ Eina_Bool eina_strbuf_common_append_char(size_t csize, Eina_Strbuf *buf, const void *c) { if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + 1))) return EINA_FALSE; memcpy(((unsigned char *)(buf->buf)) + ((buf->len)++ *csize), c, csize); memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize); return EINA_TRUE; }
EAPI Eina_Bool eina_strbuf_replace(Eina_Strbuf *buf, const char *str, const char *with, unsigned int n) { size_t len1, len2; char *spos; 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); if (n == 0) return EINA_FALSE; spos = buf->buf; while (n--) { spos = strstr(spos, str); if (!spos || *spos == '\0') return EINA_FALSE; if (n) spos++; } /* 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; } pos = spos - (const char *)buf->buf; len1 = strlen(str); len2 = strlen(with); 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; }
/** * @brief Append a string to a buffer, reallocating as necessary. * * @param buf The string buffer to append to. * @param str The string to append. * @return #EINA_TRUE on success, #EINA_FALSE on failure. * * This function appends @p str to @p buf. It computes the length of * @p str, so is slightly slower than eina_strbuf_common_append_length(). If * the length is known beforehand, consider using that variant. If * @p buf can't append it, #EINA_FALSE is returned, otherwise * #EINA_TRUE is returned. * * @see eina_strbuf_common_append() * @see eina_strbuf_common_append_length() */ Eina_Bool eina_strbuf_common_append(size_t csize, Eina_Strbuf * buf, const void *str, size_t len) { EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE); if (EINA_UNLIKELY (!_eina_strbuf_common_grow(csize, buf, buf->len + len))) return EINA_FALSE; memcpy(buf->buf + (buf->len * csize), str, (len + 1) * csize); buf->len += len; return EINA_TRUE; }
/** * @internal * @brief Append a string of exact length to a buffer, reallocating as necessary. * * @param csize the character size * @param buf The string buffer to append to. * @param str The string to append. * @param length The exact length to use. * @return #EINA_TRUE on success, #EINA_FALSE on failure. * * This function appends @p str to @p buf. @p str must be of size at * most @p length. It is slightly faster than eina_strbuf_common_append() as * it does not compute the size of @p str. It is useful when dealing * with strings of known size, such as eina_strngshare. If @p buf * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is * returned. * * @see eina_stringshare_length() * @see eina_strbuf_common_append() * @see eina_strbuf_common_append_n() */ Eina_Bool eina_strbuf_common_append_length(size_t csize, Eina_Strbuf *buf, const void *str, size_t length) { EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE); if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + length))) return EINA_FALSE; memcpy(((unsigned char *)(buf->buf)) + (buf->len * csize), str, length * csize); buf->len += length; memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize); return EINA_TRUE; }
/** * @internal * * insert string of known length at random within existing strbuf limits. * * @param buf the buffer to resize, must be valid. * @param str the string to copy, must be valid (!NULL and smaller than @a len) * @param len the amount of bytes in @a str to copy, must be valid. * @param pos the position inside buffer to insert, must be valid (smaller * than eina_strbuf_common_length_get()) * * @return #EINA_TRUE on success, #EINA_FALSE on failure. */ static inline Eina_Bool _eina_strbuf_common_insert_length(size_t csize, Eina_Strbuf * buf, const void *str, size_t len, size_t pos) { if (EINA_UNLIKELY (!_eina_strbuf_common_grow(csize, buf, buf->len + len))) return EINA_FALSE; /* move the existing text */ memmove(buf->buf + ((len + pos) * csize), buf->buf + (pos * csize), (buf->len - pos) * csize); /* and now insert the given string */ memcpy(buf->buf + (pos * csize), str, len * csize); buf->len += len; memset(buf->buf + (buf->len * csize), 0, csize); return EINA_TRUE; }
/** * @brief Replace all strings with an other string. * @param buf the string buffer to work with. * @param str The string to replace. * @param with The replaceing string. * @return How often the string was replaced. * * This function replaces all the occurrences of @p str in @ buf with * the string @p with. This function returns the number of times @p str * has been replaced. On failure, it returns 0. */ EAPI int eina_strbuf_replace_all(Eina_Strbuf * buf, const char *str, const char *with) { size_t len1, len2, len; char *tmp_buf = NULL; char *spos; size_t pos, start; size_t pos_tmp, start_tmp; int n = 0; EINA_SAFETY_ON_NULL_RETURN_VAL(str, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(with, 0); EINA_MAGIC_CHECK_STRBUF(buf, 0); spos = strstr(buf->buf, str); if (!spos || *spos == '\0') return 0; len1 = strlen(str); len2 = strlen(with); /* if the size of the two string is equal, it is fairly easy to replace them * we don't need to resize the buffer or doing other calculations */ if (len1 == len2) { while (spos) { memcpy(spos, with, len2); spos = strstr(spos + len2, str); n++; } return n; } pos = pos_tmp = spos - (const char *) buf->buf; tmp_buf = buf->buf; buf->buf = malloc(buf->size); if (EINA_UNLIKELY(!buf->buf)) { buf->buf = tmp_buf; return 0; } start = start_tmp = 0; len = buf->len; while (spos) { n++; len = (len + len2) - len1; /* resize the buffer if necessary */ if (EINA_UNLIKELY (!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf, len))) { /* we have to stop replacing here, because we haven't enough * memory to go on */ len = (len + len1) - len2; break; } /* copy the untouched text */ memcpy(buf->buf + start, tmp_buf + start_tmp, pos - start); /* copy the new string */ memcpy(buf->buf + pos, with, len2); /* calculate the next positions */ start_tmp = pos_tmp + len1; start = pos + len2; spos = strstr(tmp_buf + start_tmp, str); /* this calculations don't make sense if spos == NULL, but the * calculated values won't be used, because the loop will stop * then */ pos_tmp = spos - tmp_buf; pos = start + pos_tmp - start_tmp; } /* and now copy the rest of the text */ memcpy(buf->buf + start, tmp_buf + start_tmp, len - start); buf->len = len; memset((char *) buf->buf + buf->len, 0, 1); free(tmp_buf); return n; }