Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wchar.wmemchr
libc.src.wchar.wcpcpy
libc.src.wchar.wcpncpy
libc.src.wchar.wcstok

# sys/uio.h entrypoints
libc.src.sys.uio.writev
Expand Down
8 changes: 8 additions & 0 deletions libc/include/wchar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ functions:
arguments:
- type: wchar_t *__restrict
- type: const wchar_t *__restrict
- name: wcstok
standards:
- stdc
return_type: wchar_t *
arguments:
- type: wchar_t *__restrict
- type: const wchar_t *__restrict
- type: wchar_t** __restrict
- name: wcpcpy
standards:
- stdc
Expand Down
10 changes: 10 additions & 0 deletions libc/src/wchar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ add_entrypoint_object(
libc.src.__support.wctype_utils
)

add_entrypoint_object(
wcstok
SRCS
wcstok.cpp
HDRS
wcstok.h
DEPENDS
libc.hdr.types.wchar_t
)

add_entrypoint_object(
wcrtomb
SRCS
Expand Down
46 changes: 46 additions & 0 deletions libc/src/wchar/wcstok.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- Implementation of wcstok ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/wchar/wcstok.h"

#include "hdr/types/wchar_t.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(wchar_t *, wcstok,
(wchar_t *__restrict str, const wchar_t *__restrict delim,
wchar_t **__restrict ptr)) {
if (str == nullptr)
str = *ptr;

bool foundTokenStart = false;
wchar_t *out = nullptr;
wchar_t *str_ptr;
for (str_ptr = str; *str_ptr != L'\0'; str_ptr++) {
bool inDelim = false;
for (const wchar_t *delim_ptr = delim; *delim_ptr != L'\0' && !inDelim;
delim_ptr++)
if (*str_ptr == *delim_ptr)
inDelim = true;

if (!inDelim && !foundTokenStart) {
foundTokenStart = true;
out = str_ptr;
} else if (inDelim && foundTokenStart) {
*str_ptr = L'\0';
*ptr = str_ptr + 1;
return out;
}
}

*ptr = str_ptr;
return out;
}

} // namespace LIBC_NAMESPACE_DECL
22 changes: 22 additions & 0 deletions libc/src/wchar/wcstok.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Implementation header for wcstok ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_WCHAR_WCSTOK_H
#define LLVM_LIBC_SRC_WCHAR_WCSTOK_H

#include "hdr/types/wchar_t.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

wchar_t *wcstok(wchar_t *__restrict str, const wchar_t *__restrict delim,
wchar_t **__restrict ptr);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_WCHAR_WCSTOK_H
10 changes: 10 additions & 0 deletions libc/test/src/wchar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ add_libc_test(
libc.src.wchar.wcschr
)

add_libc_test(
wcstok_test
SUITE
libc_wchar_unittests
SRCS
wcstok_test.cpp
DEPENDS
libc.src.wchar.wcstok
)

add_libc_test(
wcsncmp_test
SUITE
Expand Down
145 changes: 145 additions & 0 deletions libc/test/src/wchar/wcstok_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//===-- Unittests for wcstok ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "hdr/types/size_t.h"
#include "hdr/types/wchar_t.h"
#include "src/wchar/wcstok.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStrTokTest, NoTokenFound) {
wchar_t empty[] = L"";
wchar_t *buf;
ASSERT_EQ(LIBC_NAMESPACE::wcstok(empty, L"", &buf), nullptr);
ASSERT_EQ(LIBC_NAMESPACE::wcstok(empty, L"_", &buf), nullptr);

wchar_t single[] = L"_";
wchar_t *token = LIBC_NAMESPACE::wcstok(single, L"", &buf);
ASSERT_TRUE(token[0] == L'_');
ASSERT_TRUE(token[1] == L'\0');

wchar_t multiple[] = L"1,2";
token = LIBC_NAMESPACE::wcstok(multiple, L":", &buf);
ASSERT_TRUE(multiple[0] == L'1');
ASSERT_TRUE(multiple[1] == L',');
ASSERT_TRUE(multiple[2] == L'2');
ASSERT_TRUE(multiple[3] == L'\0');
}

TEST(LlvmLibcStrTokTest, DelimiterAsFirstCharacterShouldBeIgnored) {
wchar_t *buf;
wchar_t src[] = L".123";
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L".", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'3');
ASSERT_TRUE(token[3] == L'\0');
}

TEST(LlvmLibcStrTokTest, DelimiterIsMiddleCharacter) {
wchar_t src[] = L"12,34";
wchar_t *buf;
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L",", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');
}

TEST(LlvmLibcStrTokTest, DelimiterAsLastCharacterShouldBeIgnored) {
wchar_t src[] = L"1234:";
wchar_t *buf;
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L":", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'3');
ASSERT_TRUE(token[3] == L'4');
ASSERT_TRUE(token[4] == L'\0');
}

TEST(LlvmLibcStrTokTest, MultipleDelimiters) {
wchar_t src[] = L"12,.34";
wchar_t *buf;
wchar_t *token;

token = LIBC_NAMESPACE::wcstok(src, L".", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L',');
ASSERT_TRUE(token[3] == L'\0');

token = LIBC_NAMESPACE::wcstok(src, L".,", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(src, L",.", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(src, L":,.", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');
}

TEST(LlvmLibcStrTokTest, ShouldNotGoPastNullTerminator) {
wchar_t src[] = {L'1', L'2', L'\0', L',', L'3'};
wchar_t *buf;
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L",", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');
}

TEST(LlvmLibcStrTokTest, SubsequentCallsShouldFindFollowingDelimiters) {
wchar_t src[] = L"12,34.56";
wchar_t *buf;
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L",.", &buf);
ASSERT_TRUE(token[0] == L'1');
ASSERT_TRUE(token[1] == L'2');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L",.", &buf);
ASSERT_TRUE(token[0] == L'3');
ASSERT_TRUE(token[1] == L'4');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L",.", &buf);
ASSERT_TRUE(token[0] == L'5');
ASSERT_TRUE(token[1] == L'6');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L"_:,_", &buf);
ASSERT_EQ(token, nullptr);
// Subsequent calls after hitting the end of the string should also return
// nullptr.
token = LIBC_NAMESPACE::wcstok(nullptr, L"_:,_", &buf);
ASSERT_EQ(token, nullptr);
}

TEST(LlvmLibcStrTokTest, DelimitersShouldNotBeIncludedInToken) {
wchar_t *buf;
wchar_t src[] = L"__ab__:_cd__:__ef__:__";
wchar_t *token = LIBC_NAMESPACE::wcstok(src, L"_:", &buf);
ASSERT_TRUE(token[0] == L'a');
ASSERT_TRUE(token[1] == L'b');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L":_", &buf);
ASSERT_TRUE(token[0] == L'c');
ASSERT_TRUE(token[1] == L'd');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L"_:,", &buf);
ASSERT_TRUE(token[0] == L'e');
ASSERT_TRUE(token[1] == L'f');
ASSERT_TRUE(token[2] == L'\0');

token = LIBC_NAMESPACE::wcstok(nullptr, L"_:,_", &buf);
ASSERT_EQ(token, nullptr);
}
Loading