Skip to content

Commit 7445bf7

Browse files
committed
created internal function
1 parent 586497d commit 7445bf7

File tree

6 files changed

+248
-1
lines changed

6 files changed

+248
-1
lines changed

libc/src/__support/wchar/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,22 @@ add_object_library(
6868
.character_converter
6969
.mbstate
7070
)
71+
72+
add_object_library(
73+
wcsnrtombs
74+
HDRS
75+
wcsnrtombs.h
76+
SRCS
77+
wcsnrtombs.cpp
78+
DEPENDS
79+
libc.hdr.errno_macros
80+
libc.hdr.types.char8_t
81+
libc.hdr.types.char32_t
82+
libc.hdr.types.size_t
83+
libc.hdr.types.wchar_t
84+
libc.src.__support.error_or
85+
libc.src.__support.common
86+
.string_converter
87+
.character_converter
88+
.mbstate
89+
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===-- Implementation of wcsnrtombs --------------------------------------===//
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/wcsnrtombs.h"
10+
11+
#include "hdr/types/char32_t.h"
12+
#include "hdr/types/size_t.h"
13+
#include "hdr/types/wchar_t.h"
14+
#include "src/__support/common.h"
15+
#include "src/__support/libc_errno.h"
16+
#include "src/__support/macros/config.h"
17+
#include "src/__support/wchar/mbstate.h"
18+
#include "src/__support/wchar/string_converter.h"
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
namespace internal {
22+
23+
ErrorOr<size_t> wcsnrtombs(char *__restrict s, const wchar_t **__restrict pwcs,
24+
size_t nwc, size_t len, mbstate *ps) {
25+
CharacterConverter cr(ps);
26+
if (!cr.isValidState())
27+
return Error(EINVAL);
28+
29+
if (s == nullptr)
30+
len = SIZE_MAX;
31+
32+
StringConverter<char32_t> str_conv(reinterpret_cast<const char32_t *>(*pwcs),
33+
ps, len, nwc);
34+
size_t dst_idx = 0;
35+
ErrorOr<char8_t> converted = str_conv.popUTF8();
36+
while (converted.has_value()) {
37+
if (s != nullptr)
38+
s[dst_idx] = converted.value();
39+
40+
if (converted.value() == '\0') {
41+
*pwcs = nullptr;
42+
return dst_idx;
43+
}
44+
45+
dst_idx++;
46+
converted = str_conv.popUTF8();
47+
}
48+
49+
*pwcs += str_conv.getSourceIndex();
50+
if (converted.error() == -1) // if we hit conversion limit
51+
return dst_idx;
52+
53+
return Error(converted.error());
54+
}
55+
} // namespace internal
56+
} // namespace LIBC_NAMESPACE_DECL
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- Implementation header for wcsnrtombs ------------------------------===//
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> wcsnrtombs(char *__restrict s, const wchar_t **__restrict pwcs,
22+
size_t nwc, size_t len, mbstate *ps);
23+
24+
} // namespace internal
25+
} // namespace LIBC_NAMESPACE_DECL
26+
27+
#endif // LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H

libc/src/wchar/wcsrtombs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ LLVM_LIBC_FUNCTION(size_t, wcsrtombs,
3939
converted = str_conv.popUTF8();
4040
}
4141

42-
pwcs += str_conv.getSourceIndex();
42+
*pwcs += str_conv.getSourceIndex();
4343
if (converted.error() == -1) // if we hit conversion limit
4444
return dst_idx;
4545

