Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DPWBS-765] feat(libcxx): provide implementations for functions not p…
…rovided by Dinkum
- Loading branch information
Showing
2 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
// -*- C++ -*- | ||
//===----------------------- support/dinkum/support.cpp -------------------===// | ||
// | ||
// 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 <cerrno> // errno | ||
#include <cstdarg> // va_start, va_end | ||
#include <cstddef> // size_t | ||
#include <cstdlib> // malloc | ||
#include <cstdio> // vsprintf, vsnprintf | ||
#include <cstring> // strcpy, wcsncpy | ||
#include <cwchar> // mbstate_t | ||
|
||
// Like sprintf, but when return value >= 0 it returns | ||
// a pointer to a malloc'd string in *sptr. | ||
// If return >= 0, use free to delete *sptr. | ||
int vasprintf( char **sptr, const char *__restrict format, va_list ap ) | ||
{ | ||
*sptr = NULL; | ||
// Query the count required. | ||
int count = vsnprintf( NULL, 0, format, ap ); | ||
if (count < 0) | ||
return count; | ||
size_t buffer_size = static_cast<size_t>(count) + 1; | ||
char* p = static_cast<char*>(malloc(buffer_size)); | ||
if ( ! p ) | ||
return -1; | ||
// If we haven't used exactly what was required, something is wrong. | ||
// Maybe bug in vsnprintf. Report the error and return. | ||
if (vsnprintf(p, buffer_size, format, ap) != count) { | ||
free(p); | ||
return -1; | ||
} | ||
// All good. This is returning memory to the caller not freeing it. | ||
*sptr = p; | ||
return count; | ||
} | ||
|
||
// Returns >= 0: the number of wide characters found in the | ||
// multi byte sequence src (of src_size_bytes), that fit in the buffer dst | ||
// (of max_dest_chars elements size). The count returned excludes the | ||
// null terminator. When dst is NULL, no characters are copied | ||
// and no "out" parameters are updated. | ||
// Returns (size_t) -1: an incomplete sequence encountered. | ||
// Leaves *src pointing the next character to convert or NULL | ||
// if a null character was converted from *src. | ||
size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src, | ||
size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps ) | ||
{ | ||
const size_t terminated_sequence = static_cast<size_t>(0); | ||
const size_t incomplete_sequence = static_cast< size_t>(-2); | ||
|
||
size_t dest_converted = 0; | ||
size_t source_converted = 0; | ||
size_t source_remaining = src_size_bytes; | ||
size_t result = 0; | ||
bool have_result = false; | ||
|
||
// If dst is null then max_dest_chars should be ignored according to the | ||
// standard. Setting max_dest_chars to a large value has this effect. | ||
if (!dst) | ||
max_dest_chars = static_cast<size_t>(-1); | ||
|
||
while ( source_remaining ) { | ||
if ( dst && dest_converted >= max_dest_chars ) | ||
break; | ||
// Converts one multi byte character. | ||
// if result > 0, it's the size in bytes of that character. | ||
// othewise if result is zero it indicates the null character has been found. | ||
// otherwise it's an error and errno may be set. | ||
size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps ); | ||
// Don't do anything to change errno from here on. | ||
if ( char_size > 0 ) { | ||
source_remaining -= char_size; | ||
source_converted += char_size; | ||
++dest_converted; | ||
continue; | ||
} | ||
result = char_size; | ||
have_result = true; | ||
break; | ||
} | ||
if ( dst ) { | ||
if ( have_result && result == terminated_sequence ) | ||
*src = NULL; | ||
else | ||
*src += source_converted; | ||
} | ||
if ( have_result && result != terminated_sequence && result != incomplete_sequence ) | ||
return static_cast<size_t>(-1); | ||
|
||
return dest_converted; | ||
} | ||
|
||
// Converts max_source_chars from the wide character buffer pointer to by *src, | ||
// into the multi byte character sequence buffer stored at dst which must be | ||
// dst_size_bytes bytes in size. | ||
// Returns >= 0: the number of bytes in the sequence | ||
// converted from *src, excluding the null terminator. | ||
// Returns size_t(-1) if an error occurs, also sets errno. | ||
// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst | ||
// and no "out" parameters are updated. | ||
size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src, | ||
size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps ) | ||
{ | ||
size_t source_converted = 0; | ||
size_t dest_converted = 0; | ||
size_t dest_remaining = dst_size_bytes; | ||
size_t char_size = 0; | ||
const errno_t no_error = ( errno_t) 0; | ||
errno_t result = ( errno_t ) 0; | ||
bool have_result = false; | ||
bool terminator_found = false; | ||
|
||
// If dst is null then dst_size_bytes should be ignored according to the | ||
// standard. Setting dest_remaining to a large value has this effect. | ||
if (!dst) | ||
dest_remaining = static_cast<size_t>(-1); | ||
|
||
while ( source_converted != max_source_chars ) { | ||
if ( ! dest_remaining ) | ||
break; | ||
wchar_t c = (*src)[source_converted]; | ||
if ( dst ) | ||
result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps); | ||
else | ||
result = wcrtomb_s( &char_size, NULL, 0, c, ps); | ||
// If result is zero there is no error and char_size contains the | ||
// size of the multi-byte-sequence converted. | ||
// Otherwise result indicates an errno type error. | ||
if ( result == no_error ) { | ||
if ( c == L'\0' ) { | ||
terminator_found = true; | ||
break; | ||
} | ||
++source_converted; | ||
if ( dst ) | ||
dest_remaining -= char_size; | ||
dest_converted += char_size; | ||
continue; | ||
} | ||
have_result = true; | ||
break; | ||
} | ||
if ( dst ) { | ||
if ( terminator_found ) | ||
*src = NULL; | ||
else | ||
*src = *src + source_converted; | ||
} | ||
if ( have_result && result != no_error ) { | ||
errno = result; | ||
return static_cast<size_t>(-1); | ||
} | ||
|
||
return dest_converted; | ||
} |