Skip to content

Commit a911543

Browse files
authored
[libc] Implemented wcrtomb internal function and public libc function (#144596)
Implemented internal wcrtomb function using the CharacterConverter class public libc function calls this internal function to perform the conversion
1 parent f0d3257 commit a911543

File tree

10 files changed

+289
-0
lines changed

10 files changed

+289
-0
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,7 @@ if(LLVM_LIBC_FULL_BUILD)
12471247

12481248
# wchar.h entrypoints
12491249
libc.src.wchar.mbrtowc
1250+
libc.src.wchar.wcrtomb
12501251
)
12511252
endif()
12521253

libc/include/wchar.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ functions:
159159
- type: wchar_t *__restrict
160160
- type: const wchar_t *__restrict
161161
- type: size_t
162+
- name: wcrtomb
163+
standards:
164+
- stdc
165+
return_type: size_t
166+
arguments:
167+
- type: char *__restrict
168+
- type: wchar_t
169+
- type: mbstate_t *__restrict
162170
- name: wcscpy
163171
standards:
164172
- stdc

libc/src/__support/wchar/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ add_object_library(
2020
.mbstate
2121
)
2222

23+
add_object_library(
24+
wcrtomb
25+
HDRS
26+
wcrtomb.h
27+
SRCS
28+
wcrtomb.cpp
29+
DEPENDS
30+
libc.hdr.types.char32_t
31+
libc.hdr.types.size_t
32+
libc.hdr.types.wchar_t
33+
libc.src.__support.error_or
34+
libc.src.__support.common
35+
.character_converter
36+
.mbstate
37+
)
38+
2339
add_object_library(
2440
mbrtowc
2541
HDRS

libc/src/__support/wchar/wcrtomb.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===-- Implementation of wcrtomb -----------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/wchar/wcrtomb.h"
10+
#include "src/__support/error_or.h"
11+
#include "src/__support/wchar/character_converter.h"
12+
#include "src/__support/wchar/mbstate.h"
13+
14+
#include "hdr/types/char32_t.h"
15+
#include "hdr/types/size_t.h"
16+
#include "hdr/types/wchar_t.h"
17+
#include "src/__support/common.h"
18+
#include "src/__support/libc_assert.h"
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
namespace internal {
22+
23+
ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc,
24+
mbstate *__restrict ps) {
25+
static_assert(sizeof(wchar_t) == 4);
26+
27+
CharacterConverter cr(ps);
28+
29+
if (s == nullptr)
30+
return Error(-1);
31+
32+
int status = cr.push(static_cast<char32_t>(wc));
33+
if (status != 0)
34+
return Error(status);
35+
36+
size_t count = 0;
37+
while (!cr.isEmpty()) {
38+
auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded
39+
LIBC_ASSERT(utf8.has_value());
40+
41+
*s = utf8.value();
42+
s++;
43+
count++;
44+
}
45+
return count;
46+
}
47+
48+
} // namespace internal
49+
} // namespace LIBC_NAMESPACE_DECL

libc/src/__support/wchar/wcrtomb.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===-- Implementation header for wcrtomb ---------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H
10+
#define LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H
11+
12+
#include "hdr/types/size_t.h"
13+
#include "hdr/types/wchar_t.h"
14+
#include "src/__support/error_or.h"
15+
#include "src/__support/macros/config.h"
16+
#include "src/__support/wchar/mbstate.h"
17+
18+
namespace LIBC_NAMESPACE_DECL {
19+
namespace internal {
20+
21+
ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps);
22+
23+
} // namespace internal
24+
} // namespace LIBC_NAMESPACE_DECL
25+
26+
#endif // LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H

libc/src/wchar/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ add_entrypoint_object(
3434
libc.src.__support.wctype_utils
3535
)
3636

37+
add_entrypoint_object(
38+
wcrtomb
39+
SRCS
40+
wcrtomb.cpp
41+
HDRS
42+
wcrtomb.h
43+
DEPENDS
44+
libc.hdr.types.wchar_t
45+
libc.hdr.types.mbstate_t
46+
libc.src.__support.libc_errno
47+
libc.src.__support.wchar.wcrtomb
48+
libc.src.__support.wchar.mbstate
49+
)
50+
3751
add_entrypoint_object(
3852
mbrtowc
3953
SRCS

libc/src/wchar/wcrtomb.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===-- Implementation of wcrtomb -----------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/wchar/wcrtomb.h"
10+
11+
#include "hdr/types/mbstate_t.h"
12+
#include "hdr/types/wchar_t.h"
13+
#include "src/__support/common.h"
14+
#include "src/__support/libc_errno.h"
15+
#include "src/__support/macros/config.h"
16+
#include "src/__support/wchar/mbstate.h"
17+
#include "src/__support/wchar/wcrtomb.h"
18+
19+
namespace LIBC_NAMESPACE_DECL {
20+
21+
LLVM_LIBC_FUNCTION(size_t, wcrtomb,
22+
(char *__restrict s, wchar_t wc, mbstate_t *__restrict ps)) {
23+
static internal::mbstate internal_mbstate;
24+
25+
// when s is nullptr, this is equivalent to wcrtomb(buf, L'\0', ps)
26+
char buf[sizeof(wchar_t) / sizeof(char)];
27+
if (s == nullptr) {
28+
s = buf;
29+
wc = L'\0';
30+
}
31+
32+
auto result = internal::wcrtomb(
33+
s, wc,
34+
ps == nullptr ? &internal_mbstate
35+
: reinterpret_cast<internal::mbstate *>(ps));
36+
37+
if (!result.has_value()) {
38+
libc_errno = EILSEQ;
39+
return -1;
40+
}
41+
42+
return result.value();
43+
}
44+
45+
} // namespace LIBC_NAMESPACE_DECL

libc/src/wchar/wcrtomb.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation header for wcrtomb -----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_WCHAR_WCRTOMB_H
10+
#define LLVM_LIBC_SRC_WCHAR_WCRTOMB_H
11+
12+
#include "hdr/types/mbstate_t.h"
13+
#include "hdr/types/size_t.h"
14+
#include "hdr/types/wchar_t.h"
15+
#include "src/__support/macros/config.h"
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
19+
size_t wcrtomb(char *__restrict s, wchar_t wc, mbstate_t *__restrict ps);
20+
21+
} // namespace LIBC_NAMESPACE_DECL
22+
23+
#endif // LLVM_LIBC_SRC_WCHAR_WCRTOMB_H

