libc: add strtok_r implementation

This is a standard function and useful for applications.

Signed-off-by: Siddharth Chandrasekaran <siddharth@embedjournal.com>
This commit is contained in:
Siddharth Chandrasekaran 2020-08-17 18:46:48 +05:30 committed by Andrew Boie
parent 9b9ce0e529
commit 0637595ec5
3 changed files with 82 additions and 1 deletions

View File

@ -25,6 +25,7 @@ extern size_t strlen(const char *s);
extern size_t strnlen(const char *s, size_t maxlen);
extern int strcmp(const char *s1, const char *s2);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern char *strtok_r(char *str, const char *sep, char **state);
extern char *strcat(char *_MLIBC_RESTRICT dest,
const char *_MLIBC_RESTRICT src);
extern char *strncat(char *_MLIBC_RESTRICT d, const char *_MLIBC_RESTRICT s,

View File

@ -170,6 +170,45 @@ int strncmp(const char *s1, const char *s2, size_t n)
return (n == 0) ? 0 : (*s1 - *s2);
}
/**
* @brief Separate `str` by any char in `sep` and return NULL terminated
* sections. Consecutive `sep` chars in `str` are treated as a single
* separator.
*
* @return pointer to NULL terminated string or NULL on errors.
*/
char *strtok_r(char *str, const char *sep, char **state)
{
char *start, *end;
start = str ? str : *state;
/* skip leading delimiters */
while (*start && strchr(sep, *start)) {
start++;
}
if (*start == '\0') {
*state = start;
return NULL;
}
/* look for token chars */
end = start;
while (*end && !strchr(sep, *end)) {
end++;
}
if (*end != '\0') {
*end = '\0';
*state = end + 1;
} else {
*state = end;
}
return start;
}
char *strcat(char *_MLIBC_RESTRICT dest, const char *_MLIBC_RESTRICT src)
{
strcpy(dest + strlen(dest), src);

View File

@ -558,6 +558,46 @@ void test_tolower_toupper(void)
zassert_equal(strcmp(lw, tolw), 0, "tolower error");
}
void test_strtok_r_do(char *str, char *sep, int tlen,
const char * const *toks, bool expect)
{
int len = 0;
char *state, *tok, buf[64+1] = {0};
strncpy(buf, str, 64);
tok = strtok_r(buf, sep, &state);
while (tok && len < tlen) {
if (strcmp(tok, toks[len]) != 0) {
break;
}
tok = strtok_r(NULL, sep, &state);
len++;
}
if (expect) {
zassert_equal(len, tlen,
"strtok_r error '%s' / '%s'", str, sep);
} else {
zassert_not_equal(len, tlen,
"strtok_r error '%s' / '%s'", str, sep);
}
}
void test_strtok_r(void)
{
static const char * const tc01[] = { "1", "2", "3", "4", "5" };
test_strtok_r_do("1,2,3,4,5", ",", 5, tc01, true);
test_strtok_r_do(",, 1 ,2 ,3 4,5 ", ", ", 5, tc01, true);
test_strtok_r_do("1,,,2 3,,,4 5", ", ", 5, tc01, true);
test_strtok_r_do("1,2 3,,,4 5 ", ", ", 5, tc01, true);
test_strtok_r_do("0,1,,,2 3,,,4 5", ", ", 5, tc01, false);
test_strtok_r_do("1,,,2 3,,,4 5", ",", 5, tc01, false);
test_strtok_r_do("A,,,2,3,,,4 5", ",", 5, tc01, false);
test_strtok_r_do("1,,,2,3,,,", ",", 5, tc01, false);
test_strtok_r_do("1|2|3,4|5", "| ", 5, tc01, false);
}
void test_main(void)
{
ztest_test_suite(test_c_lib,
@ -580,7 +620,8 @@ void test_main(void)
ztest_unit_test(test_checktype),
ztest_unit_test(test_memstr),
ztest_unit_test(test_str_operate),
ztest_unit_test(test_tolower_toupper)
ztest_unit_test(test_tolower_toupper),
ztest_unit_test(test_strtok_r)
);
ztest_run_test_suite(test_c_lib);
}