xref: /freebsd/contrib/llvm-project/libc/src/__support/wchar/mbrtowc.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===-- Implementation for mbrtowc function ---------------------*- 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 #include "src/__support/wchar/mbrtowc.h"
10 #include "hdr/errno_macros.h"
11 #include "hdr/types/mbstate_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/error_or.h"
16 #include "src/__support/macros/config.h"
17 #include "src/__support/wchar/character_converter.h"
18 #include "src/__support/wchar/mbstate.h"
19 
20 namespace LIBC_NAMESPACE_DECL {
21 namespace internal {
22 
23 ErrorOr<size_t> mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
24                         size_t n, mbstate *__restrict ps) {
25   CharacterConverter char_conv(ps);
26   if (!char_conv.isValidState())
27     return Error(EINVAL);
28   if (s == nullptr)
29     return 0;
30   size_t i = 0;
31   // Reading in bytes until we have a complete wc or error
32   for (; i < n && !char_conv.isFull(); ++i) {
33     int err = char_conv.push(static_cast<char8_t>(s[i]));
34     // Encoding error
35     if (err == EILSEQ)
36       return Error(err);
37   }
38   auto wc = char_conv.pop_utf32();
39   if (wc.has_value()) {
40     *pwc = wc.value();
41     // null terminator -> return 0
42     if (wc.value() == L'\0')
43       return 0;
44     return i;
45   }
46   // Incomplete but potentially valid
47   return -2;
48 }
49 
50 } // namespace internal
51 
52 } // namespace LIBC_NAMESPACE_DECL
53