diff options
| author | enh-google <enh@google.com> | 2025-08-21 09:32:35 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-21 09:32:35 -0400 |
| commit | 71dd4e17dd6493986e4b3647288d8e4c22a86c44 (patch) | |
| tree | 3703529e82ad1de8027ad413b453190157df65ec /libc/src/string | |
| parent | e90ce511e0dc9230c941af6328d781424b9566b4 (diff) | |
[libc] fix strsep()/strtok()/strtok_r() "subsequent searches" behavior. (#154370)
These functions turned out to have the same bug that was in wcstok()
(fixed by 4fc9801), so add the missing tests and fix the code in a way
that matches wcstok().
Also fix incorrect test expectations in existing tests.
Also update the BUILD.bazel files to actually build the strsep() test.
Diffstat (limited to 'libc/src/string')
| -rw-r--r-- | libc/src/string/string_utils.h | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h index ea2e7b2e9eb4..ce461581b9d9 100644 --- a/libc/src/string/string_utils.h +++ b/libc/src/string/string_utils.h @@ -202,33 +202,36 @@ LIBC_INLINE size_t complementary_span(const char *src, const char *segment) { template <bool SkipDelim = true> LIBC_INLINE char *string_token(char *__restrict src, const char *__restrict delimiter_string, - char **__restrict saveptr) { - // Return nullptr immediately if both src AND saveptr are nullptr - if (LIBC_UNLIKELY(src == nullptr && ((src = *saveptr) == nullptr))) + char **__restrict context) { + // Return nullptr immediately if both src AND context are nullptr + if (LIBC_UNLIKELY(src == nullptr && ((src = *context) == nullptr))) return nullptr; static_assert(CHAR_BIT == 8, "bitset of 256 assumes char is 8 bits"); - cpp::bitset<256> delimiter_set; + cpp::bitset<256> delims; for (; *delimiter_string != '\0'; ++delimiter_string) - delimiter_set.set(static_cast<size_t>(*delimiter_string)); + delims.set(static_cast<size_t>(*delimiter_string)); + char *tok_start = src; if constexpr (SkipDelim) - for (; *src != '\0' && delimiter_set.test(static_cast<size_t>(*src)); ++src) - ; - if (*src == '\0') { - *saveptr = src; + while (*tok_start != '\0' && delims.test(static_cast<size_t>(*tok_start))) + ++tok_start; + if (*tok_start == '\0' && SkipDelim) { + *context = nullptr; return nullptr; } - char *token = src; - for (; *src != '\0'; ++src) { - if (delimiter_set.test(static_cast<size_t>(*src))) { - *src = '\0'; - ++src; - break; - } + + char *tok_end = tok_start; + while (*tok_end != '\0' && !delims.test(static_cast<size_t>(*tok_end))) + ++tok_end; + + if (*tok_end == '\0') { + *context = nullptr; + } else { + *tok_end = '\0'; + *context = tok_end + 1; } - *saveptr = src; - return token; + return tok_start; } LIBC_INLINE size_t strlcpy(char *__restrict dst, const char *__restrict src, |
