Skip to content

Commit 1eab8de

Browse files
author
Sriya Pratipati
committed
[libc] Implemented mblen functions
Implemented mblen and mbrlen as well as tests
1 parent ed00cc0 commit 1eab8de

File tree

2 files changed

+78
-44
lines changed

2 files changed

+78
-44
lines changed

libc/test/src/wchar/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ add_libc_test(
7777
)
7878

7979
add_libc_test(
80-
mbrtowc_test
80+
mbrlen_test
8181
SUITE
8282
libc_wchar_unittests
8383
SRCS
84-
mbrtowc_test.cpp
84+
mbrlen_test.cpp
8585
DEPENDS
8686
libc.src.__support.libc_errno
8787
libc.src.__support.wchar.mbstate
8888
libc.src.string.memset
89-
libc.src.wchar.mbrtowc
89+
libc.src.wchar.mbrlen
9090
libc.hdr.types.mbstate_t
9191
libc.test.UnitTest.ErrnoCheckingTest
9292
)
Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===-- Unittests for mblen -----------------------------------------------===//
1+
//===-- Unittests for mbrlen ----------------------------------------------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,98 +8,132 @@
88

99
#include "hdr/types/wchar_t.h"
1010
#include "src/__support/libc_errno.h"
11-
#include "src/wchar/mblen.h"
11+
#include "src/__support/wchar/mbstate.h"
12+
#include "src/string/memset.h"
13+
#include "src/wchar/mbrlen.h"
1214
#include "test/UnitTest/ErrnoCheckingTest.h"
1315
#include "test/UnitTest/Test.h"
1416

15-
using LlvmLibcMBLenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
17+
using LlvmLibcMBRLenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
1618

17-
TEST_F(LlvmLibcMBLenTest, OneByte) {
19+
TEST_F(LlvmLibcMBRLenTest, OneByte) {
1820
const char *ch = "A";
19-
int n = LIBC_NAMESPACE::mblen(ch, 1);
21+
mbstate_t mb;
22+
LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
23+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 1, &mb);
2024
ASSERT_ERRNO_SUCCESS();
21-
ASSERT_EQ(n, 1);
25+
ASSERT_EQ(n, static_cast<size_t>(1));
2226

2327
// Should fail since we have not read enough
24-
n = LIBC_NAMESPACE::mblen(ch, 0);
28+
n = LIBC_NAMESPACE::mbrlen(ch, 0, &mb);
2529
ASSERT_ERRNO_SUCCESS();
26-
ASSERT_EQ(n, -1);
30+
ASSERT_EQ(n, static_cast<size_t>(-2));
2731
}
2832

29-
TEST_F(LlvmLibcMBLenTest, TwoByte) {
33+
TEST_F(LlvmLibcMBRLenTest, TwoByte) {
3034
const char ch[2] = {static_cast<char>(0xC2),
3135
static_cast<char>(0x8E)}; // Ž car symbol
32-
int n = LIBC_NAMESPACE::mblen(ch, 4);
36+
mbstate_t mb;
37+
LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
38+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, nullptr);
3339
ASSERT_ERRNO_SUCCESS();
34-
ASSERT_EQ(n, 2);
40+
ASSERT_EQ(static_cast<int>(n), 2);
3541

3642
// Should fail since we have not read enough
37-
n = LIBC_NAMESPACE::mblen(ch, 1);
38-
ASSERT_EQ(n, -1);
43+
n = LIBC_NAMESPACE::mbrlen(ch, 1, &mb);
44+
ASSERT_EQ(static_cast<int>(n), -2);
45+
ASSERT_ERRNO_SUCCESS();
46+
// Should pass after trying to read next byte
47+
n = LIBC_NAMESPACE::mbrlen(ch + 1, 1, &mb);
48+
ASSERT_EQ(static_cast<int>(n), 1);
3949
ASSERT_ERRNO_SUCCESS();
40-
// Should fail after trying to read next byte too
41-
n = LIBC_NAMESPACE::mblen(ch + 1, 1);
42-
ASSERT_EQ(n, -1);
43-
// This one should be an invalid starting byte so should set errno
44-
ASSERT_ERRNO_EQ(EILSEQ);
4550
}
4651

47-
TEST_F(LlvmLibcMBLenTest, ThreeByte) {
52+
TEST_F(LlvmLibcMBRLenTest, ThreeByte) {
4853
const char ch[3] = {static_cast<char>(0xE2), static_cast<char>(0x88),
4954
static_cast<char>(0x91)}; // ∑ sigma symbol
50-
int n = LIBC_NAMESPACE::mblen(ch, 3);
51-
ASSERT_EQ(n, 3);
55+
mbstate_t mb;
56+
LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
57+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 3, &mb);
58+
ASSERT_EQ(static_cast<int>(n), 3);
5259
ASSERT_ERRNO_SUCCESS();
5360

5461
// Should fail since we have not read enough
55-
n = LIBC_NAMESPACE::mblen(ch, 2);
56-
ASSERT_EQ(n, -1);
62+
n = LIBC_NAMESPACE::mbrlen(ch, 2, &mb);
63+
ASSERT_EQ(static_cast<int>(n), -2);
5764
ASSERT_ERRNO_SUCCESS();
5865
}
5966