libc/test/src/__support/wchar/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,20 @@ add_libc_test(
3434
libc.hdr.errno_macros
3535
libc.hdr.types.char32_t
3636
)
37+
38+
add_libc_test(
39+
wcsnrtombs_test
40+
SUITE
41+
libc-support-tests
42+
SRCS
43+
wcsnrtombs_test.cpp
44+
DEPENDS
45+
libc.src.__support.wchar.string_converter
46+
libc.src.__support.wchar.character_converter
47+
libc.src.__support.wchar.mbstate
48+
libc.src.__support.error_or
49+
libc.src.__support.wchar.wcsnrtombs
50+
libc.hdr.errno_macros
51+
libc.hdr.types.char32_t
52+
libc.hdr.types.char8_t
53+
)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//===-- Unittests for wcsnrtombs ------------------------------------------===//
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/errno_macros.h"
10+
#include "hdr/types/size_t.h"
11+
#include "hdr/types/wchar_t.h"
12+
#include "src/__support/error_or.h"
13+
#include "src/__support/wchar/mbstate.h"
14+
#include "src/__support/wchar/wcsnrtombs.h"
15+
#include "test/UnitTest/Test.h"
16+
17+
TEST(LlvmLibcWcsnrtombs, AllMultibyteLengths) {
18+
LIBC_NAMESPACE::internal::mbstate state;
19+
20+
/// clown emoji, sigma symbol, y with diaeresis, letter A
21+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
22+
static_cast<wchar_t>(0x2211),
23+
static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),
24+
static_cast<wchar_t>(0x0)};
25+
const wchar_t *cur = src;
26+
char mbs[11];
27+
28+
auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 11, &state);
29+
ASSERT_TRUE(res.has_value());
30+
ASSERT_EQ(res.value(), static_cast<size_t>(10));
31+
ASSERT_EQ(cur, nullptr);
32+
ASSERT_EQ(mbs[0], '\xF0'); // clown begin
33+
ASSERT_EQ(mbs[1], '\x9F');
34+
ASSERT_EQ(mbs[2], '\xA4');
35+
ASSERT_EQ(mbs[3], '\xA1');
36+
ASSERT_EQ(mbs[4], '\xE2'); // sigma begin
37+
ASSERT_EQ(mbs[5], '\x88');
38+
ASSERT_EQ(mbs[6], '\x91');
39+
ASSERT_EQ(mbs[7], '\xC3'); // y diaeresis begin
40+
ASSERT_EQ(mbs[8], '\xBF');
41+
ASSERT_EQ(mbs[9], '\x41'); // A begin
42+
ASSERT_EQ(mbs[10], '\0'); // null terminator
43+
}
44+
45+
TEST(LlvmLibcWcsnrtombs, DestLimit) {
46+
LIBC_NAMESPACE::internal::mbstate state1;
47+
48+
/// clown emoji, sigma symbol, y with diaeresis, letter A
49+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
50+
static_cast<wchar_t>(0x2211),
51+
static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),
52+
static_cast<wchar_t>(0x0)};
53+
const wchar_t *cur = src;
54+
55+
char mbs[11];
56+
for (int i = 0; i < 11; ++i)
57+
mbs[i] = '\x01'; // dummy initial values
58+
59+
auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 4, &state1);
60+
ASSERT_TRUE(res.has_value());
61+
ASSERT_EQ(res.value(), static_cast<size_t>(4));
62+
ASSERT_EQ(cur, src + 1);
63+
ASSERT_EQ(mbs[0], '\xF0');
64+
ASSERT_EQ(mbs[1], '\x9F');
65+
ASSERT_EQ(mbs[2], '\xA4');
66+
ASSERT_EQ(mbs[3], '\xA1');
67+
ASSERT_EQ(mbs[4], '\x01'); // didn't write more than 4 bytes
68+
69+
for (int i = 0; i < 11; ++i)
70+
mbs[i] = '\x01'; // dummy initial values
71+
LIBC_NAMESPACE::internal::mbstate state2;
72+
73+
// not enough bytes to convert the second character, so only converts one
74+
cur = src;
75+
res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 6, &state2);
76+
ASSERT_TRUE(res.has_value());
77+
ASSERT_EQ(res.value(), static_cast<size_t>(4));
78+
ASSERT_EQ(cur, src + 1);
79+
ASSERT_EQ(mbs[0], '\xF0');
80+
ASSERT_EQ(mbs[1], '\x9F');
81+
ASSERT_EQ(mbs[2], '\xA4');
82+
ASSERT_EQ(mbs[3], '\xA1');
83+
ASSERT_EQ(mbs[4], '\x01');
84+
}
85+
86+
TEST(LlvmLibcWcsnrtombs, NullDest) {
87+
LIBC_NAMESPACE::internal::mbstate state1;
88+
89+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
90+
static_cast<wchar_t>(0x2211),
91+
static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),
92+
static_cast<wchar_t>(0x0)};
93+
const wchar_t *cur = src;
94+
95+
// n parameter ignored when dest is null
96+
auto res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 1, &state1);
97+
ASSERT_TRUE(res.has_value());
98+
ASSERT_EQ(res.value(), static_cast<size_t>(10));
99+
ASSERT_EQ(cur, nullptr);
100+
101+
LIBC_NAMESPACE::internal::mbstate state2;
102+
cur = src;
103+
res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 100, &state2);
104+
ASSERT_TRUE(res.has_value());
105+
ASSERT_EQ(res.value(), static_cast<size_t>(10));
106+
ASSERT_EQ(cur, nullptr);
107+
}
108+
109+
TEST(LlvmLibcWcsnrtombs, ErrorTest) {
110+
LIBC_NAMESPACE::internal::mbstate state1;
111+
112+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
113+
static_cast<wchar_t>(0x2211),
114+
static_cast<wchar_t>(0x12ffff), // invalid widechar
115+
static_cast<wchar_t>(0x0)};
116+
const wchar_t *cur = src;
117+
118+
// n parameter ignored when dest is null
119+
auto res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 7, &state1);
120+
ASSERT_TRUE(res.has_value());
121+
ASSERT_EQ(res.value(), static_cast<size_t>(7));
122+
123+
LIBC_NAMESPACE::internal::mbstate state2;
124+
cur = src;
125+
res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 100, &state2);
126+
ASSERT_FALSE(res.has_value());
127+
ASSERT_EQ(res.error(), EILSEQ);
128+
}

0 commit comments

Comments
 (0)