* commit '5d4c911436445e627dcc9533bfc0792941b83a44': Switch to a working UTF-8 mb/wc implementation.
This commit is contained in:
		@@ -214,6 +214,7 @@ libc_bionic_src_files := \
 | 
				
			|||||||
    bionic/utimes.cpp \
 | 
					    bionic/utimes.cpp \
 | 
				
			||||||
    bionic/wait.cpp \
 | 
					    bionic/wait.cpp \
 | 
				
			||||||
    bionic/wchar.cpp \
 | 
					    bionic/wchar.cpp \
 | 
				
			||||||
 | 
					    bionic/wctype.cpp \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libc_upstream_freebsd_src_files := \
 | 
					libc_upstream_freebsd_src_files := \
 | 
				
			||||||
    upstream-freebsd/lib/libc/gen/ldexp.c \
 | 
					    upstream-freebsd/lib/libc/gen/ldexp.c \
 | 
				
			||||||
@@ -356,6 +357,7 @@ libc_upstream_openbsd_src_files := \
 | 
				
			|||||||
    upstream-openbsd/lib/libc/locale/wcstoumax.c \
 | 
					    upstream-openbsd/lib/libc/locale/wcstoumax.c \
 | 
				
			||||||
    upstream-openbsd/lib/libc/locale/wcsxfrm.c \
 | 
					    upstream-openbsd/lib/libc/locale/wcsxfrm.c \
 | 
				
			||||||
    upstream-openbsd/lib/libc/locale/wctob.c \
 | 
					    upstream-openbsd/lib/libc/locale/wctob.c \
 | 
				
			||||||
 | 
					    upstream-openbsd/lib/libc/locale/wctomb.c \
 | 
				
			||||||
    upstream-openbsd/lib/libc/stdio/asprintf.c \
 | 
					    upstream-openbsd/lib/libc/stdio/asprintf.c \
 | 
				
			||||||
    upstream-openbsd/lib/libc/stdio/clrerr.c \
 | 
					    upstream-openbsd/lib/libc/stdio/clrerr.c \
 | 
				
			||||||
    upstream-openbsd/lib/libc/stdio/fdopen.c \
 | 
					    upstream-openbsd/lib/libc/stdio/fdopen.c \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,8 +75,12 @@ static void __locale_init() {
 | 
				
			|||||||
  gLocale.int_n_sign_posn = CHAR_MAX;
 | 
					  gLocale.int_n_sign_posn = CHAR_MAX;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool __bionic_current_locale_is_utf8 = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool __is_supported_locale(const char* locale) {
 | 
					static bool __is_supported_locale(const char* locale) {
 | 
				
			||||||
  return (strcmp(locale, "") == 0 || strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0);
 | 
					  return (strcmp(locale, "") == 0 ||
 | 
				
			||||||
 | 
					          strcmp(locale, "C") == 0 || strcmp(locale, "C.UTF-8") == 0 ||
 | 
				
			||||||
 | 
					          strcmp(locale, "POSIX") == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static locale_t __new_locale() {
 | 
					static locale_t __new_locale() {
 | 
				
			||||||
@@ -115,26 +119,24 @@ locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/
 | 
				
			|||||||
  return __new_locale();
 | 
					  return __new_locale();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char* setlocale(int category, char const* locale_name) {
 | 
					char* setlocale(int category, const char* locale_name) {
 | 
				
			||||||
  // Is 'category' valid?
 | 
					  // Is 'category' valid?
 | 
				
			||||||
  if (category < LC_CTYPE || category > LC_IDENTIFICATION) {
 | 
					  if (category < LC_CTYPE || category > LC_IDENTIFICATION) {
 | 
				
			||||||
    errno = EINVAL;
 | 
					    errno = EINVAL;
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Caller just wants to query the current locale?
 | 
					  // Caller wants to set the locale rather than just query?
 | 
				
			||||||
  if (locale_name == NULL) {
 | 
					  if (locale_name != NULL) {
 | 
				
			||||||
    return const_cast<char*>("C");
 | 
					    if (!__is_supported_locale(locale_name)) {
 | 
				
			||||||
 | 
					      // We don't support this locale.
 | 
				
			||||||
 | 
					      errno = ENOENT;
 | 
				
			||||||
 | 
					      return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    __bionic_current_locale_is_utf8 = (strstr(locale_name, "UTF-8") != NULL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Caller wants one of the mandatory POSIX locales?
 | 
					  return const_cast<char*>(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C");
 | 
				
			||||||
  if (__is_supported_locale(locale_name)) {
 | 
					 | 
				
			||||||
    return const_cast<char*>("C");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // We don't support any other locales.
 | 
					 | 
				
			||||||
  errno = ENOENT;
 | 
					 | 
				
			||||||
  return NULL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
locale_t uselocale(locale_t new_locale) {
 | 
					locale_t uselocale(locale_t new_locale) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,215 +1,307 @@
 | 
				
			|||||||
/*
 | 
					/*	$OpenBSD: citrus_utf8.c,v 1.6 2012/12/05 23:19:59 deraadt Exp $ */
 | 
				
			||||||
 * Copyright (C) 2008 The Android Open Source Project
 | 
					
 | 
				
			||||||
 | 
					/*-
 | 
				
			||||||
 | 
					 * Copyright (c) 2002-2004 Tim J. Robbins
 | 
				
			||||||
 * All rights reserved.
 | 
					 * All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Redistribution and use in source and binary forms, with or without
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 * modification, are permitted provided that the following conditions
 | 
					 * modification, are permitted provided that the following conditions
 | 
				
			||||||
 * are met:
 | 
					 * are met:
 | 
				
			||||||
 *  * Redistributions of source code must retain the above copyright
 | 
					 * 1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 *    notice, this list of conditions and the following disclaimer.
 | 
					 *    notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 *  * Redistributions in binary form must reproduce the above copyright
 | 
					 * 2. Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 *    notice, this list of conditions and the following disclaimer in
 | 
					 *    notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 *    the documentation and/or other materials provided with the
 | 
					 *    documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 *    distribution.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | 
				
			||||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
					 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
					 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
				
			||||||
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
					 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
					 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
				
			||||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | 
					 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
					 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
					 | 
				
			||||||
 * SUCH DAMAGE.
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <limits.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/param.h>
 | 
				
			||||||
#include <wchar.h>
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* stubs for wide-char functions */
 | 
					//
 | 
				
			||||||
 | 
					// This file is basically OpenBSD's citrus_utf8.c but rewritten to not require a 12-byte mbstate_t
 | 
				
			||||||
 | 
					// so we're backwards-compatible with our LP32 ABI where mbstate_t was only 4 bytes. An additional
 | 
				
			||||||
 | 
					// advantage of this is that callers who don't supply their own mbstate_t won't be accessing shared
 | 
				
			||||||
 | 
					// state.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// We also implement the POSIX interface directly rather than being accessed via function pointers.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int iswalnum(wint_t wc) { return isalnum(wc); }
 | 
					#define ERR_ILLEGAL_SEQUENCE static_cast<size_t>(-1)
 | 
				
			||||||
int iswalpha(wint_t wc) { return isalpha(wc); }
 | 
					#define ERR_INCOMPLETE_SEQUENCE static_cast<size_t>(-2)
 | 
				
			||||||
int iswblank(wint_t wc) { return isblank(wc); }
 | 
					 | 
				
			||||||
int iswcntrl(wint_t wc) { return iscntrl(wc); }
 | 
					 | 
				
			||||||
int iswdigit(wint_t wc) { return isdigit(wc); }
 | 
					 | 
				
			||||||
int iswgraph(wint_t wc) { return isgraph(wc); }
 | 
					 | 
				
			||||||
int iswlower(wint_t wc) { return islower(wc); }
 | 
					 | 
				
			||||||
int iswprint(wint_t wc) { return isprint(wc); }
 | 
					 | 
				
			||||||
int iswpunct(wint_t wc) { return ispunct(wc); }
 | 
					 | 
				
			||||||
int iswspace(wint_t wc) { return isspace(wc); }
 | 
					 | 
				
			||||||
int iswupper(wint_t wc) { return isupper(wc); }
 | 
					 | 
				
			||||||
int iswxdigit(wint_t wc) { return isxdigit(wc); }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int iswctype(wint_t wc, wctype_t char_class) {
 | 
					int mbsinit(const mbstate_t*) {
 | 
				
			||||||
  switch (char_class) {
 | 
					  // We have no state, so we're always in the initial state.
 | 
				
			||||||
    case WC_TYPE_ALNUM: return isalnum(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_ALPHA: return isalpha(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_BLANK: return isblank(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_CNTRL: return iscntrl(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_DIGIT: return isdigit(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_GRAPH: return isgraph(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_LOWER: return islower(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_PRINT: return isprint(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_PUNCT: return ispunct(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_SPACE: return isspace(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_UPPER: return isupper(wc);
 | 
					 | 
				
			||||||
    case WC_TYPE_XDIGIT: return isxdigit(wc);
 | 
					 | 
				
			||||||
    default: return 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mbsinit(const mbstate_t* /*ps*/) {
 | 
					 | 
				
			||||||
  return 1;
 | 
					  return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* /*ps*/) {
 | 
					size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t*) {
 | 
				
			||||||
  if (s == NULL) {
 | 
					  if (s == NULL) {
 | 
				
			||||||
    return 0;
 | 
					    s = "";
 | 
				
			||||||
 | 
					    n = 1;
 | 
				
			||||||
 | 
					    pwc = NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (n == 0) {
 | 
					  if (n == 0) {
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (pwc != NULL) {
 | 
					 | 
				
			||||||
    *pwc = *s;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return (*s != 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t n, size_t dst_size, mbstate_t* /*ps*/) {
 | 
					  int ch;
 | 
				
			||||||
  size_t i = 0; // Number of input bytes read.
 | 
					  if (((ch = static_cast<uint8_t>(*s)) & ~0x7f) == 0) {
 | 
				
			||||||
  size_t o = 0; // Number of output characters written.
 | 
					    // Fast path for plain ASCII characters.
 | 
				
			||||||
  for (; i < n && (*src)[i] != 0; ++i) {
 | 
					    if (pwc != NULL) {
 | 
				
			||||||
    // TODO: UTF-8 support.
 | 
					      *pwc = ch;
 | 
				
			||||||
    if (static_cast<uint8_t>((*src)[i]) > 0x7f) {
 | 
					 | 
				
			||||||
      errno = EILSEQ;
 | 
					 | 
				
			||||||
      if (dst != NULL) {
 | 
					 | 
				
			||||||
        *src = &(*src)[i];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return static_cast<size_t>(-1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (dst != NULL) {
 | 
					 | 
				
			||||||
      if (o + 1 > dst_size) {
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      dst[o++] = static_cast<wchar_t>((*src)[i]);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      ++o;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return (ch != '\0' ? 1 : 0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // If we consumed all the input, terminate the output.
 | 
					 | 
				
			||||||
  if (dst != NULL && o < dst_size) {
 | 
					 | 
				
			||||||
    dst[o] = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // If we were actually consuming input, record how far we got.
 | 
					 | 
				
			||||||
  if (dst != NULL) {
 | 
					 | 
				
			||||||
    if ((*src)[i] != 0) {
 | 
					 | 
				
			||||||
      *src = &(*src)[i]; // This is where the next call should pick up.
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      *src = NULL; // We consumed everything.
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return o;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t mbsrtowcs(wchar_t* dst, const char** src, size_t dst_size, mbstate_t* ps) {
 | 
					  // Determine the number of octets that make up this character
 | 
				
			||||||
  return mbsnrtowcs(dst, src, SIZE_MAX, dst_size, ps);
 | 
					  // from the first octet, and a mask that extracts the
 | 
				
			||||||
}
 | 
					  // interesting bits of the first octet. We already know
 | 
				
			||||||
 | 
					  // the character is at least two bytes long.
 | 
				
			||||||
 | 
					  int length;
 | 
				
			||||||
 | 
					  int mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wint_t towlower(wint_t wc) {
 | 
					  // We also specify a lower bound for the character code to
 | 
				
			||||||
  return tolower(wc);
 | 
					  // detect redundant, non-"shortest form" encodings. For
 | 
				
			||||||
}
 | 
					  // example, the sequence C0 80 is _not_ a legal representation
 | 
				
			||||||
 | 
					  // of the null character. This enforces a 1-to-1 mapping
 | 
				
			||||||
 | 
					  // between character codes and their multibyte representations.
 | 
				
			||||||
 | 
					  wchar_t lower_bound;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wint_t towupper(wint_t wc) {
 | 
					  ch = static_cast<uint8_t>(*s);
 | 
				
			||||||
  return toupper(wc);
 | 
					  if ((ch & 0x80) == 0) {
 | 
				
			||||||
}
 | 
					    mask = 0x7f;
 | 
				
			||||||
 | 
					    length = 1;
 | 
				
			||||||
int wctomb(char* s, wchar_t wc) {
 | 
					    lower_bound = 0;
 | 
				
			||||||
  if (s == NULL) {
 | 
					  } else if ((ch & 0xe0) == 0xc0) {
 | 
				
			||||||
    return 0;
 | 
					    mask = 0x1f;
 | 
				
			||||||
  }
 | 
					    length = 2;
 | 
				
			||||||
  if (wc <= 0xff) {
 | 
					    lower_bound = 0x80;
 | 
				
			||||||
    *s = static_cast<char>(wc);
 | 
					  } else if ((ch & 0xf0) == 0xe0) {
 | 
				
			||||||
 | 
					    mask = 0x0f;
 | 
				
			||||||
 | 
					    length = 3;
 | 
				
			||||||
 | 
					    lower_bound = 0x800;
 | 
				
			||||||
 | 
					  } else if ((ch & 0xf8) == 0xf0) {
 | 
				
			||||||
 | 
					    mask = 0x07;
 | 
				
			||||||
 | 
					    length = 4;
 | 
				
			||||||
 | 
					    lower_bound = 0x10000;
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    *s = '?';
 | 
					    // Malformed input; input is not UTF-8. See RFC 3629.
 | 
				
			||||||
 | 
					    errno = EILSEQ;
 | 
				
			||||||
 | 
					    return ERR_ILLEGAL_SEQUENCE;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t wcrtomb(char* s, wchar_t wc, mbstate_t* /*ps*/) {
 | 
					  // Decode the octet sequence representing the character in chunks
 | 
				
			||||||
  if (s == NULL) {
 | 
					  // of 6 bits, most significant first.
 | 
				
			||||||
    char buf[MB_LEN_MAX];
 | 
					  wchar_t wch = static_cast<uint8_t>(*s++) & mask;
 | 
				
			||||||
    return wctomb(buf, L'\0');
 | 
					  int i;
 | 
				
			||||||
  }
 | 
					  for (i = 1; i < MIN(length, n); i++) {
 | 
				
			||||||
  return wctomb(s, wc);
 | 
					    if ((*s & 0xc0) != 0x80) {
 | 
				
			||||||
}
 | 
					      // Malformed input; bad characters in the middle of a character.
 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t wcsftime(wchar_t* wcs, size_t maxsize, const wchar_t* format,  const struct tm* timptr) {
 | 
					 | 
				
			||||||
  return strftime(reinterpret_cast<char*>(wcs), maxsize, reinterpret_cast<const char*>(format), timptr);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t wcsnrtombs(char* dst, const wchar_t** src, size_t n, size_t dst_size, mbstate_t* /*ps*/) {
 | 
					 | 
				
			||||||
  size_t i = 0; // Number of input characters read.
 | 
					 | 
				
			||||||
  size_t o = 0; // Number of output bytes written.
 | 
					 | 
				
			||||||
  for (; i < n && (*src)[i] != 0; ++i) {
 | 
					 | 
				
			||||||
    // TODO: UTF-8 support.
 | 
					 | 
				
			||||||
    if ((*src)[i] > 0x7f) {
 | 
					 | 
				
			||||||
      errno = EILSEQ;
 | 
					      errno = EILSEQ;
 | 
				
			||||||
      if (dst != NULL) {
 | 
					      return ERR_ILLEGAL_SEQUENCE;
 | 
				
			||||||
        *src = &(*src)[i];
 | 
					    }
 | 
				
			||||||
 | 
					    wch <<= 6;
 | 
				
			||||||
 | 
					    wch |= *s++ & 0x3f;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (i < length) {
 | 
				
			||||||
 | 
					    return ERR_INCOMPLETE_SEQUENCE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (wch < lower_bound) {
 | 
				
			||||||
 | 
					    // Malformed input; redundant encoding.
 | 
				
			||||||
 | 
					    errno = EILSEQ;
 | 
				
			||||||
 | 
					    return ERR_ILLEGAL_SEQUENCE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if ((wch >= 0xd800 && wch <= 0xdfff) || wch == 0xfffe || wch == 0xffff) {
 | 
				
			||||||
 | 
					    // Malformed input; invalid code points.
 | 
				
			||||||
 | 
					    errno = EILSEQ;
 | 
				
			||||||
 | 
					    return ERR_ILLEGAL_SEQUENCE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (pwc != NULL) {
 | 
				
			||||||
 | 
					    *pwc = wch;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (wch == L'\0' ? 0 : length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, mbstate_t* ps) {
 | 
				
			||||||
 | 
					  size_t i, o, r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (dst == NULL) {
 | 
				
			||||||
 | 
					    for (i = o = 0; i < nmc; i += r, o++) {
 | 
				
			||||||
 | 
					      if (static_cast<uint8_t>((*src)[i]) < 0x80) {
 | 
				
			||||||
 | 
					        // Fast path for plain ASCII characters.
 | 
				
			||||||
 | 
					        if ((*src)[i] == '\0') {
 | 
				
			||||||
 | 
					          return o;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        r = 1;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        r = mbrtowc(NULL, *src + i, nmc - i, ps);
 | 
				
			||||||
 | 
					        if (r == ERR_ILLEGAL_SEQUENCE) {
 | 
				
			||||||
 | 
					          return r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (r == ERR_INCOMPLETE_SEQUENCE) {
 | 
				
			||||||
 | 
					          return o;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (r == 0) {
 | 
				
			||||||
 | 
					          return o;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return static_cast<size_t>(-1);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (dst != NULL) {
 | 
					    return o;
 | 
				
			||||||
      if (o + 1 > dst_size) {
 | 
					  }
 | 
				
			||||||
        break;
 | 
					
 | 
				
			||||||
 | 
					  for (i = o = 0; i < nmc && o < len; i += r, o++) {
 | 
				
			||||||
 | 
					    if (static_cast<uint8_t>((*src)[i]) < 0x80) {
 | 
				
			||||||
 | 
					      // Fast path for plain ASCII characters.
 | 
				
			||||||
 | 
					      dst[o] = (*src)[i];
 | 
				
			||||||
 | 
					      if ((*src)[i] == '\0') {
 | 
				
			||||||
 | 
					        *src = NULL;
 | 
				
			||||||
 | 
					        return o;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      dst[o++] = static_cast<char>((*src)[i]);
 | 
					      r = 1;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ++o;
 | 
					      r = mbrtowc(dst + o, *src + i, nmc - i, ps);
 | 
				
			||||||
    }
 | 
					      if (r == ERR_ILLEGAL_SEQUENCE) {
 | 
				
			||||||
  }
 | 
					        *src += i;
 | 
				
			||||||
  // If we consumed all the input, terminate the output.
 | 
					        return r;
 | 
				
			||||||
  if (dst != NULL && o < dst_size) {
 | 
					      }
 | 
				
			||||||
    dst[o] = 0;
 | 
					      if (r == ERR_INCOMPLETE_SEQUENCE) {
 | 
				
			||||||
  }
 | 
					        *src += nmc;
 | 
				
			||||||
  // If we were actually consuming input, record how far we got.
 | 
					        return o;
 | 
				
			||||||
  if (dst != NULL) {
 | 
					      }
 | 
				
			||||||
    if ((*src)[i] != 0) {
 | 
					      if (r == 0) {
 | 
				
			||||||
      *src = &(*src)[i]; // This is where the next call should pick up.
 | 
					        *src = NULL;
 | 
				
			||||||
    } else {
 | 
					        return o;
 | 
				
			||||||
      *src = NULL; // We consumed everything.
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  *src += i;
 | 
				
			||||||
  return o;
 | 
					  return o;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t wcsrtombs(char* dst, const wchar_t** src, size_t dst_size, mbstate_t* ps) {
 | 
					size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) {
 | 
				
			||||||
  return wcsnrtombs(dst, src, SIZE_MAX, dst_size, ps);
 | 
					  return mbsnrtowcs(dst, src, SIZE_MAX, len, ps);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wctype_t wctype(const char* property) {
 | 
					size_t wcrtomb(char* s, wchar_t wc, mbstate_t*) {
 | 
				
			||||||
  static const char* const  properties[WC_TYPE_MAX] = {
 | 
					  unsigned char lead;
 | 
				
			||||||
    "<invalid>",
 | 
					  int i, len;
 | 
				
			||||||
    "alnum", "alpha", "blank", "cntrl", "digit", "graph",
 | 
					
 | 
				
			||||||
    "lower", "print", "punct", "space", "upper", "xdigit"
 | 
					  if (s == NULL) {
 | 
				
			||||||
  };
 | 
					    // Reset to initial shift state (no-op).
 | 
				
			||||||
  for (size_t i = 0; i < WC_TYPE_MAX; ++i) {
 | 
					    return 1;
 | 
				
			||||||
    if (!strcmp(properties[i], property)) {
 | 
					  }
 | 
				
			||||||
      return static_cast<wctype_t>(i);
 | 
					
 | 
				
			||||||
 | 
					  if ((wc & ~0x7f) == 0) {
 | 
				
			||||||
 | 
					    // Fast path for plain ASCII characters.
 | 
				
			||||||
 | 
					    *s = wc;
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Determine the number of octets needed to represent this character.
 | 
				
			||||||
 | 
					  // We always output the shortest sequence possible. Also specify the
 | 
				
			||||||
 | 
					  // first few bits of the first octet, which contains the information
 | 
				
			||||||
 | 
					  // about the sequence length.
 | 
				
			||||||
 | 
					  if ((wc & ~0x7f) == 0) {
 | 
				
			||||||
 | 
					    lead = 0;
 | 
				
			||||||
 | 
					    len = 1;
 | 
				
			||||||
 | 
					  } else if ((wc & ~0x7ff) == 0) {
 | 
				
			||||||
 | 
					    lead = 0xc0;
 | 
				
			||||||
 | 
					    len = 2;
 | 
				
			||||||
 | 
					  } else if ((wc & ~0xffff) == 0) {
 | 
				
			||||||
 | 
					    lead = 0xe0;
 | 
				
			||||||
 | 
					    len = 3;
 | 
				
			||||||
 | 
					  } else if ((wc & ~0x1fffff) == 0) {
 | 
				
			||||||
 | 
					    lead = 0xf0;
 | 
				
			||||||
 | 
					    len = 4;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    errno = EILSEQ;
 | 
				
			||||||
 | 
					    return ERR_ILLEGAL_SEQUENCE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output the octets representing the character in chunks
 | 
				
			||||||
 | 
					  // of 6 bits, least significant last. The first octet is
 | 
				
			||||||
 | 
					  // a special case because it contains the sequence length
 | 
				
			||||||
 | 
					  // information.
 | 
				
			||||||
 | 
					  for (i = len - 1; i > 0; i--) {
 | 
				
			||||||
 | 
					    s[i] = (wc & 0x3f) | 0x80;
 | 
				
			||||||
 | 
					    wc >>= 6;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  *s = (wc & 0xff) | lead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len, mbstate_t* ps) {
 | 
				
			||||||
 | 
					  char buf[MB_LEN_MAX];
 | 
				
			||||||
 | 
					  size_t i, o, r;
 | 
				
			||||||
 | 
					  if (dst == NULL) {
 | 
				
			||||||
 | 
					    for (i = o = 0; i < nwc; i++, o += r) {
 | 
				
			||||||
 | 
					      wchar_t wc = (*src)[i];
 | 
				
			||||||
 | 
					      if (wc < 0x80) {
 | 
				
			||||||
 | 
					        // Fast path for plain ASCII characters.
 | 
				
			||||||
 | 
					        if (wc == 0) {
 | 
				
			||||||
 | 
					          return o;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        r = 1;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        r = wcrtomb(buf, wc, ps);
 | 
				
			||||||
 | 
					        if (r == ERR_ILLEGAL_SEQUENCE) {
 | 
				
			||||||
 | 
					          return r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return o;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i = o = 0; i < nwc && o < len; i++, o += r) {
 | 
				
			||||||
 | 
					    wchar_t wc = (*src)[i];
 | 
				
			||||||
 | 
					    if (wc < 0x80) {
 | 
				
			||||||
 | 
					      // Fast path for plain ASCII characters.
 | 
				
			||||||
 | 
					      dst[o] = wc;
 | 
				
			||||||
 | 
					      if (wc == 0) {
 | 
				
			||||||
 | 
					        *src = NULL;
 | 
				
			||||||
 | 
					        return o;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      r = 1;
 | 
				
			||||||
 | 
					    } else if (len - o >= sizeof(buf)) {
 | 
				
			||||||
 | 
					      // Enough space to translate in-place.
 | 
				
			||||||
 | 
					      r = wcrtomb(dst + o, wc, ps);
 | 
				
			||||||
 | 
					      if (r == ERR_ILLEGAL_SEQUENCE) {
 | 
				
			||||||
 | 
					        *src += i;
 | 
				
			||||||
 | 
					        return r;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // May not be enough space; use temp buffer.
 | 
				
			||||||
 | 
					      r = wcrtomb(buf, wc, ps);
 | 
				
			||||||
 | 
					      if (r == ERR_ILLEGAL_SEQUENCE) {
 | 
				
			||||||
 | 
					        *src += i;
 | 
				
			||||||
 | 
					        return r;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (r > len - o) {
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      memcpy(dst + o, buf, r);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return static_cast<wctype_t>(0);
 | 
					  *src += i;
 | 
				
			||||||
 | 
					  return o;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int wcwidth(wchar_t wc) {
 | 
					size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps) {
 | 
				
			||||||
  return (wc > 0);
 | 
					  return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										91
									
								
								libc/bionic/wctype.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								libc/bionic/wctype.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2008 The Android Open Source Project
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions
 | 
				
			||||||
 | 
					 * are met:
 | 
				
			||||||
 | 
					 *  * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *  * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer in
 | 
				
			||||||
 | 
					 *    the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					 *    distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
				
			||||||
 | 
					 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
				
			||||||
 | 
					 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | 
				
			||||||
 | 
					 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
				
			||||||
 | 
					 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
				
			||||||
 | 
					 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
				
			||||||
 | 
					 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: these only work for the ASCII range; rewrite to dlsym icu4c?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int iswalnum(wint_t wc) { return isalnum(wc); }
 | 
				
			||||||
 | 
					int iswalpha(wint_t wc) { return isalpha(wc); }
 | 
				
			||||||
 | 
					int iswblank(wint_t wc) { return isblank(wc); }
 | 
				
			||||||
 | 
					int iswcntrl(wint_t wc) { return iscntrl(wc); }
 | 
				
			||||||
 | 
					int iswdigit(wint_t wc) { return isdigit(wc); }
 | 
				
			||||||
 | 
					int iswgraph(wint_t wc) { return isgraph(wc); }
 | 
				
			||||||
 | 
					int iswlower(wint_t wc) { return islower(wc); }
 | 
				
			||||||
 | 
					int iswprint(wint_t wc) { return isprint(wc); }
 | 
				
			||||||
 | 
					int iswpunct(wint_t wc) { return ispunct(wc); }
 | 
				
			||||||
 | 
					int iswspace(wint_t wc) { return isspace(wc); }
 | 
				
			||||||
 | 
					int iswupper(wint_t wc) { return isupper(wc); }
 | 
				
			||||||
 | 
					int iswxdigit(wint_t wc) { return isxdigit(wc); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int iswctype(wint_t wc, wctype_t char_class) {
 | 
				
			||||||
 | 
					  switch (char_class) {
 | 
				
			||||||
 | 
					    case WC_TYPE_ALNUM: return isalnum(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_ALPHA: return isalpha(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_BLANK: return isblank(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_CNTRL: return iscntrl(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_DIGIT: return isdigit(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_GRAPH: return isgraph(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_LOWER: return islower(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_PRINT: return isprint(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_PUNCT: return ispunct(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_SPACE: return isspace(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_UPPER: return isupper(wc);
 | 
				
			||||||
 | 
					    case WC_TYPE_XDIGIT: return isxdigit(wc);
 | 
				
			||||||
 | 
					    default: return 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wint_t towlower(wint_t wc) { return tolower(wc); }
 | 
				
			||||||
 | 
					wint_t towupper(wint_t wc) { return toupper(wc); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wctype_t wctype(const char* property) {
 | 
				
			||||||
 | 
					  static const char* const  properties[WC_TYPE_MAX] = {
 | 
				
			||||||
 | 
					    "<invalid>",
 | 
				
			||||||
 | 
					    "alnum", "alpha", "blank", "cntrl", "digit", "graph",
 | 
				
			||||||
 | 
					    "lower", "print", "punct", "space", "upper", "xdigit"
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < WC_TYPE_MAX; ++i) {
 | 
				
			||||||
 | 
					    if (!strcmp(properties[i], property)) {
 | 
				
			||||||
 | 
					      return static_cast<wctype_t>(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return static_cast<wctype_t>(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int wcwidth(wchar_t wc) {
 | 
				
			||||||
 | 
					  return (wc > 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: implement wcsftime.
 | 
				
			||||||
 | 
					size_t wcsftime(wchar_t* wcs, size_t maxsize, const wchar_t* format,  const struct tm* timptr) {
 | 
				
			||||||
 | 
					  abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								libc/upstream-openbsd/lib/libc/locale/wctomb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								libc/upstream-openbsd/lib/libc/locale/wctomb.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					/*	$OpenBSD: wctomb.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-
 | 
				
			||||||
 | 
					 * Copyright (c) 2002-2004 Tim J. Robbins.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions
 | 
				
			||||||
 | 
					 * are met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 * 2. Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *    documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | 
				
			||||||
 | 
					 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 | 
					 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
				
			||||||
 | 
					 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
				
			||||||
 | 
					 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					wctomb(char *s, wchar_t wchar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static mbstate_t mbs;
 | 
				
			||||||
 | 
						size_t rval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (s == NULL) {
 | 
				
			||||||
 | 
							/* No support for state dependent encodings. */
 | 
				
			||||||
 | 
							memset(&mbs, 0, sizeof(mbs));
 | 
				
			||||||
 | 
							return (0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ((rval = wcrtomb(s, wchar, &mbs)) == (size_t)-1)
 | 
				
			||||||
 | 
							return (-1);
 | 
				
			||||||
 | 
						return ((int)rval);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,6 +18,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <locale.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <wchar.h>
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,18 +50,46 @@ TEST(wchar, wctomb_wcrtomb) {
 | 
				
			|||||||
  EXPECT_EQ(1U, wcrtomb(bytes, L'\0', NULL));
 | 
					  EXPECT_EQ(1U, wcrtomb(bytes, L'\0', NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // ...and for regular characters.
 | 
					  // ...and for regular characters.
 | 
				
			||||||
  bytes[0] = 'x';
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
  EXPECT_EQ(1, wctomb(bytes, L'h'));
 | 
					  EXPECT_EQ(1, wctomb(bytes, L'h'));
 | 
				
			||||||
  EXPECT_EQ('h', bytes[0]);
 | 
					  EXPECT_EQ('h', bytes[0]);
 | 
				
			||||||
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
  bytes[0] = 'x';
 | 
					 | 
				
			||||||
  EXPECT_EQ(1U, wcrtomb(bytes, L'h', NULL));
 | 
					  EXPECT_EQ(1U, wcrtomb(bytes, L'h', NULL));
 | 
				
			||||||
  EXPECT_EQ('h', bytes[0]);
 | 
					  EXPECT_EQ('h', bytes[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
 | 
				
			||||||
 | 
					  uselocale(LC_GLOBAL_LOCALE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 1-byte UTF-8.
 | 
				
			||||||
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
 | 
					  EXPECT_EQ(1U, wcrtomb(bytes, L'h', NULL));
 | 
				
			||||||
 | 
					  EXPECT_EQ('h', bytes[0]);
 | 
				
			||||||
 | 
					  // 2-byte UTF-8.
 | 
				
			||||||
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
 | 
					  EXPECT_EQ(2U, wcrtomb(bytes, 0x00a2, NULL));
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xc2', bytes[0]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xa2', bytes[1]);
 | 
				
			||||||
 | 
					  // 3-byte UTF-8.
 | 
				
			||||||
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
 | 
					  EXPECT_EQ(3U, wcrtomb(bytes, 0x20ac, NULL));
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xe2', bytes[0]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\x82', bytes[1]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xac', bytes[2]);
 | 
				
			||||||
 | 
					  // 4-byte UTF-8.
 | 
				
			||||||
 | 
					  memset(bytes, 0, sizeof(bytes));
 | 
				
			||||||
 | 
					  EXPECT_EQ(4U, wcrtomb(bytes, 0x24b62, NULL));
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xf0', bytes[0]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xa4', bytes[1]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xad', bytes[2]);
 | 
				
			||||||
 | 
					  EXPECT_EQ('\xa2', bytes[3]);
 | 
				
			||||||
 | 
					  // Invalid code point.
 | 
				
			||||||
 | 
					  EXPECT_EQ(static_cast<size_t>(-1), wcrtomb(bytes, 0xffffffff, NULL));
 | 
				
			||||||
 | 
					  EXPECT_EQ(EILSEQ, errno);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(wchar, wcstombs_wcrtombs) {
 | 
					TEST(wchar, wcstombs_wcrtombs) {
 | 
				
			||||||
  const wchar_t chars[] = { L'h', L'e', L'l', L'l', L'o', 0 };
 | 
					  const wchar_t chars[] = { L'h', L'e', L'l', L'l', L'o', 0 };
 | 
				
			||||||
  const wchar_t bad_chars[] = { L'h', L'i', 666, 0 };
 | 
					  const wchar_t bad_chars[] = { L'h', L'i', 0xffffffff, 0 };
 | 
				
			||||||
  const wchar_t* src;
 | 
					  const wchar_t* src;
 | 
				
			||||||
  char bytes[BUFSIZ];
 | 
					  char bytes[BUFSIZ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,6 +241,30 @@ TEST(wchar, mbrtowc) {
 | 
				
			|||||||
  ASSERT_EQ(1U, mbrtowc(NULL, "hello", 1, NULL));
 | 
					  ASSERT_EQ(1U, mbrtowc(NULL, "hello", 1, NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ASSERT_EQ(0U, mbrtowc(NULL, NULL, 0, NULL));
 | 
					  ASSERT_EQ(0U, mbrtowc(NULL, NULL, 0, NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
 | 
				
			||||||
 | 
					  uselocale(LC_GLOBAL_LOCALE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 1-byte UTF-8.
 | 
				
			||||||
 | 
					  ASSERT_EQ(1U, mbrtowc(out, "abcdef", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(L'a', out[0]);
 | 
				
			||||||
 | 
					  // 2-byte UTF-8.
 | 
				
			||||||
 | 
					  ASSERT_EQ(2U, mbrtowc(out, "\xc2\xa2" "cdef", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0x00a2, out[0]);
 | 
				
			||||||
 | 
					  // 3-byte UTF-8.
 | 
				
			||||||
 | 
					  ASSERT_EQ(3U, mbrtowc(out, "\xe2\x82\xac" "def", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0x20ac, out[0]);
 | 
				
			||||||
 | 
					  // 4-byte UTF-8.
 | 
				
			||||||
 | 
					  ASSERT_EQ(4U, mbrtowc(out, "\xf0\xa4\xad\xa2" "ef", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(0x24b62, out[0]);
 | 
				
			||||||
 | 
					#if __BIONIC__ // glibc allows this.
 | 
				
			||||||
 | 
					  // Illegal 5-byte UTF-8.
 | 
				
			||||||
 | 
					  ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EILSEQ, errno);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  // Illegal over-long sequence.
 | 
				
			||||||
 | 
					  ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf0\x82\x82\xac" "ef", 6, NULL));
 | 
				
			||||||
 | 
					  ASSERT_EQ(EILSEQ, errno);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(wchar, wcstod) {
 | 
					TEST(wchar, wcstod) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user