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;
+}
+