eina_matrixsparse.h \
eina_inline_tiler.x \
eina_str.h \
+eina_inline_str.x \
eina_strbuf.h
installed_mainheaderdir = $(includedir)/eina-@VMAJ@
--- /dev/null
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_STR_INLINE_H_
+#define EINA_STR_INLINE_H_
+
+/**
+ * @addtogroup Eina_Str_Group Str
+ *
+ * @{
+ */
+
+/**
+ * strlen() that will count up to maxlen bytes.
+ *
+ * If one wants to know the size of @a str, but it should not be
+ * greater than @a maxlen, then use this function and avoid needless
+ * iterations after that size.
+ *
+ * @param str the string pointer, must be valid and not @c NULL.
+ * @param maxlen the maximum length to allow.
+ * @return the string size or (size_t)-1 if greater than @a maxlen.
+ */
+static inline size_t
+eina_strlen_bounded(const char *str, size_t maxlen)
+{
+ const char *itr, *str_maxend = str + maxlen;
+ for (itr = str; *itr != '\0'; itr++)
+ if (itr == str_maxend) return (size_t)-1;
+ return itr - str;
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STR_INLINE_H_ */
*/
/* 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 size_t eina_strlcpy(char *dst, const char *src, size_t siz) EINA_ARG_NONNULL(1, 2);
+EAPI size_t eina_strlcat(char *dst, const char *src, size_t siz) EINA_ARG_NONNULL(1, 2);
-EAPI Eina_Bool eina_str_has_prefix(const char *str, const char *prefix);
+EAPI Eina_Bool eina_str_has_prefix(const char *str, const char *prefix) EINA_PURE EINA_ARG_NONNULL(1, 2);
-EAPI Eina_Bool eina_str_has_suffix(const char *str, const char *suffix);
-EAPI Eina_Bool eina_str_has_extension(const char *str, const char *ext);
+EAPI Eina_Bool eina_str_has_suffix(const char *str, const char *suffix) EINA_PURE EINA_ARG_NONNULL(1, 2);
+EAPI Eina_Bool eina_str_has_extension(const char *str, const char *ext) EINA_PURE EINA_ARG_NONNULL(1, 2);
-EAPI char **eina_str_split(const char *string, const char *delimiter,
- int max_tokens);
+EAPI char **eina_str_split(const char *string, const char *delimiter, int max_tokens) EINA_ARG_NONNULL(1, 2);
+EAPI char **eina_str_split_full(const char *string, const char *delimiter, int max_tokens, unsigned int *elements) EINA_ARG_NONNULL(1, 2, 3);
-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);
+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) EINA_ARG_NONNULL(1, 4, 6);
-EAPI char *eina_str_convert(const char *enc_from, const char *enc_to, const char *text);
+EAPI char *eina_str_convert(const char *enc_from, const char *enc_to, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_ARG_NONNULL(1, 2, 3);
-EAPI char *eina_str_escape(const char *str);
+EAPI char *eina_str_escape(const char *str) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_ARG_NONNULL(1);
+static inline size_t eina_str_join(char *dst, size_t size, char sep, const char *a, const char *b) EINA_ARG_NONNULL(1, 4, 5);
+
/**
* @brief Join two strings of known length.
*
*/
#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)
+static inline size_t eina_strlen_bounded(const char *str, size_t maxlen) EINA_PURE EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+#include "eina_inline_str.x"
+
#endif /* EINA_STR_H */
# include "config.h"
#endif
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
* Internal helper function used by eina_str_has_suffix() and
* eina_str_has_extension()
*/
-static Eina_Bool
+static inline Eina_Bool
eina_str_has_suffix_helper(const char *str,
const char *suffix,
int (*cmp)(const char *, const char *))
size_t suffix_len;
str_len = strlen(str);
- suffix_len = strlen(suffix);
- if (suffix_len > str_len)
+ suffix_len = eina_strlen_bounded(suffix, str_len);
+ if (suffix_len == (size_t)-1)
return EINA_FALSE;
return cmp(str + str_len - suffix_len, suffix) == 0;
}
+static inline char **
+eina_str_split_full_helper(const char *str, const char *delim, int max_tokens, unsigned int *elements)
+{
+ char *s, **str_array;
+ const char *src;
+ size_t len, dlen;
+ unsigned int tokens;
+
+ dlen = strlen(delim);
+ if (dlen == 0)
+ {
+ if (elements) *elements = 0;
+ return NULL;
+ }
+
+ tokens = 0;
+ src = str;
+ /* count tokens and check strlen(str) */
+ while (*src != '\0')
+ {
+ const char *d = delim, *d_end = d + dlen;
+ const char *tmp = src;
+ for (; (d < d_end) && (*tmp != '\0'); d++, tmp++)
+ {
+ if (EINA_LIKELY(*d != *tmp))
+ break;
+ }
+ if (EINA_UNLIKELY(d == d_end))
+ {
+ src = tmp;
+ tokens++;
+ }
+ else
+ src++;
+ }
+ len = src - str;
+
+ if ((max_tokens > 0) && (tokens > (unsigned int)max_tokens))
+ tokens = max_tokens;
+
+ str_array = malloc(sizeof(char *) * (tokens + 2));
+ if (!str_array)
+ {
+ if (elements) *elements = 0;
+ return NULL;
+ }
+
+ s = malloc(len + 1);
+ if (!s)
+ {
+ free(str_array);
+ if (elements) *elements = 0;
+ return NULL;
+ }
+
+ /* copy tokens and string */
+ tokens = 0;
+ str_array[0] = s;
+ src = str;
+ while (*src != '\0')
+ {
+ const char *d = delim, *d_end = d + dlen;
+ const char *tmp = src;
+ for (; (d < d_end) && (*tmp != '\0'); d++, tmp++)
+ {
+ if (EINA_LIKELY(*d != *tmp))
+ break;
+ }
+ if (EINA_UNLIKELY(d == d_end))
+ {
+ src = tmp;
+ *s = '\0';
+ s += dlen;
+ tokens++;
+ str_array[tokens] = s;
+ }
+ else
+ {
+ *s = *src;
+ s++;
+ src++;
+ }
+ }
+ *s = '\0';
+ str_array[tokens + 1] = NULL;
+ if (elements) *elements = (tokens + 1);
+ return str_array;
+}
+
/**
* @endcond
*/
size_t prefix_len;
str_len = strlen(str);
- prefix_len = strlen(prefix);
- if (prefix_len > str_len)
+ prefix_len = eina_strlen_bounded(prefix, str_len);
+ if (prefix_len == (size_t)-1)
return EINA_FALSE;
return (strncmp(str, prefix, prefix_len) == 0);
}
/**
- * @brief Split a string using a delimiter.
+ * @brief Split a string using a delimiter and returns number of elements.
*
* @param str The string to split.
* @param delim The string which specifies the places at which to split the string.
* @param max_tokens The maximum number of strings to split string into.
+ * @param elements Where to return the number of elements in returned
+ * array (not counting the terminating @c NULL). May be @c NULL.
* @return A newly-allocated NULL-terminated array of strings.
*
* This functin splits @p str into a maximum of @p max_tokens pieces,
* array contains the remainder of string. The returned value is a
* newly allocated NUL-terminated array of string. To free it, free
* the first element of the array and the array itself.
+ *
+ * @see eina_str_split()
*/
EAPI char **
-eina_str_split(const char *str, const char *delim, int max_tokens)
+eina_str_split_full(const char *str, const char *delim, int max_tokens, unsigned int *elements)
{
- 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;
- }
+ return eina_str_split_full_helper(str, delim, max_tokens, elements);
+}
- str_array[i++] = s;
- str_array = realloc(str_array, sizeof(char *) * (i + 1));
- str_array[i] = NULL;
- return str_array;
+/**
+ * @brief Split a string using a delimiter.
+ *
+ * @param str The string to split.
+ * @param delim The string which specifies the places at which to split the string.
+ * @param max_tokens The maximum number of strings to split string into.
+ * @return A newly-allocated NULL-terminated array of strings.
+ *
+ * This functin splits @p str into a maximum of @p max_tokens pieces,
+ * using the given delimiter @p delim. @p delim is not included in any
+ * of the resulting strings, unless @p max_tokens is reached. If
+ * @p max_tokens is less than @c 1, the string is splitted completely. If
+ * @p max_tokens is reached, the last string in the returned string
+ * array contains the remainder of string. The returned value is a
+ * newly allocated NUL-terminated array of string. To free it, free
+ * the first element of the array and the array itself.
+ */
+EAPI char **
+eina_str_split(const char *str, const char *delim, int max_tokens)
+{
+ return eina_str_split_full_helper(str, delim, max_tokens, NULL);
}
/**
eina_test_list.c \
eina_test_matrixsparse.c \
eina_test_tiler.c \
-eina_test_strbuf.c
+eina_test_strbuf.c \
+eina_test_str.c
eina_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libeina.la
{ "Matrix Sparse", eina_test_matrixsparse },
{ "Eina Tiler", eina_test_tiler },
{ "Eina Strbuf", eina_test_strbuf },
+ { "String", eina_test_str },
{ NULL, NULL }
};
void eina_test_matrixsparse(TCase *tc);
void eina_test_tiler(TCase *tc);
void eina_test_strbuf(TCase *tc);
+void eina_test_str(TCase *tc);
#endif /* EINA_SUITE_H_ */
--- /dev/null
+/* EINA - EFL data type library
+ * Copyright (C) 2010 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "eina_suite.h"
+#include "Eina.h"
+
+START_TEST(str_simple)
+{
+ eina_init();
+
+ fail_if(!eina_str_has_prefix("", ""));
+
+ fail_if(!eina_str_has_prefix("x", "x"));
+ fail_if(!eina_str_has_prefix("xab", "x"));
+ fail_if(!eina_str_has_prefix("xab", "xab"));
+
+ fail_if(eina_str_has_prefix("x", "xab"));
+ fail_if(eina_str_has_prefix("xab", "xyz"));
+ fail_if(eina_str_has_prefix("", "x"));
+ fail_if(eina_str_has_prefix("X", "x"));
+ fail_if(eina_str_has_prefix("xAb", "X"));
+ fail_if(eina_str_has_prefix("xAb", "xab"));
+
+
+ fail_if(!eina_str_has_suffix("", ""));
+
+ fail_if(!eina_str_has_suffix("x", "x"));
+ fail_if(!eina_str_has_suffix("abx", "x"));
+ fail_if(!eina_str_has_suffix("xab", "xab"));
+
+ fail_if(eina_str_has_suffix("x", "xab"));
+ fail_if(eina_str_has_suffix("xab", "xyz"));
+ fail_if(eina_str_has_suffix("", "x"));
+ fail_if(eina_str_has_suffix("X", "x"));
+ fail_if(eina_str_has_suffix("aBx", "X"));
+ fail_if(eina_str_has_suffix("xaB", "Xab"));
+
+
+ fail_if(!eina_str_has_extension("", ""));
+
+ fail_if(!eina_str_has_extension("x", "x"));
+ fail_if(!eina_str_has_extension("abx", "x"));
+ fail_if(!eina_str_has_extension("xab", "xab"));
+ fail_if(!eina_str_has_extension("x", "X"));
+ fail_if(!eina_str_has_extension("abx", "X"));
+ fail_if(!eina_str_has_extension("xab", "Xab"));
+ fail_if(!eina_str_has_extension("X", "X"));
+ fail_if(!eina_str_has_extension("aBx", "X"));
+ fail_if(!eina_str_has_extension("xaB", "Xab"));
+
+ fail_if(eina_str_has_extension("x", "xab"));
+ fail_if(eina_str_has_extension("xab", "xyz"));
+ fail_if(eina_str_has_extension("", "x"));
+ fail_if(eina_str_has_extension("x", "xAb"));
+ fail_if(eina_str_has_extension("xab", "xYz"));
+ fail_if(eina_str_has_extension("", "x"));
+
+ fail_if(eina_strlen_bounded("abc", 1024) != strlen("abc"));
+ fail_if(eina_strlen_bounded("abc", 2) != (size_t)-1);
+
+ eina_shutdown();
+}
+END_TEST
+
+START_TEST(str_split)
+{
+ char **result;
+ unsigned int elements;
+
+ eina_init();
+
+ result = eina_str_split_full("nomatch", "", -1, &elements);
+ fail_if(result != NULL);
+ fail_if(elements != 0);
+
+ result = eina_str_split_full("nomatch", "x", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 1);
+ fail_if(strcmp(result[0], "nomatch") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("nomatch", "xyz", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 1);
+ fail_if(strcmp(result[0], "nomatch") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("match:match:match", ":", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 3);
+ while (elements >= 1)
+ {
+ elements--;
+ fail_if(strcmp(result[elements], "match") != 0);
+ }
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("a:b:c", ":", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 3);
+ fail_if(strcmp(result[0], "a") != 0);
+ fail_if(strcmp(result[1], "b") != 0);
+ fail_if(strcmp(result[2], "c") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("a:b:", ":", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 3);
+ fail_if(strcmp(result[0], "a") != 0);
+ fail_if(strcmp(result[1], "b") != 0);
+ fail_if(strcmp(result[2], "") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full(":b:c", ":", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 3);
+ fail_if(strcmp(result[0], "") != 0);
+ fail_if(strcmp(result[1], "b") != 0);
+ fail_if(strcmp(result[2], "c") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full(":", ":", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 2);
+ fail_if(strcmp(result[0], "") != 0);
+ fail_if(strcmp(result[1], "") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("a", "!!!!!!!!!", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 1);
+ fail_if(strcmp(result[0], "a") != 0);
+ free(result[0]);
+ free(result);
+
+ result = eina_str_split_full("aaba", "ab", -1, &elements);
+ fail_if(result == NULL);
+ fail_if(elements != 2);
+ fail_if(strcmp(result[0], "a") != 0);
+ fail_if(strcmp(result[1], "a") != 0);
+ free(result[0]);
+ free(result);
+
+ eina_shutdown();
+}
+END_TEST
+
+void
+eina_test_str(TCase *tc)
+{
+ tcase_add_test(tc, str_simple);
+ tcase_add_test(tc, str_split);
+}