Skip to content

[libc] Implemented wcstrombs internal and public function #145794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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 @@ -1252,6 +1252,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.wchar.mbtowc
libc.src.wchar.wcrtomb
libc.src.wchar.wctomb
libc.src.wchar.wcsrtombs
)
endif()

Expand Down
9 changes: 9 additions & 0 deletions libc/include/wchar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ functions:
- type: char *__restrict
- type: wchar_t
- type: mbstate_t *__restrict
- name: wcsrtombs
standards:
- stdc
return_type: size_t
arguments:
- type: char *__restrict
- type: wchar_t **__restrict
- type: size_t
- type: mbstate_t *__restrict
- name: wctomb
standards:
- stdc
Expand Down
18 changes: 18 additions & 0 deletions libc/src/__support/wchar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ add_object_library(
.mbstate
)

add_object_library(
wcsrtombs
HDRS
wcsrtombs.h
SRCS
wcsrtombs.cpp
DEPENDS
libc.hdr.types.char32_t
libc.hdr.types.size_t
libc.hdr.types.wchar_t
libc.src.__support.error_or
libc.src.__support.common
libc.src.__support.libc_assert
.character_converter
.mbstate
.wcrtomb
)

add_object_library(
mbrtowc
HDRS
Expand Down
22 changes: 15 additions & 7 deletions libc/src/__support/wchar/wcrtomb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,39 @@
namespace LIBC_NAMESPACE_DECL {
namespace internal {

ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc,
mbstate *__restrict ps) {
ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps,
size_t max_written) {
Comment on lines +24 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're calling this function wcrtomb it should match that interface. If you want to have a different interface, then that's fine but it should have a different name to avoid confusion.

static_assert(sizeof(wchar_t) == 4);

CharacterConverter cr(ps);

if (!cr.isValidState())
return Error(EINVAL);

char buf[sizeof(wchar_t) / sizeof(char)];
if (s == nullptr)
return Error(EILSEQ);
s = buf;

int status = cr.push(static_cast<char32_t>(wc));
if (status != 0)
return Error(EILSEQ);
// if cr isnt empty, it should be represented in mbstate already
if (cr.isEmpty()) {
int status = cr.push(static_cast<char32_t>(wc));
if (status != 0)
return Error(EILSEQ);
}

size_t count = 0;
while (!cr.isEmpty()) {
while (!cr.isEmpty() && count < max_written) {
auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded
LIBC_ASSERT(utf8.has_value());

*s = utf8.value();
s++;
count++;
}

if (!cr.isEmpty()) // didn't complete the conversion
return -1;

return count;
}

Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/wchar/wcrtomb.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace internal {

ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps);
ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps,
size_t max_written);

} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
Expand Down
55 changes: 55 additions & 0 deletions libc/src/__support/wchar/wcsrtombs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//===-- Implementation of wcsrtombs ---------------------------------------===//
//
// 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/__support/wchar/wcsrtombs.h"
#include "hdr/types/char32_t.h"
#include "hdr/types/size_t.h"
#include "hdr/types/wchar_t.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_assert.h"
#include "src/__support/wchar/character_converter.h"
#include "src/__support/wchar/mbstate.h"
#include "src/__support/wchar/wcrtomb.h"

namespace LIBC_NAMESPACE_DECL {
namespace internal {

ErrorOr<size_t> wcsrtombs(char *__restrict dst, const wchar_t **__restrict src,
size_t len, mbstate *__restrict ps) {
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is wcsnrtombs, not wcsrtombs

// ignore len parameter when theres no destination string
if (dst == nullptr)
len = SIZE_MAX;

size_t bytes_written = 0;
while (bytes_written < len) {
auto result =
internal::wcrtomb(dst == nullptr ? nullptr : dst + bytes_written, **src,
ps, len - bytes_written);
if (!result.has_value())
return result; // forward the error

// couldn't complete conversion
if (result.value() == static_cast<size_t>(-1))
return len;

// terminate the loop after converting the null wide character
if (**src == L'\0') {
*src = nullptr;
return bytes_written;
}

bytes_written += result.value();
(*src)++;
}

return bytes_written;
}

} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
27 changes: 27 additions & 0 deletions libc/src/__support/wchar/wcsrtombs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===-- Implementation header for wcsrtombs -------------------------------===//
//
// 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__SUPPORT_WCHAR_WCSRTOMBS_H
#define LLVM_LIBC_SRC__SUPPORT_WCHAR_WCSRTOMBS_H

#include "hdr/types/size_t.h"
#include "hdr/types/wchar_t.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include "src/__support/wchar/mbstate.h"

namespace LIBC_NAMESPACE_DECL {
namespace internal {

ErrorOr<size_t> wcsrtombs(char *__restrict dst, const wchar_t **__restrict src,
size_t len, mbstate *__restrict ps);

} // namespace internal
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC__SUPPORT_WCHAR_WCSRTOMBS_H
14 changes: 14 additions & 0 deletions libc/src/wchar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ add_entrypoint_object(
libc.src.__support.wchar.mbstate
)

add_entrypoint_object(
wcsrtombs
SRCS
wcsrtombs.cpp
HDRS
wcsrtombs.h
DEPENDS
libc.hdr.types.wchar_t
libc.hdr.types.mbstate_t
libc.src.__support.libc_errno
libc.src.__support.wchar.wcsrtombs
libc.src.__support.wchar.mbstate
)

add_entrypoint_object(
wctomb
SRCS
Expand Down
8 changes: 3 additions & 5 deletions libc/src/wchar/wcrtomb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,14 @@ LLVM_LIBC_FUNCTION(size_t, wcrtomb,
static internal::mbstate internal_mbstate;

// when s is nullptr, this is equivalent to wcrtomb(buf, L'\0', ps)
char buf[sizeof(wchar_t) / sizeof(char)];
if (s == nullptr) {
s = buf;
if (s == nullptr)
wc = L'\0';
}

auto result = internal::wcrtomb(
s, wc,
ps == nullptr ? &internal_mbstate
: reinterpret_cast<internal::mbstate *>(ps));
: reinterpret_cast<internal::mbstate *>(ps),
sizeof(wchar_t));

if (!result.has_value()) {
libc_errno = result.error();
Expand Down
42 changes: 42 additions & 0 deletions libc/src/wchar/wcsrtombs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===-- Implementation of wcsrtombs ---------------------------------------===//
//
// 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/wcsrtombs.h"

#include "hdr/types/mbstate_t.h"
#include "hdr/types/wchar_t.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/null_check.h"
#include "src/__support/wchar/mbstate.h"
#include "src/__support/wchar/wcsrtombs.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(size_t, wcsrtombs,
(char *__restrict dst, const wchar_t **__restrict src,
size_t len, mbstate_t *__restrict ps)) {
static internal::mbstate internal_mbstate;

LIBC_CRASH_ON_NULLPTR(src);

auto result = internal::wcsrtombs(
dst, src, len,
ps == nullptr ? &internal_mbstate
: reinterpret_cast<internal::mbstate *>(ps));

if (!result.has_value()) {
libc_errno = result.error();
return -1;
}

return result.value();
}

} // namespace LIBC_NAMESPACE_DECL
24 changes: 24 additions & 0 deletions libc/src/wchar/wcsrtombs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===-- Implementation header for wcsrtombs ---------------------*- C++ -*-===//
//
// 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_WCSRTOMBS_H
#define LLVM_LIBC_SRC_WCHAR_WCSRTOMBS_H

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

namespace LIBC_NAMESPACE_DECL {

size_t wcsrtombs(char *__restrict dst, const wchar_t **__restrict src,
size_t len, mbstate_t *__restrict ps);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_WCHAR_WCSRTOMBS_H
2 changes: 1 addition & 1 deletion libc/src/wchar/wctomb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LLVM_LIBC_FUNCTION(int, wctomb, (char *s, wchar_t wc)) {
if (s == nullptr)
return 0;

auto result = internal::wcrtomb(s, wc, &internal_mbstate);
auto result = internal::wcrtomb(s, wc, &internal_mbstate, sizeof(wchar_t));

if (!result.has_value()) { // invalid wide character
libc_errno = EILSEQ;
Expand Down
15 changes: 15 additions & 0 deletions libc/test/src/wchar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ add_libc_test(
libc.test.UnitTest.ErrnoCheckingTest
)

add_libc_test(
wcsrtombs_test
SUITE
libc_wchar_unittests
SRCS
wcsrtombs_test.cpp
DEPENDS
libc.src.wchar.wcsrtombs
libc.src.string.memset
libc.hdr.types.wchar_t
libc.hdr.types.mbstate_t
libc.src.__support.wchar.mbstate
libc.src.__support.libc_errno
)

add_libc_test(
wctomb_test
SUITE
Expand Down
Loading
Loading