Merge "libc++: Add wchar support wrappers."
diff --git a/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk b/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk
index 7270b10..4bca4f6 100644
--- a/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk
+++ b/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk
@@ -29,7 +29,8 @@
valarray.cpp
llvm_libc++_sources += \
- support/android/locale_support.c
+ support/android/locale_support.c \
+ support/android/wchar_support.c
llvm_libc++_sources := $(llvm_libc++_sources:%=src/%)
llvm_libc++_cxxflags := -std=c++11
diff --git a/sources/cxx-stl/llvm-libc++/src/support/android/wchar_support.c b/sources/cxx-stl/llvm-libc++/src/support/android/wchar_support.c
new file mode 100644
index 0000000..6987bcd
--- /dev/null
+++ b/sources/cxx-stl/llvm-libc++/src/support/android/wchar_support.c
@@ -0,0 +1,379 @@
+// -*- C++ -*-
+//===-------------------- support/android/wchar_support.c ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+// Returns 1 if 'wc' is in the 'delim' string, 0 otherwise.
+static int _wc_indelim(wchar_t wc, const wchar_t* delim) {
+ while (*delim) {
+ if (wc == *delim)
+ return 1;
+ }
+ return 0;
+}
+
+wchar_t *wcpcpy(wchar_t *to, const wchar_t *from) {
+ size_t n = 0;
+ for (;;) {
+ wchar_t wc = from[n];
+ to[n] = wc;
+ if (wc == L'\0')
+ break;
+ n++;
+ }
+ return to;
+}
+
+wchar_t *wcpncpy(wchar_t *dst, const wchar_t *src, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc = src[i];
+ dst[i] = wc;
+ if (wc == L'\0')
+ break;
+ }
+ while (i < n) {
+ dst[i] = L'\0';
+ ++i;
+ }
+ return &dst[n-1];
+}
+
+int wcscasecmp(const wchar_t *s1, const wchar_t *s2) {
+ size_t n = 0;
+ for (;;) {
+ wchar_t wc1 = towlower(s1[n]);
+ wchar_t wc2 = towlower(s2[n]);
+ if (wc1 != wc2)
+ return (wc1 > wc2) ? +1 : -1;
+ if (wc1 == L'\0')
+ return 0;
+ n++;
+ }
+}
+
+wchar_t *wcscat(wchar_t *s1, const wchar_t *s2) {
+ size_t n = 0;
+ while (s1[n] != L'\0')
+ n++;
+
+ size_t i = 0;
+ for (;;) {
+ wchar_t wc = s2[i];
+ s1[n+i] = wc;
+ if (wc == L'\0')
+ break;
+ }
+ return s1;
+}
+
+size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t siz) {
+ // Sanity check simplifies code below
+ if (siz == 0)
+ return 0;
+
+ // Skip dst characters.
+ size_t n;
+ for (n = 0; n < siz && dst[n] != L'\0'; ++n)
+ ;
+
+ // Copy as much source characters as they fit into siz-1 bytes.
+ size_t i;
+ for (i = 0; n+i+1 < siz && src[i] != L'\0'; ++i)
+ dst[n+i] = src[i];
+
+ // Always zero terminate destination
+ dst[n+i] = L'\0';
+
+ // Skip remaining source characters
+ while (src[i] != L'\0')
+ i++;
+
+ return n+i;
+}
+
+size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz) {
+ size_t i;
+
+ // Copy all non-zero bytes that fit into siz-1 destination bytes
+ for (i = 0; i + 1 < siz && src[i] != L'\0'; ++i)
+ dst[i] = src[i];
+
+ // Always zero-terminate destination buffer
+ dst[i] = L'\0';
+
+ // Skip other source characters.
+ while (src[i] != L'\0')
+ ++i;
+
+ return i;
+}
+
+size_t wcslen(const wchar_t *s) {
+ size_t n = 0;
+ for (;;) {
+ wchar_t wc = s[n];
+ if (wc == L'\0')
+ return n;
+ n++;
+ }
+}
+
+int wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc1 = towlower(s1[i]);
+ wchar_t wc2 = towlower(s2[i]);
+ if (wc1 != wc2)
+ return (wc1 > wc2) ? +1 : -1;
+ }
+ return 0;
+}
+
+wchar_t *wcsncat(wchar_t *s1, const wchar_t *s2, size_t n) {
+ size_t start = 0;
+ while (s1[start] != L'\0')
+ start++;
+
+ // Append s2.
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc = s2[i];
+ s1[start + i] = wc;
+ if (wc == L'\0')
+ break;
+ }
+ return (wchar_t*)s1;
+}
+
+int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc = s1[i];
+ if (wc != s2[i])
+ return (wc > s2[i]) ? +1 : -1;
+ if (wc == L'\0')
+ break;
+ }
+ return 0;
+}
+
+wchar_t *wcsncpy(wchar_t *dst, const wchar_t *src, size_t n) {
+ // Copy initial characters.
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc = src[i];
+ if (wc == L'\0')
+ break;
+ dst[i] = wc;
+ }
+ // zero-pad the remainder.
+ for ( ; i < n; ++i)
+ dst[i] = L'\0';
+
+ return dst;
+}
+
+size_t wcsnlen(const wchar_t *s, size_t maxlen) {
+ size_t n;
+ for (n = 0; n < maxlen; ++n) {
+ if (s[n] == L'\0')
+ break;
+ }
+ return n;
+}
+
+wchar_t *wcspbrk(const wchar_t *s, const wchar_t *set) {
+ size_t n = 0;
+ for (;;) {
+ wchar_t wc = s[n];
+ if (!wc)
+ return NULL;
+ if (_wc_indelim(wc, set))
+ return (wchar_t*)&s[n];
+ n++;
+ }
+}
+
+wchar_t *wcsrchr(const wchar_t *s, wchar_t c) {
+ size_t n = 0;
+ wchar_t* last = NULL;
+ for (;;) {
+ wchar_t wc = s[n];
+ if (wc == c)
+ last = (wchar_t*)s + n;
+ if (wc == L'\0')
+ break;
+ n++;
+ }
+ return last;
+}
+
+size_t wcsspn(const wchar_t *s, const wchar_t *set) {
+ size_t n = 0;
+ for (;;) {
+ wchar_t wc = s[n];
+ if (wc == L'\0')
+ break;
+ if (!_wc_indelim(wc, set))
+ break;
+ ++n;
+ }
+ return n;
+}
+
+wchar_t *wcsstr(const wchar_t *s, const wchar_t *find) {
+ wchar_t find_c;
+
+ // Always find the empty string
+ find_c = *find++;
+ if (!find_c)
+ return (wchar_t*)s;
+
+ size_t find_len = wcslen(find);
+
+ for (;;) {
+ wchar_t* p = wcschr(s, find_c);
+ if (p == NULL)
+ return NULL;
+
+ if (!wmemcmp(p, find, find_len))
+ return p;
+
+ s = p + 1;
+ }
+ return NULL;
+}
+
+wchar_t *wcstok(wchar_t *s, const wchar_t *delim, wchar_t **last) {
+ if (s == NULL) {
+ s = *last;
+ if (s == NULL)
+ return NULL;
+ }
+
+ // Skip leading delimiters first.
+ size_t i = 0;
+ wchar_t wc;
+ for (;;) {
+ wc = s[i];
+ if (wc && _wc_indelim(wc, delim)) {
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ if (!wc) {
+ // Nothing left.
+ *last = NULL;
+ return NULL;
+ }
+
+ size_t tok_start = i;
+
+ // Skip non delimiters now.
+ for (;;) {
+ wc = s[i];
+ if (wc && !_wc_indelim(wc, delim)) {
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ if (!wc) {
+ *last = NULL;
+ } else {
+ s[i] = L'\0';
+ *last = &s[i+1];
+ }
+ return &s[tok_start];
+}
+
+int wcswidth(const wchar_t *str, size_t n) {
+ int len = 0;
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ wchar_t wc = str[i];
+ if (wc == L'\0')
+ break;
+ int l = wcwidth(wc);
+ if (l < 0)
+ return -1;
+ len += l;
+ }
+ return len;
+}
+
+// TODO(digit): Handle real collations.
+size_t wcsxfrm(wchar_t *dst, const wchar_t *src, size_t len) {
+ // Handle trivial case first.
+ if (src[0] == L'\0') {
+ if (len != 0)
+ dst[0] = L'\0';
+ return 0;
+ }
+
+ size_t slen = wcslen(src);
+ if (len > 0) {
+ if (slen < len)
+ wcscpy(dst, src);
+ else {
+ wcsncpy(dst, src, len-1);
+ dst[len - 1] = L'\0';
+ }
+ }
+ return slen;
+}
+
+wchar_t * wmemchr(const wchar_t *s, wchar_t c, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ if (s[i] == c)
+ return (wchar_t*)&s[i];
+ }
+ return NULL;
+}
+
+int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ if (s1[i] == s2[i])
+ continue;
+ if (s1[i] > s2[i])
+ return 1;
+ else
+ return -1;
+ }
+ return 0;
+}
+
+wchar_t * wmemcpy(wchar_t *d, const wchar_t *s, size_t n) {
+ return (wchar_t *)memcpy((char*)d,
+ (const char*)s,
+ n * sizeof(wchar_t));
+}
+
+wchar_t* wmemmove(wchar_t* d, const wchar_t* s, size_t n) {
+ return (wchar_t* )memmove((char*)d,
+ (const char*)s,
+ n * sizeof(wchar_t));
+}
+
+wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i)
+ s[i] = c;
+ return s;
+}
+