* str_icmp,
* str_nicmp - compare two strings ignoring case
*
- * str_delim - locate the first occurrence of a delimiter
+ * str_ichr,
+ * str_irchr - locate character in string ignoring case
*
* str_istr - locate a substring ignoring case
*
* mem_str,
* mem_istr - locate a pattern in memory
*
+ * str_delim - locate the first occurrence of a delimiter in a string
+
+ * str_skip - skip initial sequence of specified characters in a string
+
+ * str_split - break down a string into separate parts
+ *
+ * str_ltrim,
+ * str_rtrim,
+ * str_trim - remove sequences of characters from the ends of a string
+ *
+ * str_clean - remove unwanted characters from string
+ *
+ * str_trans - replace characters in string
+ *
+ * str_toupper,
+ * str_tolower - convert case of characters in string
+ *
*/
#ifndef STR_H_
#include <string.h>
#include <ctype.h>
+#include <stdbool.h>
/*
/*
- * str_delim - locate the first occurrence of a delimiter
+ * str_ichr, str_irchr - locate character in string ignoring case
*
- * The str_delim() function finds the first occurrence in the string s
- * of one of the characters in the string delim.
+ * The str_ichr() function looks for the first occurrence of the character
+ * c in the string s, ignoring the case of both s and c. The str_irchr()
+ * function is similar, but looks for the last occurrence of c in s.
*
- * The function returns a pointer to the first occurrence of one of the
- * specified delimiters, or a pointer to the terminating null character
- * at the end of s, if no such occurrence was found.
+ * The str_ichr() and str_irchr() functions return a pointer to the
+ * matched character, or NULL if the character is not found. The
+ * terminating null byte is considered part of the string, so that if c
+ * is specified as '\0', these function return a pointer to the terminator.
*/
-static inline char *str_delim(const char *s, const char *delim) {
- while (!strchr(delim, *s))
- ++s;
- return (char *)s;
+static inline char *str_ichr(const char *s, int c) {
+ const unsigned char lc = tolower((unsigned char)c);
+ do {
+ if (tolower((unsigned char)*s) == lc)
+ return (char *)s;
+ } while ( *s++ );
+ return NULL;
+}
+
+static inline char *str_irchr(const char *s, int c) {
+ const unsigned char lc = tolower((unsigned char)c);
+ const char *last = NULL;
+ do {
+ if (tolower((unsigned char)*s) == lc)
+ last = s;
+ } while ( *s++ );
+ return (char *)last;
}
return NULL;
}
+
+/*
+ * str_delim - locate the first occurrence of a delimiter
+ *
+ * The str_delim() function finds the first occurrence in the string s
+ * of one of the characters found in dset, or not found in dset, depending
+ * on the value of notin.
+ *
+ * The function returns a pointer to the first occurrence of one of the
+ * specified delimiters, or a pointer to the terminating null character
+ * at the end of s, if no such occurrence was found.
+ */
+static inline char *str_delim(const char *s, const char *dset, bool notin) {
+ while (*s && (!strchr(dset, *s) ^ notin))
+ ++s;
+ return (char *)s;
+}
+
+
+/*
+ * str_skip - skip initial sequence of characters
+ *
+ * The str_skip() function skips any initial sequence in s that consists
+ * entirely of characters found in skipset, or not found in skipset,
+ * depending on the value of notin.
+ *
+ * The function returns a pointer to the first occurrence of a character
+ * not in skipset, or a pointer to the terminating null character at the
+ * end of s, if no such character could be found.
+ */
+static inline char *str_skip(const char *s, const char *skipset, bool notin) {
+ while (*s && (!!strchr(skipset, *s) ^ notin))
+ ++s;
+ return (char *)s;
+}
+
+
+/*
+ * str_split - break down a string into separate parts
+ *
+ * The str_split() function looks for the first occurrence in the string
+ * s of one of the characters in the string sepset. If len is not NULL,
+ * it is used to store the length of the initial sequence of characters
+ * leading up to this first separator. If the STR_SPLIT_DESTR flag is
+ * set, this separator is overwritten with a zero byte. If the
+ * STR_SPLIT_FOLD flag is set, sequences consisting of only separators
+ * are treated as a single separator.
+ *
+ * The str_split() function returns a pointer to the initial sequence, or
+ * a pointer to the terminating null character at the end of s. If len
+ * is not NULL it is used to store the length of this sequence up to the
+ * first separator. If next is not NULL, it is used to store a pointer
+ * to the next character after the first separator. This pointer can be
+ * used in subsequent invocations of str_split() as the first argument
+ * to successively traverse the original input sting in its entirety.
+ *
+ * CAVEAT:
+ * When the STR_SPLIT_DESTR flag is set, the str_split function modifies
+ * the string pointed to by the first argument.
+ *
+ * EXAMPLE:
+ * A very simplistic word extractor might look like this:
+ *
+ * char input[] = ">> Hello, world! How are you? <<";
+ * char *word, *next = input;
+ * size_t len;
+ * while (*next) {
+ * word = str_split(next, " .,!?><", &len, &next,
+ * STR_SPLIT_FOLD | STR_SPLIT_DESTR);
+ * printf("'%s' (%zu)\n", word, len);
+ * }
+ *
+ */
+#define STR_SPLIT_FOLD 0x1U
+#define STR_SPLIT_DESTR 0x2U
+
+static inline char *str_split(const char *s, const char *sepset,
+ size_t *len, char **next, unsigned flags) {
+ char *p;
+
+ if (flags & STR_SPLIT_FOLD)
+ s = str_skip(s, sepset, 0);
+ p = str_delim(s, sepset, 0);
+ if (len)
+ *len = (size_t)(p - s);
+ if (*p) {
+ if ((flags & STR_SPLIT_DESTR))
+ *p = '\0';
+ ++p;
+ }
+ if (next)
+ *next = p;
+ return (char *)s;
+}
+
+
+/*
+ * str_ltrim, str_rtrim, str_trim -
+ * remove unwanted sequences of characters from the ends of a string
+ *
+ * The str_ltrim() function removes from the string s any initial sequence
+ * that consists entirely of characters found in trimset, or not found
+ * in trimset dset, depending on the value of notin. The str_rtrim()
+ * function is similar, except it removes any such sequence from the end
+ * of the string. The str_trim() function performs both operations back
+ * to back.
+ *
+ * The functions each return a pointer to the modified string.
+ */
+static inline char *str_ltrim(char *s, const char *trimset, bool notin) {
+ char *ls = str_skip(s, trimset, notin);
+ return memmove(s, ls, strlen(ls) + 1);
+}
+
+static inline char *str_rtrim(char *s, const char *trimset, bool notin) {
+ *(str_delim(s, trimset, notin)) = '\0';
+ return s;
+}
+
+static inline char *str_trim(char *s, const char *trimset, bool notin) {
+ return str_rtrim(str_ltrim(s, trimset, notin), trimset, notin);
+}
+
+
+/*
+ * str_clean - remove unwanted characters from string
+ *
+ * The str_clean() function removes from the string s any initial sequence
+ * that consists entirely of characters found in delset, or not found in
+ * delset, depending on the value of notin.
+ *
+ * The function returns a pointer to the modified string.
+ */
+static inline char *str_clean(char *s, const char *delset, bool notin) {
+ char *cs = s;
+ for (char *p = cs; *p; ++p )
+ if ( !strchr(delset, *p) ^ notin )
+ *cs++ = *p;
+ *cs = '\0';
+ return s;
+}
+
+
+/*
+ * str_trans - replace characters in string
+ *
+ * The str_trans() function replaces any occurrence in string s of a
+ * chracter that is present in set1 with the corresponding character
+ * from set2.
+ *
+ * CAVEAT:
+ * If set2 is shorter than set1, the behavior is undefined.
+ */
+static inline char *str_trans(char *s, const char *set1, const char *set2) {
+ for (char *cs = s; *cs; ++cs) {
+ char *match;
+ match = strchr(set1, *cs);
+ if (match)
+ *cs = set2[match - set1];
+ }
+ return s;
+}
+
+
+/*
+ * str_toupper, str_tolower - convert case of characters in string
+ *
+ * The str_toupper() function replaces any character in s for which
+ * isupper() is true with its lowercase counterpart. The str_tolower()
+ * function replaces any character in s for which islower() is true with
+ * its lowercase counterpart.
+ */
+static inline char *str_toupper(char *s) {
+ for (unsigned char *cs = (unsigned char *)s; *cs; ++cs)
+ *cs = toupper(*cs);
+ return s;
+}
+
+static inline char *str_tolower(char *s) {
+ for (unsigned char *cs = (unsigned char *)s; *cs; ++cs)
+ *cs = tolower(*cs);
+ return s;
+}
+
+
#ifdef cplusplus
}
#endif
#include <assert.h>
#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
#include "str.h"
#define H(a_) fprintf(stderr, "\n%s\n", a_)
#define D(s_) do{ \
- fprintf(stderr, ". %s = '", #s_); \
+ fprintf(stderr, ". %s = \"", #s_); \
for (int i = 0; i < (int)sizeof(s_); ++i) { \
if (s_[i] == 0) \
fprintf(stderr, "\\0"); \
else \
fputc(s_[i], stderr); \
} \
- fprintf(stderr, "'\n"); \
+ fprintf(stderr, "\"\n"); \
}while(0) \
int main(void) {
- H("str_icmp");
- T(str_icmp("asdf", "") > 0);
- T(str_icmp("", "asdf") < 0);
- T(str_icmp("asdf", "b") < 0);
- T(str_icmp("b", "asdf") > 0);
- T(str_icmp("asdfまほ", "asdfまほ") == 0);
- T(str_icmp("Asdf", "asdf") == 0);
- T(str_icmp("まほaSdf", "まほasdF") == 0);
- T(str_icmp("asdf", "asdF") == 0);
-
- H("str_nicmp");
- T(str_nicmp(NULL, NULL, 0) == 0);
- T(str_nicmp(NULL, "x", 0) == 0);
- T(str_nicmp("x", NULL, 0) == 0);
- T(str_nicmp("asdf", NULL, 0) == 0);
- T(str_nicmp("asdf", NULL, 0) == 0);
- T(str_nicmp("asdf", "", 0) == 0);
- T(str_nicmp("asdf", "a", 1) == 0);
- T(str_nicmp("a", "asdf", 1) == 0);
- T(str_nicmp("asdf", "ab", 1) == 0);
- T(str_nicmp("ab", "asdf", 1) == 0);
- T(str_nicmp("asdf", "ab", 2) > 0);
- T(str_nicmp("ab", "asdf", 2) < 0);
- T(str_nicmp("asdfまほ", "asdまほ", 1) == 0);
- T(str_nicmp("Asdf", "asdf", 1) == 0);
- T(str_nicmp("まほaSdf", "まほasdF", 1) == 0);
- T(str_nicmp("asdf", "asdF", 1) == 0);
-
- H("str_delim");
- char s1[] = "abc:def,\r\n\tghi";
- D(s1);
- T(str_delim(s1, "") - s1 == (int)strlen(s1));
- T(str_delim(s1, "*") - s1 == (int)strlen(s1));
- T(str_delim(s1, "i") - s1 == (int)strlen(s1)-1);
- T(str_delim(s1, ":") - s1 == 3);
- T(str_delim(s1, "-_:") - s1 == 3);
- T(str_delim(s1, "e,") - s1 == 5);
- T(str_delim(s1, ",#'") - s1 == 7);
- T(str_delim(s1, "\n\r") - s1 == 8);
-
- H("str_istr");
- char h1[] = "asdfま\0ほyxc";
- char h2[] = "";
- D(h1);
- D(h2);
- T(str_istr(NULL, NULL) == NULL);
- T(str_istr(h2, NULL) == h2);
- T(str_istr(NULL, "") == NULL);
- T(str_istr(h2, "") == h2);
- T(str_istr(h1, "") == h1);
- T(str_istr(h2, "\0\0") == h2);
- T(str_istr("", "a") == NULL);
- T(str_istr(h1, "xoxoxoxo") == NULL);
- T(str_istr(h1, "S") == h1 + 1);
- T(str_istr(h1, "as") == h1);
- T(str_istr(h1, "df") == h1 + 2);
- T(str_istr(h1, "As") == h1);
- T(str_istr(h1, "dF") == h1 + 2);
- T(str_istr(h1, "X") == NULL);
- T(str_istr(h1, "yxc") == NULL);
-
- H("mem_mem");
- char m1[] = { 1,'s','d','f', 0,'y','x','c', -1 };
- char m2[] = { 'a','b','c', 0 };
- D(m1);
- D(m2);
- T(mem_mem(NULL, 0, NULL, 0) == NULL);
- T(mem_mem(m2, 0, NULL, 0) == m2);
- T(mem_mem(m2, 0, "", 0) == m2);
- T(mem_mem(NULL, 0, m2, 0) == NULL);
- T(mem_mem(NULL, 0, "", 0) == NULL);
- T(mem_mem(m2, 3, "abc", 3) == m2);
- T(mem_mem(m2, 4, "abc", 4) == m2);
- T(mem_mem(m1, sizeof m1, "", 0) == m1);
- T(mem_mem(m1, sizeof m1, NULL, 0) == m1);
- T(mem_mem(m1, sizeof m1, "\x01s", 2) == m1);
- T(mem_mem(m1, sizeof m1, "f\0y", 3) == m1 + 3);
- T(mem_mem(m1, sizeof m1, "f\0y" + 1, 2) == m1 + 4);
- T(mem_mem(m1, sizeof m1, "f\0Y" + 1, 2) == NULL);
- T(mem_mem(m1, sizeof m1, (char[]){-1}, 1) == m1 + 8);
- T(mem_mem(m1, sizeof m1, "xc", 3) == NULL);
- T(mem_mem(m1, sizeof m1, "xc", 2) == m1 + 6);
-
- H("mem_str");
- D(m1);
- T(mem_str(NULL, 0, NULL) == NULL);
- T(mem_str(NULL, 0, "") == NULL);
- T(mem_str(m1, 0, NULL) == m1);
- T(mem_str(m1, 0, "") == m1);
- T(mem_str(m1, sizeof m1, "") == m1);
- T(mem_str(m1, sizeof m1, NULL) == m1);
- T(mem_str(m1, sizeof m1, "sdf") == m1 + 1);
- T(mem_str(m1, sizeof m1, "yxc") == m1 + 5);
- T(mem_str(m1, sizeof m1, "yxc\0qwe") == m1 + 5);
- T(mem_str(m1, sizeof m1, "yXc\0qwe") == NULL);
-
- H("mem_istr");
- D(m1);
- T(mem_istr(NULL, 0, NULL) == NULL);
- T(mem_istr(NULL, 0, "") == NULL);
- T(mem_istr(m1, 0, NULL) == m1);
- T(mem_istr(m1, 0, "") == m1);
- T(mem_istr(m1, sizeof m1, "") == m1);
- T(mem_istr(m1, sizeof m1, NULL) == m1);
- T(mem_istr(m1, sizeof m1, "") == m1);
- T(mem_istr(m1, sizeof m1, "sDf") == m1 + 1);
- T(mem_istr(m1, sizeof m1, "Yxc") == m1 + 5);
- T(mem_istr(m1, sizeof m1, "yxC\0qwe") == m1 + 5);
+ /*****************************************/
+
+ {
+ H("str_icmp");
+ T(str_icmp("asdf", "") > 0);
+ T(str_icmp("", "asdf") < 0);
+ T(str_icmp("asdf", "b") < 0);
+ T(str_icmp("b", "asdf") > 0);
+ T(str_icmp("asdfまほ", "asdfまほ") == 0);
+ T(str_icmp("Asdf", "asdf") == 0);
+ T(str_icmp("まほaSdf", "まほasdF") == 0);
+ T(str_icmp("asdf", "asdF") == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_nicmp");
+ T(str_nicmp(NULL, NULL, 0) == 0);
+ T(str_nicmp(NULL, "x", 0) == 0);
+ T(str_nicmp("x", NULL, 0) == 0);
+ T(str_nicmp("asdf", NULL, 0) == 0);
+ T(str_nicmp("asdf", NULL, 0) == 0);
+ T(str_nicmp("asdf", "", 0) == 0);
+ T(str_nicmp("asdf", "a", 1) == 0);
+ T(str_nicmp("a", "asdf", 1) == 0);
+ T(str_nicmp("asdf", "ab", 1) == 0);
+ T(str_nicmp("ab", "asdf", 1) == 0);
+ T(str_nicmp("asdf", "ab", 2) > 0);
+ T(str_nicmp("ab", "asdf", 2) < 0);
+ T(str_nicmp("asdfまほ", "asdまほ", 1) == 0);
+ T(str_nicmp("Asdf", "asdf", 1) == 0);
+ T(str_nicmp("まほaSdf", "まほasdF", 1) == 0);
+ T(str_nicmp("asdf", "asdF", 1) == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_ichr, str_irchr");
+ const char s[] = "abcdABCD";
+ D(s);
+ T(str_ichr(s, 'a') - s == 0);
+ T(str_ichr(s, 'A') - s == 0);
+ T(str_ichr(s, 'b') - s == 1);
+ T(str_ichr(s, 'B') - s == 1);
+ T(str_irchr(s, 'a') - s == 4);
+ T(str_irchr(s, 'A') - s == 4);
+ T(str_irchr(s, 'd') - s == 7);
+ T(str_irchr(s, 'D') - s == 7);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_istr");
+ char h1[] = "asdfま\0ほyxc";
+ char h2[] = "";
+ D(h1);
+ D(h2);
+ T(str_istr(NULL, NULL) == NULL);
+ T(str_istr(h2, NULL) == h2);
+ T(str_istr(NULL, "") == NULL);
+ T(str_istr(h2, "") == h2);
+ T(str_istr(h1, "") == h1);
+ T(str_istr(h2, "\0\0") == h2);
+ T(str_istr("", "a") == NULL);
+ T(str_istr(h1, "xoxoxoxo") == NULL);
+ T(str_istr(h1, "S") == h1 + 1);
+ T(str_istr(h1, "as") == h1);
+ T(str_istr(h1, "df") == h1 + 2);
+ T(str_istr(h1, "As") == h1);
+ T(str_istr(h1, "dF") == h1 + 2);
+ T(str_istr(h1, "X") == NULL);
+ T(str_istr(h1, "yxc") == NULL);
+ }
+
+ /*****************************************/
+
+ {
+ H("mem_mem");
+ char m1[] = { 1,'s','d','f', 0,'y','x','c', -1 };
+ char m2[] = { 'a','b','c', 0 };
+ D(m1);
+ D(m2);
+ T(mem_mem(NULL, 0, NULL, 0) == NULL);
+ T(mem_mem(m2, 0, NULL, 0) == m2);
+ T(mem_mem(m2, 0, "", 0) == m2);
+ T(mem_mem(NULL, 0, m2, 0) == NULL);
+ T(mem_mem(NULL, 0, "", 0) == NULL);
+ T(mem_mem(m2, 3, "abc", 3) == m2);
+ T(mem_mem(m2, 4, "abc", 4) == m2);
+ T(mem_mem(m1, sizeof m1, "", 0) == m1);
+ T(mem_mem(m1, sizeof m1, NULL, 0) == m1);
+ T(mem_mem(m1, sizeof m1, "\x01s", 2) == m1);
+ T(mem_mem(m1, sizeof m1, "f\0y", 3) == m1 + 3);
+ T(mem_mem(m1, sizeof m1, "f\0y" + 1, 2) == m1 + 4);
+ T(mem_mem(m1, sizeof m1, "f\0Y" + 1, 2) == NULL);
+ T(mem_mem(m1, sizeof m1, (char[]){-1}, 1) == m1 + 8);
+ T(mem_mem(m1, sizeof m1, "xc", 3) == NULL);
+ T(mem_mem(m1, sizeof m1, "xc", 2) == m1 + 6);
+ }
+
+ /*****************************************/
+
+ {
+ H("mem_str");
+ char m1[] = { 1,'s','d','f', 0,'y','x','c', -1 };
+ D(m1);
+ T(mem_str(NULL, 0, NULL) == NULL);
+ T(mem_str(NULL, 0, "") == NULL);
+ T(mem_str(m1, 0, NULL) == m1);
+ T(mem_str(m1, 0, "") == m1);
+ T(mem_str(m1, sizeof m1, "") == m1);
+ T(mem_str(m1, sizeof m1, NULL) == m1);
+ T(mem_str(m1, sizeof m1, "sdf") == m1 + 1);
+ T(mem_str(m1, sizeof m1, "yxc") == m1 + 5);
+ T(mem_str(m1, sizeof m1, "yxc\0qwe") == m1 + 5);
+ T(mem_str(m1, sizeof m1, "yXc\0qwe") == NULL);
+ }
+
+ /*****************************************/
+
+ {
+ H("mem_istr");
+ char m1[] = { 1,'s','d','f', 0,'y','x','c', -1 };
+ D(m1);
+ T(mem_istr(NULL, 0, NULL) == NULL);
+ T(mem_istr(NULL, 0, "") == NULL);
+ T(mem_istr(m1, 0, NULL) == m1);
+ T(mem_istr(m1, 0, "") == m1);
+ T(mem_istr(m1, sizeof m1, "") == m1);
+ T(mem_istr(m1, sizeof m1, NULL) == m1);
+ T(mem_istr(m1, sizeof m1, "") == m1);
+ T(mem_istr(m1, sizeof m1, "sDf") == m1 + 1);
+ T(mem_istr(m1, sizeof m1, "Yxc") == m1 + 5);
+ T(mem_istr(m1, sizeof m1, "yxC\0qwe") == m1 + 5);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_delim");
+ char s1[] = "abc:def,\r\n\tghi";
+ D(s1);
+ T(str_delim(s1, "", false) - s1 == (int)strlen(s1));
+ T(str_delim(s1, "*", false) - s1 == (int)strlen(s1));
+ T(str_delim(s1, "i", false) - s1 == (int)strlen(s1)-1);
+ T(str_delim(s1, "i", true) - s1 == 0);
+ T(str_delim(s1, ":", false) - s1 == 3);
+ T(str_delim(s1, "abc", true) - s1 == 3);
+ T(str_delim(s1, "-_:", false) - s1 == 3);
+ T(str_delim(s1, "e,", false) - s1 == 5);
+ T(str_delim(s1, ",#'", false) - s1 == 7);
+ T(str_delim(s1, "\n\r", false) - s1 == 8);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_split");
+ char in1[] = ">> Hello, world! How are you? <<";
+ char d1[] = " .,!?<>";
+ D(in1);
+ D(d1);
+ char *tok, *next = in1;
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "Hello") == 0);
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "world") == 0);
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "How") == 0);
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "are") == 0);
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "you") == 0);
+ tok = str_split(next, d1, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ D(in1);
+ T(strcmp(tok, "") == 0);
+
+ char in2[] = ">> Hello, world! How are you? <<";
+ char d2[] = "";
+ D(in2);
+ D(d2);
+ next = in2;
+ tok = str_split(next, d2, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, in2) == 0);
+
+ char in3[] = ">> Hello, world! How are you? <<";
+ char d3[] = " ";
+ D(in3);
+ D(d3);
+ next = in3;
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, ">>") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "Hello,") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "world!") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "How") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "are") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "you?") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "<<") == 0);
+ tok = str_split(next, d3, NULL, &next, STR_SPLIT_FOLD|STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+
+ char in4[] = ",,,0,1,,pi,";
+ char d4[] = ",";
+ D(in4);
+ D(d4);
+ next = in4;
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "0") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "1") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "pi") == 0);
+ T(tok != next);
+ tok = str_split(next, d4, NULL, &next, STR_SPLIT_DESTR);
+ T(strcmp(tok, "") == 0);
+ T(tok == next);
+
+ size_t len;
+ char in5[] = "fourty;;two";
+ char d5[] = ";";
+ D(in5);
+ D(d5);
+ next = in5;
+ tok = str_split(next, d5, &len, &next, 0);
+ T(strncmp(tok, "fourty", len) == 0 && len == 6);
+ tok = str_split(next, d5, &len, &next, 0);
+ T(strncmp(tok, "", len) == 0 && len == 0);
+ tok = str_split(next, d5, &len, &next, 0);
+ T(strncmp(tok, "two", len) == 0 && len == 3);
+ tok = str_split(next, d5, &len, &next, 0);
+ T(strncmp(tok, "", len) == 0 && len == 0);
+ T(tok == next && len == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_ltrim, str_rtrim, str_trim");
+ char s1[] = ",.-XXX,.-";
+ D(s1);
+ T(strcmp(str_ltrim(s1, "-,.", false), "XXX,.-") == 0);
+ D(s1);
+ T(strcmp(str_rtrim(s1, "-,.", false), "XXX") == 0);
+ D(s1);
+ T(strcmp(str_rtrim(s1, "-,.", true), "") == 0);
+ char s2[] = "***XXX***";
+ D(s2);
+ T(strcmp(str_trim(s2, "*", false), "XXX") == 0);
+ char s3[] = "XXX***XXX";
+ D(s3);
+ T(strcmp(str_trim(s3, "*", true), "***") == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_clean");
+ char s1[] = "a1b2c3 45def6";
+ D(s1);
+ T(strcmp(str_clean(s1, "0123456789", false), "abc def") == 0);
+ D(s1);
+ T(strcmp(str_clean(s1, "0123456789", true), "") == 0);
+ char s2[] = "a1b2c3 45def6";
+ D(s2);
+ T(strcmp(str_clean(s2, "0123456789", true), "123456") == 0);
+ D(s2);
+ T(strcmp(str_clean(s2, "0123456789", false), "") == 0);
+ char s3[] = "123abc4d";
+ char s4[] = "123abc4d";
+ D(s3);
+ D(s4);
+ T(strcmp(str_clean(s3, "1234", false), str_clean(s4, "abcd", true)) == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_trans");
+ char s1[] = "a,b,c,43";
+ D(s1);
+ T(strcmp(str_trans(s1, ",3", ";2"), "a;b;c;42") == 0);
+ T(strcmp(str_trans(s1, "", ""), "a;b;c;42") == 0);
+ T(strcmp(str_trans("", "x", "y"), "") == 0);
+ }
+
+ /*****************************************/
+
+ {
+ H("str_toupper, str_tolower");
+ char s1[] = "MiXed CaSe 101";
+ char s2[] = "202 MiXed CaSe";
+ D(s1);
+ T(strcmp(str_toupper(s1), "MIXED CASE 101") == 0);
+ T(strcmp(str_tolower(s1), "mixed case 101") == 0);
+ D(s2);
+ T(strcmp(str_tolower(s2), "202 mixed case") == 0);
+ T(strcmp(str_toupper(s2), "202 MIXED CASE") == 0);
+ T(strcmp(str_toupper(""), "") == 0);
+ T(strcmp(str_tolower(""), "") == 0);
+ }
+
+ /*****************************************/
H("All tests passed.");
return 0;