### Checks for library functions
AC_FUNC_ALLOCA
+AC_CHECK_FUNCS(strlcpy)
#dlopen and dladdr
dlopen_libs=""
#include "eina_tiler.h"
#include "eina_hamster.h"
#include "eina_matrixsparse.h"
+#include "eina_str.h"
+#include "eina_strbuf.h"
#ifdef __cplusplus
}
eina_tiler.h \
eina_hamster.h \
eina_matrixsparse.h \
-eina_inline_tiler.x
+eina_inline_tiler.x \
+eina_str.h \
+eina_strbuf.h
installed_mainheaderdir = $(includedir)/eina-@VMAJ@
dist_installed_mainheader_DATA = Eina.h eina_config.h
--- /dev/null
+#ifndef _EINA_STR_H
+#define _EINA_STR_H
+
+#include <stddef.h>
+#include <string.h>
+
+#include "eina_types.h"
+
+/**
+ * @file eina_str.h
+ * @brief Contains useful C string functions.
+ */
+
+/* strlcpy implementation for libc's lacking it */
+EAPI size_t eina_strlcpy(char *dst, const char *src, size_t siz);
+EAPI size_t eina_strlcat(char *dst, const char *src, size_t siz);
+
+EAPI int eina_str_has_prefix(const char *str, const char *prefix);
+
+EAPI int eina_str_has_suffix(const char *str, const char *suffix);
+EAPI int eina_str_has_extension(const char *str, const char *ext);
+
+EAPI char **eina_str_split(const char *string, const char *delimiter,
+ int max_tokens);
+
+EAPI size_t eina_str_join_len(char *dst, size_t size, char sep, const char *a, size_t a_len, const char *b, size_t b_len);
+
+
+/**
+ * Join two strings and store the result in @a dst buffer.
+ *
+ * Similar to eina_str_join_len(), but will compute the length of @a
+ * and @a b using strlen().
+ *
+ * @param dst where to store the result.
+ * @param size byte size of dst, will write at most (size - 1)
+ * characters and then the '\0' (null terminator).
+ * @param sep separator character to use.
+ * @param a first string to use, before @a sep.
+ * @param b second string to use, after @a sep.
+ *
+ * @return the number of characters printed (not including the
+ * trailing '\0' used to end output to strings). Just like
+ * snprintf(), it will not write more than @a size bytes, thus a
+ * return value of @a size or more means that the output was
+ * truncated.
+ *
+ * @see eina_str_join_len() and eina_str_join_static()
+ */
+static inline size_t eina_str_join(char *dst, size_t size, char sep, const char *a, const char *b)
+{
+ return eina_str_join_len(dst, size, sep, a, strlen(a), b, strlen(b));
+}
+
+/**
+ * Join two static strings and store the result in static @a dst buffer.
+ *
+ * Similar to eina_str_join_len(), but will assume string sizes are
+ * know using sizeof(X).
+ *
+ * @param dst where to store the result.
+ * @param sep separator character to use.
+ * @param a first string to use, before @a sep.
+ * @param b second string to use, after @a sep.
+ *
+ * @return the number of characters printed (not including the
+ * trailing '\0' used to end output to strings). Just like
+ * snprintf(), it will not write more than @a size bytes, thus a
+ * return value of @a size or more means that the output was
+ * truncated.
+ *
+ * @see eina_str_join() and eina_str_join_static()
+ */
+#define eina_str_join_static(dst, sep, a, b) eina_str_join_len(dst, sizeof(dst), sep, a, (sizeof(a) > 0) ? sizeof(a) - 1 : 0, b, (sizeof(b) > 0) ? sizeof(b) - 1 : 0)
+
+#endif /* EINA_STR_H */
--- /dev/null
+#ifndef EINA_STRBUF_H
+#define EINA_STRBUF_H
+
+#include <stddef.h>
+
+#include "eina_types.h"
+
+typedef struct _Eina_Strbuf Eina_Strbuf;
+
+EAPI Eina_Strbuf *eina_strbuf_new(void);
+EAPI void eina_strbuf_free(Eina_Strbuf *buf);
+EAPI void eina_strbuf_append(Eina_Strbuf *buf, const char *str);
+EAPI void eina_strbuf_append_char(Eina_Strbuf *buf, char c);
+EAPI void eina_strbuf_insert(Eina_Strbuf *buf, const char *str,
+ size_t pos);
+#define eina_strbuf_prepend(buf, str) eina_strbuf_insert(buf, str, 0)
+EAPI const char *eina_strbuf_string_get(Eina_Strbuf *buf);
+EAPI size_t eina_strbuf_length_get(Eina_Strbuf *buf);
+EAPI int eina_strbuf_replace(Eina_Strbuf *buf, const char *str,
+ const char *with, unsigned int n);
+#define eina_strbuf_replace_first(buf, str, with) \
+ eina_strbuf_replace(buf, str, with, 1)
+EAPI int eina_strbuf_replace_all(Eina_Strbuf *buf, const char *str,
+ const char *with);
+
+#endif /* EINA_STRBUF_H */
eina_cpu.c \
eina_tiler.c \
eina_hamster.c \
-eina_safety_checks.c
+eina_safety_checks.c \
+eina_str.c \
+eina_strbuf.c
if EINA_STATIC_BUILD_CHAINED_POOL
base_sources += $(top_srcdir)/src/modules/mp/chained_pool/eina_chained_mempool.c
--- /dev/null
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+/* Leave the OpenBSD version below so we can track upstream fixes */
+/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+static int eina_str_has_suffix_helper(const char *str, const char *suffix,
+ int (*cmp)(const char *, const char *));
+/**
+ * @param dst the destination
+ * @param src the source
+ * @param siz the size of the destination
+ * @return the length of the source string
+ * @brief copy a c-string
+ *
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+eina_strlcpy(char *dst, const char *src, size_t siz)
+{
+#ifdef HAVE_STRLCPY
+ return strlcpy(dst, src, siz);
+#else
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0)
+ {
+ while (--n != 0)
+ {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0)
+ {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+#endif
+}
+
+/**
+ * @param dst the destination
+ * @param src the source
+ * @param siz the size of the destination
+ * @return the length of the source string plus MIN(siz, strlen(initial dst))
+ * @brief append a c-string
+ *
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+eina_strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+/**
+ * @param str the string to work with
+ * @param prefix the prefix to check for
+ * @return true if str has the given prefix
+ * @brief checks if the string has the given prefix
+ */
+int
+eina_str_has_prefix(const char *str, const char *prefix)
+{
+ size_t str_len;
+ size_t prefix_len;
+
+ str_len = strlen(str);
+ prefix_len = strlen(prefix);
+ if (prefix_len > str_len)
+ return 0;
+
+ return (strncmp(str, prefix, prefix_len) == 0);
+}
+
+/**
+ * @param str the string to work with
+ * @param suffix the suffix to check for
+ * @return true if str has the given suffix
+ * @brief checks if the string has the given suffix
+ */
+int
+eina_str_has_suffix(const char *str, const char *suffix)
+{
+ return eina_str_has_suffix_helper(str, suffix, strcmp);
+}
+
+/**
+ * This function does the same like eina_str_has_suffix(), but with a
+ * case insensitive compare.
+ *
+ * @param str the string to work with
+ * @param ext the extension to check for
+ * @return true if str has the given extension
+ * @brief checks if the string has the given extension
+ */
+int
+eina_str_has_extension(const char *str, const char *ext)
+{
+ return eina_str_has_suffix_helper(str, ext, strcasecmp);
+}
+
+/*
+ * Internal helper function used by eina_str_has_suffix() and
+ * eina_str_has_extension()
+ */
+static int
+eina_str_has_suffix_helper(const char *str, const char *suffix,
+ int (*cmp)(const char *, const char *))
+{
+ size_t str_len;
+ size_t suffix_len;
+
+ str_len = strlen(str);
+ suffix_len = strlen(suffix);
+ if (suffix_len > str_len)
+ return 0;
+
+ return cmp(str + str_len - suffix_len, suffix) == 0;
+}
+
+/**
+ * Splits a string into a maximum of max_tokens pieces, using the given
+ * delimiter. If max_tokens is reached, the final string in the returned
+ * string array contains the remainder of string.
+ *
+ * @param str A string to split.
+ * @param delim A string which specifies the places at which to split the
+ * string. The delimiter is not included in any of the
+ * resulting strings, unless max_tokens is reached.
+ * @param max_tokens The maximum number of strings to split string into.
+ * If this is less than 1, the string is split completely.
+ * @return A newly-allocated NULL-terminated array of strings.
+ * To free it: free the first element of the array
+ * and the array itself.
+ */
+char **
+eina_str_split(const char *str, const char *delim, int max_tokens)
+{
+ char *s, *sep, **str_array;
+ size_t len, dlen;
+ int i;
+
+ if (*delim == '\0')
+ return NULL;
+
+ max_tokens = ((max_tokens <= 0) ? (INT_MAX) : (max_tokens - 1));
+ len = strlen(str);
+ dlen = strlen(delim);
+ s = strdup(str);
+ str_array = malloc(sizeof(char *) * (len + 1));
+ for (i = 0; (i < max_tokens) && (sep = strstr(s, delim)); i++)
+ {
+ str_array[i] = s;
+ s = sep + dlen;
+ *sep = 0;
+ }
+
+ str_array[i++] = s;
+ str_array = realloc(str_array, sizeof(char *) * (i + 1));
+ str_array[i] = NULL;
+
+ return str_array;
+}
+
+/**
+ * Join two strings of known length and store the result in @a dst buffer.
+ *
+ * @param dst where to store the result.
+ * @param size byte size of dst, will write at most (size - 1)
+ * characters and then the '\0' (null terminator).
+ * @param sep separator character to use.
+ * @param a first string to use, before @a sep.
+ * @param a_len length of @a a, not including '\0' (strlen()-like)
+ * @param b second string to use, after @a sep.
+ * @param b_len length of @a b, not including '\0' (strlen()-like)
+ *
+ * @return the number of characters printed (not including the
+ * trailing '\0' used to end output to strings). Just like
+ * snprintf(), it will not write more than @a size bytes, thus a
+ * return value of @a size or more means that the output was
+ * truncated.
+ *
+ * @see eina_str_join() and eina_str_join_static()
+ */
+size_t
+eina_str_join_len(char *dst, size_t size, char sep, const char *a, size_t a_len, const char *b, size_t b_len)
+{
+ size_t ret = a_len + b_len + 1;
+ size_t off;
+
+ if (size < 1) return ret;
+
+ if (size <= a_len)
+ {
+ memcpy(dst, a, size - 1);
+ dst[size - 1] = '\0';
+ return ret;
+ }
+
+ memcpy(dst, a, a_len);
+ off = a_len;
+
+ if (size <= off + 1)
+ {
+ dst[size - 1] = '\0';
+ return ret;
+ }
+
+ dst[off] = sep;
+ off++;
+
+ if (size <= off + b_len + 1)
+ {
+ memcpy(dst + off, b, size - off - 1);
+ dst[size - 1] = '\0';
+ return ret;
+ }
+
+ memcpy(dst + off, b, b_len);
+ dst[off + b_len] = '\0';
+ return ret;
+}
--- /dev/null
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eina_str.h"
+#include "eina_strbuf.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define EINA_STRBUF_INIT_SIZE 32
+#define EINA_STRBUF_INIT_STEP 32
+#define EINA_STRBUF_MAX_STEP 4096
+
+struct _Eina_Strbuf
+{
+ char *buf;
+ size_t len;
+ size_t size;
+ size_t step;
+};
+
+static int _eina_strbuf_resize(Eina_Strbuf *buf, size_t size);
+
+/**
+ * Create a new string buffer
+ */
+EAPI Eina_Strbuf *
+eina_strbuf_new(void)
+{
+ Eina_Strbuf *buf;
+
+ buf = malloc(sizeof(Eina_Strbuf));
+ if (!buf) return NULL;
+
+ buf->len = 0;
+ buf->size = EINA_STRBUF_INIT_SIZE;
+ buf->step = EINA_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
+eina_strbuf_free(Eina_Strbuf *buf)
+{
+ free(buf->buf);
+ free(buf);
+}
+
+/**
+ * Append a string to a buffer, reallocating as necessary.
+ * @param buf the Eina_Strbuf to append to
+ * @param str the string to append
+ */
+EAPI void
+eina_strbuf_append(Eina_Strbuf *buf, const char *str)
+{
+ size_t l;
+ size_t off = 0;
+
+ l = eina_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 < EINA_STRBUF_MAX_STEP)
+ buf->step *= 2;
+ buf->buf = realloc(buf->buf, buf->size);
+ *(buf->buf + buf->len) = '\0';
+
+ l = eina_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 Eina_Strbuf to insert
+ * @param str the string to insert
+ * @param pos the position to insert the string
+ */
+EAPI void
+eina_strbuf_insert(Eina_Strbuf *buf, const char *str, size_t pos)
+{
+ size_t len;
+
+ if (pos >= buf->len)
+ {
+ eina_strbuf_append(buf, str);
+ return;
+ }
+
+ /*
+ * resize the buffer if necessary
+ */
+ len = strlen(str);
+ if (!_eina_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 Eina_Strbuf to append to
+ * @param c the char to append
+ */
+EAPI void
+eina_strbuf_append_char(Eina_Strbuf *buf, char c)
+{
+ if (buf->len >= buf->size - 1)
+ {
+ buf->size += buf->step;
+ if (buf->step < EINA_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 Eina_Strbuf is modified.
+ */
+EAPI const char *
+eina_strbuf_string_get(Eina_Strbuf *buf)
+{
+ return buf->buf;
+}
+
+/**
+ * Retrieve the length of the string buffer content
+ * @param buf the buffer
+ */
+EAPI size_t
+eina_strbuf_length_get(Eina_Strbuf *buf)
+{
+ return buf->len;
+}
+
+/**
+ * Replace the n-th string with an other string.
+ * @param buf the Eina_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
+eina_strbuf_replace(Eina_Strbuf *buf, const char *str, const char *with,
+ unsigned int n)
+{
+ size_t len1, len2;
+ char *spos;
+ size_t pos;
+
+ 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 (!_eina_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 Eina_Strbuf to work with
+ * @param str the string to replace
+ * @param with the replaceing string
+ *
+ * @return how often the string was replaced
+ */
+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;
+
+ 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 (!_eina_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
+_eina_strbuf_resize(Eina_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 < EINA_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;
+}