efl/legacy/ecore/src/lib/ecore/ecore_strbuf.c

361 lines
7.7 KiB
C

#include "ecore_private.h"
#include "Ecore.h"
#include "Ecore_Data.h"
#include "Ecore_Str.h"
#define ECORE_STRBUF_INIT_SIZE 32
#define ECORE_STRBUF_INIT_STEP 32
#define ECORE_STRBUF_MAX_STEP 4096
struct _ecore_strbuf
{
char *buf;
size_t len;
size_t size;
size_t step;
};
static int _ecore_strbuf_resize(Ecore_Strbuf *buf, size_t size);
/**
* Create a new string buffer
*/
EAPI Ecore_Strbuf *
ecore_strbuf_new(void)
{
Ecore_Strbuf *buf;
buf = malloc(sizeof(Ecore_Strbuf));
if (!buf) return NULL;
buf->len = 0;
buf->size = ECORE_STRBUF_INIT_SIZE;
buf->step = ECORE_STRBUF_INIT_STEP;
buf->buf = malloc(buf->size);
buf->buf[0] = '\0';
return buf;
}
/**
* Free a string buffer
* @param buf the buffer to free
*/
EAPI void
ecore_strbuf_free(Ecore_Strbuf *buf)
{
CHECK_PARAM_POINTER("buf", buf);
free(buf->buf);
free(buf);
}
/**
* Append a string to a buffer, reallocating as necessary.
* @param buf the Ecore_Strbuf to append to
* @param str the string to append
*/
EAPI void
ecore_strbuf_append(Ecore_Strbuf *buf, const char *str)
{
size_t l;
size_t off = 0;
CHECK_PARAM_POINTER("buf", buf);
CHECK_PARAM_POINTER("str", str);
l = ecore_strlcpy(buf->buf + buf->len, str, buf->size - buf->len);
while (l > buf->size - buf->len)
{
/* we successfully appended this much */
off += buf->size - buf->len - 1;
buf->len = buf->size - 1;
buf->size += buf->step;
if (buf->step < ECORE_STRBUF_MAX_STEP)
buf->step *= 2;
buf->buf = realloc(buf->buf, buf->size);
*(buf->buf + buf->len) = '\0';
l = ecore_strlcpy(buf->buf + buf->len, str + off, buf->size - buf->len);
}
buf->len += l;
}
/**
* Insert a string to a buffer, reallocating as necessary.
* @param buf the Ecore_Strbuf to insert
* @param str the string to insert
* @param pos the position to insert the string
*/
EAPI void
ecore_strbuf_insert(Ecore_Strbuf *buf, const char *str, size_t pos)
{
size_t len;
CHECK_PARAM_POINTER("buf", buf);
CHECK_PARAM_POINTER("str", str);
if (pos >= buf->len)
{
ecore_strbuf_append(buf, str);
return;
}
/*
* resize the buffer if necessary
*/
len = strlen(str);
if (!_ecore_strbuf_resize(buf, buf->len + len))
return;
/* move the existing text */
memmove(buf->buf + len + pos, buf->buf + pos, buf->len - pos);
/* and now insert the given string */
memcpy(buf->buf + pos, str, len);
buf->len += len;
buf->buf[buf->len] = 0;
}
/**
* Append a character to a string buffer, reallocating as necessary.
* @param buf the Ecore_Strbuf to append to
* @param c the char to append
*/
EAPI void
ecore_strbuf_append_char(Ecore_Strbuf *buf, char c)
{
CHECK_PARAM_POINTER("buf", buf);
if (buf->len >= buf->size - 1)
{
buf->size += buf->step;
if (buf->step < ECORE_STRBUF_MAX_STEP)
buf->step *= 2;
buf->buf = realloc(buf->buf, buf->size);
}
buf->buf[(buf->len)++] = c;
buf->buf[buf->len] = '\0';
}
/**
* Retrieve a pointer to the contents of a string buffer
* @param buf the buffer
*
* This pointer must not be modified, and will no longer be valid if
* the Ecore_Strbuf is modified.
*/
EAPI const char *
ecore_strbuf_string_get(Ecore_Strbuf *buf)
{
CHECK_PARAM_POINTER_RETURN("buf", buf, NULL);
return buf->buf;
}
/**
* Retrieve the length of the string buffer content
* @param buf the buffer
*/
EAPI size_t
ecore_strbuf_length_get(Ecore_Strbuf *buf)
{
CHECK_PARAM_POINTER_RETURN("buf", buf, 0);
return buf->len;
}
/**
* Replace the n-th string with an other string.
* @param buf the Ecore_Strbuf to work with
* @param str the string to replace
* @param with the replaceing string
* @param n the number of the fitting string
*
* @return true on success
*/
EAPI int
ecore_strbuf_replace(Ecore_Strbuf *buf, const char *str, const char *with,
unsigned int n)
{
size_t len1, len2;
char *spos;
size_t pos;
CHECK_PARAM_POINTER_RETURN("buf", buf, 0);
CHECK_PARAM_POINTER_RETURN("str", str, 0);
CHECK_PARAM_POINTER_RETURN("with", with, 0);
if (n == 0)
return 0;
spos = buf->buf;
while (n--)
{
spos = strstr(spos, str);
if (!spos || *spos == '\0')
return 0;
if (n) spos++;
}
pos = spos - buf->buf;
len1 = strlen(str);
len2 = strlen(with);
if (len1 != len2)
{
/* resize the buffer if necessary */
if (!_ecore_strbuf_resize(buf, buf->len - len1 + len2))
return 0;
/* move the existing text */
memmove(buf->buf + pos + len2, buf->buf + pos + len1,
buf->len - pos - len1);
}
/* and now insert the given string */
memcpy(buf->buf + pos, with, len2);
buf->len += len2 - len1;
buf->buf[buf->len] = 0;
return 1;
}
/**
* Replace all strings with an other string.
* @param buf the Ecore_Strbuf to work with
* @param str the string to replace
* @param with the replaceing string
*
* @return how often the string was replaced
*/
EAPI int
ecore_strbuf_replace_all(Ecore_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;
CHECK_PARAM_POINTER_RETURN("buf", buf, 0);
CHECK_PARAM_POINTER_RETURN("str", str, 0);
CHECK_PARAM_POINTER_RETURN("with", with, 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 - buf->buf;
tmp_buf = buf->buf;
buf->buf = malloc(buf->size);
if (!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 (!_ecore_strbuf_resize(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;
buf->buf[buf->len] = 0;
free(tmp_buf);
return n;
}
/**
* resize the buffer
* @param buf the buffer to resize
* @param size the minimum size of the buffer
*/
static int
_ecore_strbuf_resize(Ecore_Strbuf *buf, size_t size)
{
char *buffer;
size_t new_size;
size_t new_step;
new_size = buf->size;
new_step = buf->step;
/*
* first we have to determine the new buffer size
*/
if (size == buf->size)
/* nothing to do */
return 1;
else if (size > buf->size)
{
/* enlarge the buffer */
while (size > new_size)
{
new_size += new_step;
if (new_step < ECORE_STRBUF_MAX_STEP)
new_step *= 2;
}
}
else
{
/* shrink the buffer */
/*
* to be done
*/
return 1;
}
/* reallocate the buffer to the new size */
buffer = realloc(buf->buf, new_size);
if (!buffer)
return 0;
buf->buf = buffer;
buf->size = new_size;
buf->step = new_step;
return 1;
}