libc/test/src/wchar/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ add_libc_test(
4747
libc.src.wchar.wctob
4848
)
4949

50+
add_libc_test(
51+
wcrtomb_test
52+
SUITE
53+
libc_wchar_unittests
54+
SRCS
55+
wcrtomb_test.cpp
56+
DEPENDS
57+
libc.src.wchar.wcrtomb
58+
libc.src.string.memset
59+
libc.hdr.types.wchar_t
60+
libc.hdr.types.mbstate_t
61+
libc.src.__support.libc_errno
62+
)
63+
5064
add_libc_test(
5165
wmemset_test
5266
SUITE

libc/test/src/wchar/wcrtomb_test.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===-- Unittests for wcrtomb --------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/types/mbstate_t.h"
10+
#include "hdr/types/wchar_t.h"
11+
#include "src/__support/libc_errno.h"
12+
#include "src/string/memset.h"
13+
#include "src/wchar/wcrtomb.h"
14+
#include "test/UnitTest/Test.h"
15+
16+
TEST(LlvmLibcWCRToMBTest, OneByte) {
17+
mbstate_t state;
18+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
19+
wchar_t wc = L'U';
20+
char mb[4];
21+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state);
22+
ASSERT_EQ(cnt, static_cast<size_t>(1));
23+
ASSERT_EQ(mb[0], 'U');
24+
}
25+
26+
TEST(LlvmLibcWCRToMBTest, TwoByte) {
27+
mbstate_t state;
28+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
29+
// testing utf32: 0xff -> utf8: 0xc3 0xbf
30+
wchar_t wc = 0xff;
31+
char mb[4];
32+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state);
33+
ASSERT_EQ(cnt, static_cast<size_t>(2));
34+
ASSERT_EQ(mb[0], static_cast<char>(0xc3));
35+
ASSERT_EQ(mb[1], static_cast<char>(0xbf));
36+
}
37+
38+
TEST(LlvmLibcWCRToMBTest, ThreeByte) {
39+
mbstate_t state;
40+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
41+
// testing utf32: 0xac15 -> utf8: 0xea 0xb0 0x95
42+
wchar_t wc = 0xac15;
43+
char mb[4];
44+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state);
45+
ASSERT_EQ(cnt, static_cast<size_t>(3));
46+
ASSERT_EQ(mb[0], static_cast<char>(0xea));
47+
ASSERT_EQ(mb[1], static_cast<char>(0xb0));
48+
ASSERT_EQ(mb[2], static_cast<char>(0x95));
49+
}
50+
51+
TEST(LlvmLibcWCRToMBTest, FourByte) {
52+
mbstate_t state;
53+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
54+
// testing utf32: 0x1f921 -> utf8: 0xf0 0x9f 0xa4 0xa1
55+
wchar_t wc = 0x1f921;
56+
char mb[4];
57+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state);
58+
ASSERT_EQ(cnt, static_cast<size_t>(4));
59+
ASSERT_EQ(mb[0], static_cast<char>(0xf0));
60+
ASSERT_EQ(mb[1], static_cast<char>(0x9f));
61+
ASSERT_EQ(mb[2], static_cast<char>(0xa4));
62+
ASSERT_EQ(mb[3], static_cast<char>(0xa1));
63+
}
64+
65+
TEST(LlvmLibcWCRToMBTest, NullString) {
66+
mbstate_t state;
67+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
68+
wchar_t wc = L'A';
69+
char mb[4];
70+
71+
// should be equivalent to the call wcrtomb(buf, L'\0', state)
72+
size_t cnt1 = LIBC_NAMESPACE::wcrtomb(nullptr, wc, &state);
73+
size_t cnt2 = LIBC_NAMESPACE::wcrtomb(mb, L'\0', &state);
74+
75+
ASSERT_EQ(cnt1, cnt2);
76+
}
77+
78+
TEST(LlvmLibcWCRToMBTest, NullState) {
79+
wchar_t wc = L'A';
80+
char mb[4];
81+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, nullptr);
82+
ASSERT_EQ(cnt, static_cast<size_t>(1));
83+
}
84+
85+
TEST(LlvmLibcWCRToMBTest, InvalidWchar) {
86+
mbstate_t state;
87+
LIBC_NAMESPACE::memset(&state, 0, sizeof(mbstate_t));
88+
wchar_t wc = 0x12ffff;
89+
char mb[4];
90+
size_t cnt = LIBC_NAMESPACE::wcrtomb(mb, wc, &state);
91+
ASSERT_EQ(cnt, static_cast<size_t>(-1));
92+
ASSERT_EQ(static_cast<int>(libc_errno), EILSEQ);
93+
}

0 commit comments

Comments
 (0)