60-
TEST_F(LlvmLibcMBLenTest, FourByte) {
67+
TEST_F(LlvmLibcMBRLenTest, FourByte) {
6168
const char ch[4] = {static_cast<char>(0xF0), static_cast<char>(0x9F),
6269
static_cast<char>(0xA4),
6370
static_cast<char>(0xA1)}; // 🤡 clown emoji
64-
int n = LIBC_NAMESPACE::mblen(ch, 4);
65-
ASSERT_EQ(n, 4);
71+
mbstate_t mb;
72+
LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
73+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, &mb);
74+
ASSERT_EQ(static_cast<int>(n), 4);
75+
ASSERT_ERRNO_SUCCESS();
76+
77+
// Should fail since we have not read enough
78+
n = LIBC_NAMESPACE::mbrlen(ch, 2, &mb);
79+
ASSERT_EQ(static_cast<int>(n), -2);
6680
ASSERT_ERRNO_SUCCESS();
6781

6882
// Should fail since we have not read enough
69-
n = LIBC_NAMESPACE::mblen(ch, 2);
70-
ASSERT_EQ(n, -1);
83+
n = LIBC_NAMESPACE::mbrlen(ch + 2, 1, &mb);
84+
ASSERT_EQ(static_cast<int>(n), -2);
85+
ASSERT_ERRNO_SUCCESS();
86+
87+
// Should pass after reading final byte
88+
n = LIBC_NAMESPACE::mbrlen(ch + 3, 5, &mb);
89+
ASSERT_EQ(static_cast<int>(n), 1);
7190
ASSERT_ERRNO_SUCCESS();
7291
}
7392

74-
TEST_F(LlvmLibcMBLenTest, InvalidByte) {
93+
TEST_F(LlvmLibcMBRLenTest, InvalidByte) {
7594
const char ch[1] = {static_cast<char>(0x80)};
76-
int n = LIBC_NAMESPACE::mblen(ch, 1);
77-
ASSERT_EQ(n, -1);
95+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 1, nullptr);
96+
ASSERT_EQ(static_cast<int>(n), -1);
7897
ASSERT_ERRNO_EQ(EILSEQ);
7998
}
8099

81-
TEST_F(LlvmLibcMBLenTest, InvalidMultiByte) {
100+
TEST_F(LlvmLibcMBRLenTest, InvalidMultiByte) {
82101
const char ch[4] = {static_cast<char>(0x80), static_cast<char>(0x00),
83102
static_cast<char>(0x80),
84103
static_cast<char>(0x00)}; // invalid sequence of bytes
104+
mbstate_t mb;
105+
LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));
85106
// Trying to push all 4 should error
86-
int n = LIBC_NAMESPACE::mblen(ch, 4);
87-
ASSERT_EQ(n, -1);
107+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, &mb);
108+
ASSERT_EQ(static_cast<int>(n), -1);
88109
ASSERT_ERRNO_EQ(EILSEQ);
89110

90111
// Trying to push the second and third should correspond to null wc
91-
n = LIBC_NAMESPACE::mblen(ch + 1, 2);
92-
ASSERT_EQ(n, 0);
112+
n = LIBC_NAMESPACE::mbrlen(ch + 1, 2, &mb);
113+
ASSERT_EQ(static_cast<int>(n), 0);
93114
ASSERT_ERRNO_SUCCESS();
94115
}
95116

96-
TEST_F(LlvmLibcMBLenTest, NullString) {
117+
TEST_F(LlvmLibcMBRLenTest, NullString) {
97118
// reading on nullptr should return 0
98-
int n = LIBC_NAMESPACE::mblen(nullptr, 2);
99-
ASSERT_EQ(n, 0);
119+
size_t n = LIBC_NAMESPACE::mbrlen(nullptr, 2, nullptr);
120+
ASSERT_EQ(static_cast<int>(n), 0);
100121
ASSERT_ERRNO_SUCCESS();
101122
// reading a null terminator should return 0
102123
const char *ch = "\0";
103-
n = LIBC_NAMESPACE::mblen(ch, 1);
104-
ASSERT_EQ(n, 0);
124+
n = LIBC_NAMESPACE::mbrlen(ch, 1, nullptr);
125+
ASSERT_EQ(static_cast<int>(n), 0);
126+
}
127+
128+
TEST_F(LlvmLibcMBRLenTest, InvalidMBState) {
129+
const char ch[4] = {static_cast<char>(0xC2), static_cast<char>(0x8E),
130+
static_cast<char>(0xC7), static_cast<char>(0x8C)};
131+
mbstate_t *mb;
132+
LIBC_NAMESPACE::internal::mbstate inv;
133+
inv.total_bytes = 6;
134+
mb = reinterpret_cast<mbstate_t *>(&inv);
135+
// invalid mbstate should error
136+
size_t n = LIBC_NAMESPACE::mbrlen(ch, 2, mb);
137+
ASSERT_EQ(static_cast<int>(n), -1);
138+
ASSERT_ERRNO_EQ(EINVAL);
105139
}

0 commit comments

Comments
 (0)