Merge "libc++: Add locale-specific wrappers for C library functions."
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 4e2448a..7270b10 100644
--- a/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk
+++ b/sources/cxx-stl/llvm-libc++/android/llvm-libc++/Android.mk
@@ -28,6 +28,9 @@
utility.cpp \
valarray.cpp
+llvm_libc++_sources += \
+ support/android/locale_support.c
+
llvm_libc++_sources := $(llvm_libc++_sources:%=src/%)
llvm_libc++_cxxflags := -std=c++11
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/ctype.h b/sources/cxx-stl/llvm-libc++/include/support/android/ctype.h
index 830fb78..847a340 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/ctype.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/ctype.h
@@ -4,7 +4,9 @@
#include_next <ctype.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
# define __exctype_l(name) extern int name (int, locale_t)
@@ -24,6 +26,8 @@
int tolower_l(int c, locale_t);
int toupper_l(int c, locale_t);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_CTYPE_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/locale.h b/sources/cxx-stl/llvm-libc++/include/support/android/locale.h
index 9270560..2f98dc5 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/locale.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/locale.h
Binary files differ
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/math.h b/sources/cxx-stl/llvm-libc++/include/support/android/math.h
index ec5e566..1890945 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/math.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/math.h
@@ -3,6 +3,10 @@
#include_next <math.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// TODO(digit): Check that this is not needed for Clang.
typedef double double_t;
typedef double float_t;
@@ -56,4 +60,8 @@
float log2f(float);
double log2(double);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif /* LLVM_LIBCXX_SUPPORT_ANDROID_MATH_H */
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/nl_types.h b/sources/cxx-stl/llvm-libc++/include/support/android/nl_types.h
index 46248c5..3346da8 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/nl_types.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/nl_types.h
@@ -4,6 +4,10 @@
#define NL_SETD 1
#define NL_CAT_LOCALE 1
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef void* nl_catd;
typedef int nl_item;
@@ -11,5 +15,9 @@
char* catgets(nl_catd, int, int, const char*);
int catclose(nl_catd);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif /* LLVM_LIBCXX_SUPPORT_ANDROID_NL_TYPES_H */
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/stdio.h b/sources/cxx-stl/llvm-libc++/include/support/android/stdio.h
index 8a2915b..8d0b3da 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/stdio.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/stdio.h
@@ -10,9 +10,11 @@
#include <stdarg.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
-char* asprintf_l(char**, locale_t, const char*, ...);
+int asprintf_l(char**, locale_t, const char*, ...);
int sprintf_l(char*, locale_t, const char*, ...);
int snprintf_l(char*, size_t, locale_t, const char*, ...);
int sscanf_l(const char*, locale_t, const char*, ...);
@@ -21,6 +23,8 @@
int vswscanf(const wchar_t *, const wchar_t *, va_list);
int vwscanf(const wchar_t *, va_list);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_STDIO_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/stdlib.h b/sources/cxx-stl/llvm-libc++/include/support/android/stdlib.h
index bb01582..3ce85dd 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/stdlib.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/stdlib.h
@@ -4,7 +4,9 @@
#include_next <stdlib.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
long long strtoll(const char*, char**, int);
long double strtold(const char*, char**);
@@ -16,6 +18,8 @@
unsigned long long strtoull_l(const char *nptr, char **endptr, int base, locale_t loc);
long double strtold_l (const char *nptr, char **endptr, locale_t loc);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_STDLIB_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/string.h b/sources/cxx-stl/llvm-libc++/include/support/android/string.h
index d6b8500..b78b494 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/string.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/string.h
@@ -4,11 +4,15 @@
#include_next <string.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
int strcoll_l(const char*, const char*, locale_t);
int strxfrm_l(char*, const char*, size_t, locale_t);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_STRING_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/time.h b/sources/cxx-stl/llvm-libc++/include/support/android/time.h
index 2715b3e..3706af8 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/time.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/time.h
@@ -4,11 +4,15 @@
#include_next <time.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
size_t strftime_l(char *s, size_t maxsize, const char *format,
const struct tm * timeptr, locale_t locale);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_TIME_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/wchar.h b/sources/cxx-stl/llvm-libc++/include/support/android/wchar.h
index a438d05..f80f592 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/wchar.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/wchar.h
@@ -4,7 +4,9 @@
#include_next <wchar.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
// Add missing declarations that are not in the NDK.
float wcstof(const wchar_t*, wchar_t**);
@@ -25,6 +27,8 @@
int wcscoll_l(const wchar_t*, const wchar_t*, locale_t);
int wcsxfrm_l(wchar_t*, const wchar_t*, size_t, locale_t);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_WCHAR_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/wctype.h b/sources/cxx-stl/llvm-libc++/include/support/android/wctype.h
index 7dd272f..4291f8a 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/wctype.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/wctype.h
@@ -4,7 +4,9 @@
#include_next <wctype.h>
#include <xlocale.h>
+#ifdef __cplusplus
extern "C" {
+#endif
// Add missing declarations from the NDK header. Implemented under
// src/android/wctype.cc
@@ -25,6 +27,8 @@
wint_t towlower_l(wint_t, locale_t);
wint_t towupper_l(wint_t, locale_t);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_WCTYPES_H
diff --git a/sources/cxx-stl/llvm-libc++/include/support/android/xlocale.h b/sources/cxx-stl/llvm-libc++/include/support/android/xlocale.h
index 23e2def..c391c57 100644
--- a/sources/cxx-stl/llvm-libc++/include/support/android/xlocale.h
+++ b/sources/cxx-stl/llvm-libc++/include/support/android/xlocale.h
@@ -1,7 +1,9 @@
#ifndef LLVM_LIBCXX_SUPPORT_ANDROID_XLOCALE_H
#define LLVM_LIBCXX_SUPPORT_ANDROID_XLOCALE_H
+#ifdef __cplusplus
extern "C" {
+#endif
typedef struct locale_struct* locale_t;
@@ -9,6 +11,8 @@
void* dummy;
};
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // LLVM_LIBCXX_SUPPORT_ANDROID_XLOCALE_H
diff --git a/sources/cxx-stl/llvm-libc++/src/support/android/locale_support.c b/sources/cxx-stl/llvm-libc++/src/support/android/locale_support.c
new file mode 100644
index 0000000..7bad7ec
--- /dev/null
+++ b/sources/cxx-stl/llvm-libc++/src/support/android/locale_support.c
@@ -0,0 +1,280 @@
+// -*- C++ -*-
+//===-------------------- support/android/locale_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 <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wctype.h>
+
+// Contains an implementation of all locale-specific functions (those
+// ending in _l, like strcoll_l()), as simple wrapper to the non-locale
+// specific ones for now.
+//
+// That's because Android's C library doesn't support locales. Or more
+// specifically, only supports the "C" one.
+//
+// TODO(digit): Write a more complete implementation that uses JNI to
+// invoke the platform APIs to implement proper handling.
+//
+
+///////////////////////////////////////////////////////////////////////
+// ctype.h declarations
+
+# define define_char_wrapper_l(name) \
+ int name ## _l (int ch, locale_t loc) { \
+ return name (ch); \
+ }
+
+define_char_wrapper_l (isalnum);
+define_char_wrapper_l (isalpha);
+define_char_wrapper_l (iscntrl);
+define_char_wrapper_l (isdigit);
+define_char_wrapper_l (islower);
+define_char_wrapper_l (isgraph);
+define_char_wrapper_l (isprint);
+define_char_wrapper_l (ispunct);
+define_char_wrapper_l (isspace);
+define_char_wrapper_l (isupper);
+define_char_wrapper_l (isxdigit);
+define_char_wrapper_l (isblank);
+define_char_wrapper_l (tolower)
+define_char_wrapper_l (toupper)
+
+///////////////////////////////////////////////////////////////////////
+// stdio.h declarations
+
+int vasprintf_l(char** strp, locale_t l, const char* fmt, va_list args) {
+ // Ignore locale.
+ return vasprintf(strp, fmt, args);
+}
+
+int asprintf_l(char** strp, locale_t locale, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vasprintf_l(strp, locale, fmt, args);
+ va_end(args);
+ return result;
+}
+
+int vsprintf_l(char* str, locale_t l, const char* fmt, va_list args) {
+ // Ignore locale.
+ return vsprintf(str, fmt, args);
+}
+
+int sprintf_l(char* str, locale_t l, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vsprintf_l(str, l, fmt, args);
+ va_end(args);
+ return result;
+}
+
+int vsnprintf_l(char* str, size_t size, locale_t l, const char* fmt, va_list args) {
+ return vsnprintf(str, size, fmt, args);
+}
+
+int snprintf_l(char* str, size_t size, locale_t l, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vsnprintf_l(str, size, l, fmt, args);
+ va_end(args);
+ return result;
+}
+
+int vsscanf_l(const char* str, locale_t l, const char* fmt, va_list args) {
+ return vsscanf(str, fmt, args);
+}
+
+int sscanf_l(const char* str, locale_t l, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vsscanf_l(str, l, fmt, args);
+ va_end(args);
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////
+// stdlib.h declarations
+
+long strtol_l(const char *nptr, char **endptr, int base, locale_t loc) {
+ return strtol(nptr, endptr, base);
+}
+
+long long strtoll_l(const char *nptr, char **endptr, int base, locale_t loc) {
+ return strtoll(nptr, endptr, base);
+}
+
+unsigned long strtoul_l(const char *nptr, char **endptr, int base, locale_t loc) {
+ return strtoul(nptr, endptr, base);
+}
+
+unsigned long long strtoull_l(const char *nptr, char **endptr, int base, locale_t loc) {
+ return strtoull(nptr, endptr, base);
+}
+
+long double strtold_l (const char *nptr, char **endptr, locale_t loc) {
+ return strtold(nptr, endptr);
+}
+
+///////////////////////////////////////////////////////////////////////
+// string.h declarations
+
+int strcoll_l(const char* s1, const char* s2, locale_t loc) {
+ return strcoll(s1, s2);
+}
+
+int strxfrm_l(char* dst, const char* src, size_t n, locale_t loc) {
+ return strxfrm(dst, src, n);
+}
+
+///////////////////////////////////////////////////////////////////////
+// time.h declarations
+
+size_t strftime_l(char *s, size_t maxsize, const char *format,
+ const struct tm * timeptr, locale_t loc) {
+ return strftime(s, maxsize, format, timeptr);
+}
+
+///////////////////////////////////////////////////////////////////////
+// wchar.h declarations
+
+int wcscoll_l(const wchar_t* s1, const wchar_t* s2, locale_t loc) {
+ return wcscoll(s1, s2);
+}
+
+int wcsxfrm_l(wchar_t* dst, const wchar_t* src, size_t n, locale_t loc) {
+ return wcsxfrm(dst, src, n);
+}
+
+///////////////////////////////////////////////////////////////////////
+// wctype.h declarations
+
+#define define_wchar_wrapper(name) \
+ int name ## _l (wint_t c, locale_t loc) { \
+ return name (c); \
+ }
+
+define_wchar_wrapper(iswspace)
+define_wchar_wrapper(iswprint)
+define_wchar_wrapper(iswcntrl)
+define_wchar_wrapper(iswupper)
+define_wchar_wrapper(iswlower)
+define_wchar_wrapper(iswalpha)
+define_wchar_wrapper(iswdigit)
+define_wchar_wrapper(iswpunct)
+define_wchar_wrapper(iswxdigit)
+define_wchar_wrapper(iswblank)
+
+wint_t towlower_l(wint_t c, locale_t loc) {
+ return towlower(c);
+}
+
+wint_t towupper_l(wint_t c, locale_t loc) {
+ return towupper(c);
+}
+
+///////////////////////////////////////////////////////////////////////
+// locale.h declarations
+
+#define LC_NULL_LOCALE ((locale_t)0)
+
+locale_t newlocale(int category_mask, const char* locale, locale_t base) {
+ if (base != LC_NULL_LOCALE)
+ return base;
+
+ locale_t loc = calloc(1, sizeof(*loc));
+ return loc;
+}
+
+locale_t duplocale(locale_t loc) {
+ if (loc == LC_GLOBAL_LOCALE)
+ return loc;
+ if (loc == LC_NULL_LOCALE) {
+ errno = EINVAL;
+ return LC_NULL_LOCALE;
+ }
+ locale_t copy = calloc(1, sizeof(*loc));
+ copy[0] = loc[0];
+ return copy;
+}
+
+
+// Static mutable variable because setlocale() is supposed to return
+// a pointer to a writable C string.
+static char g_C_LOCALE_SETTING[] = "C";
+
+char *setlocale(int category, const char *locale) {
+ // Sanity check.
+ if (!locale) {
+ errno = EINVAL;
+ return NULL;
+ }
+ // Only accept "", "C" or "POSIX", all equivalent on Android.
+ if (strcmp(locale, "") && strcmp(locale, "C") && strcmp(locale, "POSIX")) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return g_C_LOCALE_SETTING;
+}
+
+locale_t uselocale(locale_t loc) {
+ // If 'loc' is LC_GLOBAL_LOCALE, should return the global locale set
+ // through setlocale(). Since the implementation above doesn't modify
+ // anything, just return LC_GLOBAL_LOCALE too.
+
+ // If 'loc' is (locale_t)0, should return either LC_GLOBAL_LOCALE or
+ // or the global locale if setlocale() has been called at least once.
+
+ // Should return the previous value from a previous call, of
+ // LC_GLOBAL_LOCALE.
+
+ // So, in all cases, return LC_GLOBAL_LOCALE
+ return LC_GLOBAL_LOCALE;
+}
+
+void freelocale(locale_t loc) {
+ if (loc != LC_NULL_LOCALE && loc != LC_GLOBAL_LOCALE)
+ free(loc);
+}
+
+static struct lconv g_C_LCONV[1] = { {
+ .decimal_point = ".",
+ .thousands_sep = "",
+ .grouping = "",
+ .int_curr_symbol = "",
+ .currency_symbol = "",
+ .mon_decimal_point = "",
+ .mon_thousands_sep = "",
+ .mon_grouping = "",
+ .positive_sign = "",
+ .negative_sign = "",
+ .int_frac_digits = CHAR_MAX,
+ .frac_digits = CHAR_MAX,
+ .p_cs_precedes = CHAR_MAX,
+ .p_sep_by_space = CHAR_MAX,
+ .n_cs_precedes = CHAR_MAX,
+ .n_sep_by_space = CHAR_MAX,
+ .p_sign_posn = CHAR_MAX,
+ .n_sign_posn = CHAR_MAX,
+ .int_p_cs_precedes = CHAR_MAX,
+ .int_p_sep_by_space = CHAR_MAX,
+ .int_n_cs_precedes = CHAR_MAX,
+ .int_n_sep_by_space = CHAR_MAX,
+ .int_p_sign_posn = CHAR_MAX,
+ .int_n_sign_posn = CHAR_MAX,
+} };
+
+struct lconv* localeconv(void) {
+ return g_C_LCONV;
+}