1//===----------------------------------------------------------------------===//
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 <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
15
16// Like sprintf, but when return value >= 0 it returns
17// a pointer to a malloc'd string in *sptr.
18// If return >= 0, use free to delete *sptr.
19int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) {
20 *sptr = NULL;
21 // Query the count required.
22 va_list ap_copy;
23 va_copy(ap_copy, ap);
24 _LIBCPP_DIAGNOSTIC_PUSH
25 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
26 int count = vsnprintf(NULL, maxlen: 0, format: format, arg: ap_copy);
27 _LIBCPP_DIAGNOSTIC_POP
28 va_end(ap_copy);
29 if (count < 0)
30 return count;
31 size_t buffer_size = static_cast<size_t>(count) + 1;
32 char* p = static_cast<char*>(malloc(size: buffer_size));
33 if (!p)
34 return -1;
35 // If we haven't used exactly what was required, something is wrong.
36 // Maybe bug in vsnprintf. Report the error and return.
37 _LIBCPP_DIAGNOSTIC_PUSH
38 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
39 if (vsnprintf(p, buffer_size, format, ap) != count) {
40 _LIBCPP_DIAGNOSTIC_POP
41 free(p);
42 return -1;
43 }
44 // All good. This is returning memory to the caller not freeing it.
45 *sptr = p;
46 return count;
47}
48
49// Returns >= 0: the number of wide characters found in the
50// multi byte sequence src (of src_size_bytes), that fit in the buffer dst
51// (of max_dest_chars elements size). The count returned excludes the
52// null terminator. When dst is NULL, no characters are copied
53// and no "out" parameters are updated.
54// Returns (size_t) -1: an incomplete sequence encountered.
55// Leaves *src pointing the next character to convert or NULL
56// if a null character was converted from *src.
57size_t mbsnrtowcs(wchar_t* __restrict dst,
58 const char** __restrict src,
59 size_t src_size_bytes,
60 size_t max_dest_chars,
61 mbstate_t* __restrict ps) {
62 const size_t terminated_sequence = static_cast<size_t>(0);
63 // const size_t invalid_sequence = static_cast<size_t>(-1);
64 const size_t incomplete_sequence = static_cast< size_t>(-2);
65
66 size_t dest_converted = 0;
67 size_t source_converted = 0;
68 size_t source_remaining = src_size_bytes;
69 size_t result = 0;
70 bool have_result = false;
71
72 // If dst is null then max_dest_chars should be ignored according to the
73 // standard. Setting max_dest_chars to a large value has this effect.
74 if (!dst)
75 max_dest_chars = static_cast<size_t>(-1);
76
77 while (source_remaining) {
78 if (dst && dest_converted >= max_dest_chars)
79 break;
80 // Converts one multi byte character.
81 // if result > 0, it's the size in bytes of that character.
82 // othewise if result is zero it indicates the null character has been found.
83 // otherwise it's an error and errno may be set.
84 size_t char_size = mbrtowc(pwc: dst ? dst + dest_converted : NULL, s: *src + source_converted, n: source_remaining, p: ps);
85 // Don't do anything to change errno from here on.
86 if (char_size > 0) {
87 source_remaining -= char_size;
88 source_converted += char_size;
89 ++dest_converted;
90 continue;
91 }
92 result = char_size;
93 have_result = true;
94 break;
95 }
96 if (dst) {
97 if (have_result && result == terminated_sequence)
98 *src = NULL;
99 else
100 *src += source_converted;
101 }
102 if (have_result && result != terminated_sequence && result != incomplete_sequence)
103 return static_cast<size_t>(-1);
104
105 return dest_converted;
106}
107
108// Converts max_source_chars from the wide character buffer pointer to by *src,
109// into the multi byte character sequence buffer stored at dst which must be
110// dst_size_bytes bytes in size.
111// Returns >= 0: the number of bytes in the sequence
112// converted from *src, excluding the null terminator.
113// Returns size_t(-1) if an error occurs, also sets errno.
114// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
115// and no "out" parameters are updated.
116size_t wcsnrtombs(char* __restrict dst,
117 const wchar_t** __restrict src,
118 size_t max_source_chars,
119 size_t dst_size_bytes,
120 mbstate_t* __restrict ps) {
121 // const size_t invalid_sequence = static_cast<size_t>(-1);
122
123 size_t source_converted = 0;
124 size_t dest_converted = 0;
125 size_t dest_remaining = dst_size_bytes;
126 size_t char_size = 0;
127 const errno_t no_error = (errno_t)0;
128 errno_t result = (errno_t)0;
129 bool have_result = false;
130 bool terminator_found = false;
131
132 // If dst is null then dst_size_bytes should be ignored according to the
133 // standard. Setting dest_remaining to a large value has this effect.
134 if (!dst)
135 dest_remaining = static_cast<size_t>(-1);
136
137 while (source_converted != max_source_chars) {
138 if (!dest_remaining)
139 break;
140 wchar_t c = (*src)[source_converted];
141 if (dst)
142 result = wcrtomb_s(&char_size, dst + dest_converted, dest_remaining, c, ps);
143 else
144 result = wcrtomb_s(&char_size, NULL, 0, c, ps);
145 // If result is zero there is no error and char_size contains the
146 // size of the multi-byte-sequence converted.
147 // Otherwise result indicates an errno type error.
148 if (result == no_error) {
149 if (c == L'\0') {
150 terminator_found = true;
151 break;
152 }
153 ++source_converted;
154 if (dst)
155 dest_remaining -= char_size;
156 dest_converted += char_size;
157 continue;
158 }
159 have_result = true;
160 break;
161 }
162 if (dst) {
163 if (terminator_found)
164 *src = NULL;
165 else
166 *src = *src + source_converted;
167 }
168 if (have_result && result != no_error) {
169 errno = result;
170 return static_cast<size_t>(-1);
171 }
172
173 return dest_converted;
174}
175

source code of libcxx/src/support/win32/support.cpp