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:
parent
9b9ce0e529
commit
0637595ec5
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user