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