Path: blob/main/contrib/llvm-project/libcxx/src/support/ibm/wcsnrtombs.cpp
35291 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <cwchar> // mbstate_t9#include <limits.h> // MB_LEN_MAX10#include <stdlib.h> // MB_CUR_MAX, size_t11#include <string.h> // memcpy1213// Converts `max_source_chars` from the wide character buffer pointer to by *`src`,14// into the multi byte character sequence buffer stored at `dst`, which must be15// `dst_size_bytes` bytes in size. Returns the number of bytes in the sequence16// converted from *src, excluding the null terminator.17// Returns (size_t) -1 if an error occurs and sets errno.18// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.19_LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(20char* __restrict dst,21const wchar_t** __restrict src,22size_t max_source_chars,23size_t dst_size_bytes,24mbstate_t* __restrict ps) {25const size_t invalid_wchar = static_cast<size_t>(-1);2627size_t source_converted;28size_t dest_converted;29size_t result = 0;3031// If `dst` is null then `dst_size_bytes` should be ignored according to the32// standard. Setting dst_size_bytes to a large value has this effect.33if (dst == nullptr)34dst_size_bytes = static_cast<size_t>(-1);3536for (dest_converted = source_converted = 0;37source_converted < max_source_chars && (!dst || dest_converted < dst_size_bytes);38++source_converted, dest_converted += result) {39wchar_t c = (*src)[source_converted];40size_t dest_remaining = dst_size_bytes - dest_converted;4142if (dst == nullptr) {43result = wcrtomb(NULL, c, ps);44} else if (dest_remaining >= static_cast<size_t>(MB_CUR_MAX)) {45// dst has enough space to translate in-place.46result = wcrtomb(dst + dest_converted, c, ps);47} else {48/*49* dst may not have enough space, so use a temporary buffer.50*51* We need to save a copy of the conversion state52* here so we can restore it if the multibyte53* character is too long for the buffer.54*/55char buff[MB_LEN_MAX];56mbstate_t mbstate_tmp;5758if (ps != nullptr)59mbstate_tmp = *ps;60result = wcrtomb(buff, c, ps);6162if (result > dest_remaining) {63// Multi-byte sequence for character won't fit.64if (ps != nullptr)65*ps = mbstate_tmp;66if (result != invalid_wchar)67break;68} else {69// The buffer was used, so we need copy the translation to dst.70memcpy(dst, buff, result);71}72}7374// result (char_size) contains the size of the multi-byte-sequence converted.75// Otherwise, result (char_size) is (size_t) -1 and wcrtomb() sets the errno.76if (result == invalid_wchar) {77if (dst)78*src = *src + source_converted;79return invalid_wchar;80}8182if (c == L'\0') {83if (dst)84*src = NULL;85return dest_converted;86}87}8889if (dst)90*src = *src + source_converted;9192return dest_converted;93}949596