brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.2 KiB · df87b9e Raw
95 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include <cwchar>   // mbstate_t10#include <limits.h> // MB_LEN_MAX11#include <stdlib.h> // MB_CUR_MAX, size_t12#include <string.h> // memcpy13 14// Converts `max_source_chars` from the wide character buffer pointer to by *`src`,15// into the multi byte character sequence buffer stored at `dst`, which must be16// `dst_size_bytes` bytes in size. Returns the number of bytes in the sequence17// converted from *src, excluding the null terminator.18// Returns (size_t) -1 if an error occurs and sets errno.19// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.20_LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(21    char* __restrict dst,22    const wchar_t** __restrict src,23    size_t max_source_chars,24    size_t dst_size_bytes,25    mbstate_t* __restrict ps) {26  const size_t invalid_wchar = static_cast<size_t>(-1);27 28  size_t source_converted;29  size_t dest_converted;30  size_t result = 0;31 32  // If `dst` is null then `dst_size_bytes` should be ignored according to the33  // standard. Setting dst_size_bytes to a large value has this effect.34  if (dst == nullptr)35    dst_size_bytes = static_cast<size_t>(-1);36 37  for (dest_converted = source_converted = 0;38       source_converted < max_source_chars && (!dst || dest_converted < dst_size_bytes);39       ++source_converted, dest_converted += result) {40    wchar_t c             = (*src)[source_converted];41    size_t dest_remaining = dst_size_bytes - dest_converted;42 43    if (dst == nullptr) {44      result = wcrtomb(nullptr, c, ps);45    } else if (dest_remaining >= static_cast<size_t>(MB_CUR_MAX)) {46      // dst has enough space to translate in-place.47      result = wcrtomb(dst + dest_converted, c, ps);48    } else {49      /*50       * dst may not have enough space, so use a temporary buffer.51       *52       * We need to save a copy of the conversion state53       * here so we can restore it if the multibyte54       * character is too long for the buffer.55       */56      char buff[MB_LEN_MAX];57      mbstate_t mbstate_tmp;58 59      if (ps != nullptr)60        mbstate_tmp = *ps;61      result = wcrtomb(buff, c, ps);62 63      if (result > dest_remaining) {64        // Multi-byte sequence for character won't fit.65        if (ps != nullptr)66          *ps = mbstate_tmp;67        if (result != invalid_wchar)68          break;69      } else {70        // The buffer was used, so we need copy the translation to dst.71        memcpy(dst, buff, result);72      }73    }74 75    // result (char_size) contains the size of the multi-byte-sequence converted.76    // Otherwise, result (char_size) is (size_t) -1 and wcrtomb() sets the errno.77    if (result == invalid_wchar) {78      if (dst)79        *src = *src + source_converted;80      return invalid_wchar;81    }82 83    if (c == L'\0') {84      if (dst)85        *src = nullptr;86      return dest_converted;87    }88  }89 90  if (dst)91    *src = *src + source_converted;92 93  return dest_converted;94}95