1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include <cstdarg> // va_start, va_end
10 #include <cstddef> // size_t
11 #include <cstdio> // vsprintf, vsnprintf
12 #include <cstdlib> // malloc
13 #include <cstring> // strcpy, wcsncpy
14 #include <cwchar> // mbstate_t
16 // Returns >= 0: the number of wide characters found in the
17 // multi byte sequence src (of src_size_bytes), that fit in the buffer dst
18 // (of max_dest_chars elements size). The count returned excludes the
19 // null terminator. When dst is NULL, no characters are copied
20 // and no "out" parameters are updated.
21 // Returns (size_t) -1: an incomplete sequence encountered.
22 // Leaves *src pointing the next character to convert or NULL
23 // if a null character was converted from *src.
24 size_t mbsnrtowcs(wchar_t* __restrict dst
,
25 const char** __restrict src
,
26 size_t src_size_bytes
,
27 size_t max_dest_chars
,
28 mbstate_t* __restrict ps
) {
29 const size_t terminated_sequence
= static_cast<size_t>(0);
30 // const size_t invalid_sequence = static_cast<size_t>(-1);
31 const size_t incomplete_sequence
= static_cast< size_t>(-2);
33 size_t dest_converted
= 0;
34 size_t source_converted
= 0;
35 size_t source_remaining
= src_size_bytes
;
37 bool have_result
= false;
39 // If dst is null then max_dest_chars should be ignored according to the
40 // standard. Setting max_dest_chars to a large value has this effect.
42 max_dest_chars
= static_cast<size_t>(-1);
44 while (source_remaining
) {
45 if (dst
&& dest_converted
>= max_dest_chars
)
47 // Converts one multi byte character.
48 // if result > 0, it's the size in bytes of that character.
49 // othewise if result is zero it indicates the null character has been found.
50 // otherwise it's an error and errno may be set.
51 size_t char_size
= mbrtowc(dst
? dst
+ dest_converted
: nullptr, *src
+ source_converted
, source_remaining
, ps
);
52 // Don't do anything to change errno from here on.
54 source_remaining
-= char_size
;
55 source_converted
+= char_size
;
64 if (have_result
&& result
== terminated_sequence
)
67 *src
+= source_converted
;
69 if (have_result
&& result
!= terminated_sequence
&& result
!= incomplete_sequence
)
70 return static_cast<size_t>(-1);
72 return dest_converted
;
75 // Converts max_source_chars from the wide character buffer pointer to by *src,
76 // into the multi byte character sequence buffer stored at dst which must be
77 // dst_size_bytes bytes in size.
78 // Returns >= 0: the number of bytes in the sequence
79 // converted from *src, excluding the null terminator.
80 // Returns size_t(-1) if an error occurs, also sets errno.
81 // If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
82 // and no "out" parameters are updated.
83 size_t wcsnrtombs(char* __restrict dst
,
84 const wchar_t** __restrict src
,
85 size_t max_source_chars
,
86 size_t dst_size_bytes
,
87 mbstate_t* __restrict ps
) {
88 // const size_t invalid_sequence = static_cast<size_t>(-1);
90 size_t source_converted
= 0;
91 size_t dest_converted
= 0;
92 size_t dest_remaining
= dst_size_bytes
;
94 const errno_t no_error
= (errno_t
)0;
95 errno_t result
= (errno_t
)0;
96 bool have_result
= false;
97 bool terminator_found
= false;
99 // If dst is null then dst_size_bytes should be ignored according to the
100 // standard. Setting dest_remaining to a large value has this effect.
102 dest_remaining
= static_cast<size_t>(-1);
104 while (source_converted
!= max_source_chars
) {
107 wchar_t c
= (*src
)[source_converted
];
109 result
= wcrtomb_s(&char_size
, dst
+ dest_converted
, dest_remaining
, c
, ps
);
111 result
= wcrtomb_s(&char_size
, nullptr, 0, c
, ps
);
112 // If result is zero there is no error and char_size contains the
113 // size of the multi-byte-sequence converted.
114 // Otherwise result indicates an errno type error.
115 if (result
== no_error
) {
117 terminator_found
= true;
122 dest_remaining
-= char_size
;
123 dest_converted
+= char_size
;
130 if (terminator_found
)
133 *src
= *src
+ source_converted
;
135 if (have_result
&& result
!= no_error
) {
137 return static_cast<size_t>(-1);
140 return dest_converted
;