Add support files required for building on Solaris.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@151721 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/support/solaris/floatingpoint.h b/include/support/solaris/floatingpoint.h
new file mode 100644
index 0000000..21b0349
--- /dev/null
+++ b/include/support/solaris/floatingpoint.h
@@ -0,0 +1,5 @@
+#define atof sun_atof
+#define strtod sun_strtod
+#include_next "floatingpoint.h"
+#undef atof
+#undef strtod
diff --git a/include/support/solaris/wchar.h b/include/support/solaris/wchar.h
new file mode 100644
index 0000000..0af4ea8
--- /dev/null
+++ b/include/support/solaris/wchar.h
@@ -0,0 +1,37 @@
+#define iswalpha sun_iswalpha
+#define iswupper sun_iswupper
+#define iswlower sun_iswlower
+#define iswdigit sun_iswdigit
+#define iswxdigit sun_iswxdigit
+#define iswalnum sun_iswalnum
+#define iswspace sun_iswspace
+#define iswpunct sun_iswpunct
+#define iswprint sun_iswprint
+#define iswgraph sun_iswgraph
+#define iswcntrl sun_iswcntrl
+#define iswctype sun_iswctype
+#define towlower sun_towlower
+#define towupper sun_towupper
+#define wcswcs sun_wcswcs
+#define wcswidth sun_wcswidth
+#define wcwidth sun_wcwidth
+#define wctype sun_wctype
+#include_next "wchar.h"
+#undef iswalpha
+#undef iswupper
+#undef iswlower
+#undef iswdigit
+#undef iswxdigit
+#undef iswalnum
+#undef iswspace
+#undef iswpunct
+#undef iswprint
+#undef iswgraph
+#undef iswcntrl
+#undef iswctype
+#undef towlower
+#undef towupper
+#undef wcswcs
+#undef wcswidth
+#undef wcwidth
+#undef wctype
diff --git a/include/support/solaris/xlocale.h b/include/support/solaris/xlocale.h
new file mode 100644
index 0000000..359508d
--- /dev/null
+++ b/include/support/solaris/xlocale.h
@@ -0,0 +1,146 @@
+////////////////////////////////////////////////////////////////////////////////
+// Minimal xlocale implementation for Solaris. This implements the subset of
+// the xlocale APIs that libc++ depends on.
+////////////////////////////////////////////////////////////////////////////////
+#ifndef __XLOCALE_H_INCLUDED
+#define __XLOCALE_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _LC_locale_t* locale_t;
+
+#define LC_COLLATE_MASK (1<<0)
+#define LC_CTYPE_MASK (1<<1)
+#define LC_MESSAGES_MASK (1<<2)
+#define LC_MONETARY_MASK (1<<3)
+#define LC_NUMERIC_MASK (1<<4)
+#define LC_TIME_MASK (1<<5)
+#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | \
+ LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+
+#define LC_GLOBAL_LOCALE ((locale_t)-1)
+
+size_t __mb_cur_max(locale_t l);
+#define MB_CUR_MAX_L(l) __mb_cur_max(l)
+
+locale_t newlocale(int mask, const char * locale, locale_t base);
+void freelocale(locale_t loc);
+
+wint_t btowc_l(int __c, locale_t __l);
+
+int wctob_l(wint_t __c, locale_t __l);
+
+size_t wcrtomb_l(char *__s, wchar_t __wc, mbstate_t *__ps, locale_t __l);
+
+size_t mbrtowc_l(wchar_t *__pwc, const char *__s, size_t __n,
+ mbstate_t *__ps, locale_t __l);
+
+int mbtowc_l(wchar_t *__pwc, const char *__pmb, size_t __max, locale_t __l);
+
+size_t mbrlen_l(const char *__s, size_t __n, mbstate_t *__ps, locale_t __l);
+
+struct lconv *localeconv_l(locale_t __l);
+
+size_t mbsrtowcs_l(wchar_t *__dest, const char **__src, size_t __len,
+ mbstate_t *__ps, locale_t __l);
+
+int sprintf_l(char *__s, locale_t __l, const char *__format, ...);
+
+int snprintf_l(char *__s, size_t __n, locale_t __l, const char *__format, ...);
+
+int asprintf_l(char **__s, locale_t __l, const char *__format, ...);
+
+int sscanf_l(const char *__s, locale_t __l, const char *__format, ...);
+
+int isalnum_l(int,locale_t);
+int isalpha_l(int,locale_t);
+int isblank_l(int,locale_t);
+int iscntrl_l(int,locale_t);
+int isdigit_l(int,locale_t);
+int isgraph_l(int,locale_t);
+int islower_l(int,locale_t);
+int isprint_l(int,locale_t);
+int ispunct_l(int,locale_t);
+int isspace_l(int,locale_t);
+int isupper_l(int,locale_t);
+int isxdigit_l(int,locale_t);
+
+int iswalnum_l(wchar_t,locale_t);
+int iswalpha_l(wchar_t,locale_t);
+int iswblank_l(wchar_t,locale_t);
+int iswcntrl_l(wchar_t,locale_t);
+int iswdigit_l(wchar_t,locale_t);
+int iswgraph_l(wchar_t,locale_t);
+int iswlower_l(wchar_t,locale_t);
+int iswprint_l(wchar_t,locale_t);
+int iswpunct_l(wchar_t,locale_t);
+int iswspace_l(wchar_t,locale_t);
+int iswupper_l(wchar_t,locale_t);
+int iswxdigit_l(wchar_t,locale_t);
+
+int iswctype_l(wint_t, wctype_t, locale_t);
+
+int toupper_l(int __c, locale_t __l);
+int tolower_l(int __c, locale_t __l);
+wint_t towupper_l(wint_t __c, locale_t __l);
+wint_t towlower_l(wint_t __c, locale_t __l);
+
+
+int strcoll_l(const char *__s1, const char *__s2, locale_t __l);
+int wcscoll_l(const wchar_t *__s1, const wchar_t *__s2, locale_t __l);
+size_t strftime_l(char *__s, size_t __size, const char *__fmt, const struct tm
+ *__tm, locale_t __l);
+
+size_t strxfrm_l(char *__s1, const char *__s2, size_t __n, locale_t __l);
+
+size_t wcsxfrm_l(wchar_t *__ws1, const wchar_t *__ws2, size_t __n,
+ locale_t __l);
+
+
+
+size_t
+mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps, locale_t loc);
+
+
+size_t
+wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps, locale_t loc);
+
+locale_t __cloc(void);
+
+// FIXME: These are quick-and-dirty hacks to make things pretend to work
+static inline
+long long strtoll_l(const char *__nptr, char **__endptr,
+ int __base, locale_t __loc) {
+ return strtoll(__nptr, __endptr, __base);
+}
+static inline
+long strtol_l(const char *__nptr, char **__endptr,
+ int __base, locale_t __loc) {
+ return strtol(__nptr, __endptr, __base);
+}
+static inline
+long double strtold_l(const char *__nptr, char **__endptr,
+ locale_t __loc) {
+ return strtold(__nptr, __endptr);
+}
+static inline
+unsigned long long strtoull_l(const char *__nptr, char **__endptr,
+ int __base, locale_t __loc) {
+ return strtoull(__nptr, __endptr, __base);
+}
+static inline
+unsigned long strtoul_l(const char *__nptr, char **__endptr,
+ int __base, locale_t __loc) {
+ return strtoul(__nptr, __endptr, __base);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/support/solaris/README b/src/support/solaris/README
new file mode 100644
index 0000000..89c887a
--- /dev/null
+++ b/src/support/solaris/README
@@ -0,0 +1,4 @@
+This directory contains a partial implementation of the xlocale APIs for
+Solaris. Some portions are lifted from FreeBSD libc, and so are covered by a
+2-clause BSD license instead of the MIT/UUIC license that the rest of libc++ is
+distributed under.
diff --git a/src/support/solaris/mbsnrtowcs.inc b/src/support/solaris/mbsnrtowcs.inc
new file mode 100644
index 0000000..0740452
--- /dev/null
+++ b/src/support/solaris/mbsnrtowcs.inc
@@ -0,0 +1,76 @@
+
+
+/*-
+ * As noted in the source, some portions of this implementation are copied from
+ * FreeBSD libc. These are covered by the following copyright:
+ *
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ *
+ * 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.
+ */
+
+size_t
+mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps, locale_t loc)
+{
+ const char *s;
+ size_t nchr;
+ wchar_t wc;
+ size_t nb;
+ FIX_LOCALE(loc);
+
+ s = *src;
+ nchr = 0;
+
+ if (dst == NULL) {
+ for (;;) {
+ if ((nb = mbrtowc_l(&wc, s, nms, ps, loc)) == (size_t)-1)
+ /* Invalid sequence - mbrtowc() sets errno. */
+ return ((size_t)-1);
+ else if (nb == 0 || nb == (size_t)-2)
+ return (nchr);
+ s += nb;
+ nms -= nb;
+ nchr++;
+ }
+ /*NOTREACHED*/
+ }
+
+ while (len-- > 0) {
+ if ((nb = mbrtowc_l(dst, s, nms, ps, loc)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ } else if (nb == (size_t)-2) {
+ *src = s + nms;
+ return (nchr);
+ } else if (nb == 0) {
+ *src = NULL;
+ return (nchr);
+ }
+ s += nb;
+ nms -= nb;
+ nchr++;
+ dst++;
+ }
+ *src = s;
+ return (nchr);
+}
diff --git a/src/support/solaris/wcsnrtombs.inc b/src/support/solaris/wcsnrtombs.inc
new file mode 100644
index 0000000..67e7078
--- /dev/null
+++ b/src/support/solaris/wcsnrtombs.inc
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ *
+ * 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.
+ */
+
+
+size_t
+wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps, locale_t loc)
+{
+ FIX_LOCALE(loc);
+ mbstate_t mbsbak;
+ char buf[MB_CUR_MAX_L(loc)];
+ const wchar_t *s;
+ size_t nbytes;
+ size_t nb;
+
+ s = *src;
+ nbytes = 0;
+
+ if (dst == NULL) {
+ while (nwc-- > 0) {
+ if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1)
+ /* Invalid character - wcrtomb() sets errno. */
+ return ((size_t)-1);
+ else if (*s == L'\0')
+ return (nbytes + nb - 1);
+ s++;
+ nbytes += nb;
+ }
+ return (nbytes);
+ }
+
+ while (len > 0 && nwc-- > 0) {
+ if (len > (size_t)MB_CUR_MAX_L(loc)) {
+ /* Enough space to translate in-place. */
+ if ((nb = wcrtomb_l(dst, *s, ps, loc)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ } else {
+ /*
+ * May not be enough space; use temp. buffer.
+ *
+ * We need to save a copy of the conversion state
+ * here so we can restore it if the multibyte
+ * character is too long for the buffer.
+ */
+ mbsbak = *ps;
+ if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ if (nb > (int)len) {
+ /* MB sequence for character won't fit. */
+ *ps = mbsbak;
+ break;
+ }
+ memcpy(dst, buf, nb);
+ }
+ if (*s == L'\0') {
+ *src = NULL;
+ return (nbytes + nb - 1);
+ }
+ s++;
+ dst += nb;
+ len -= nb;
+ nbytes += nb;
+ }
+ *src = s;
+ return (nbytes);
+}
+
diff --git a/src/support/solaris/xlocale.c b/src/support/solaris/xlocale.c
new file mode 100644
index 0000000..a2c1fa9
--- /dev/null
+++ b/src/support/solaris/xlocale.c
@@ -0,0 +1,245 @@
+
+#ifdef __sun__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <locale.h>
+#include <limits.h>
+#include <assert.h>
+#include <sys/localedef.h>
+#include "xlocale.h"
+
+static _LC_locale_t *__C_locale;
+
+#define FIX_LOCALE(l) l = (l == 0) ? __C_locale : l
+
+#include "mbsnrtowcs.inc"
+#include "wcsnrtombs.inc"
+
+size_t __mb_cur_max(locale_t __l) {
+ FIX_LOCALE(__l);
+ return (__l->lc_ctype->cmapp->cm_mb_cur_max);
+}
+
+wint_t btowc_l(int __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->btowc(__l->lc_ctype->cmapp, __c);
+}
+
+int wctob_l(wint_t __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->wctob(__l->lc_ctype->cmapp, __c);
+}
+
+size_t wcrtomb_l(char *__s, wchar_t __wc, mbstate_t *__ps, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->wcrtomb(__l->lc_ctype->cmapp,
+ __s, __wc, __ps);
+}
+
+size_t mbrtowc_l(wchar_t *__pwc, const char *__s, size_t __n,
+ mbstate_t *__ps, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->mbrtowc(__l->lc_ctype->cmapp,
+ __pwc, __s, __n, __ps);
+}
+
+int mbtowc_l(wchar_t *__pwc, const char *__pmb, size_t __max, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->mbtowc(__l->lc_ctype->cmapp,
+ __pwc, __pmb, __max);
+}
+
+size_t mbrlen_l(const char *__s, size_t __n, mbstate_t *__ps, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->mbrlen(__l->lc_ctype->cmapp, __s,
+ __n, __ps);
+}
+
+struct lconv *localeconv_l(locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->core.user_api->localeconv(__l);
+}
+
+size_t mbsrtowcs_l(wchar_t *__dest, const char **__src, size_t __len,
+ mbstate_t *__ps, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->cmapp->core.user_api->mbsrtowcs(__l->lc_ctype->cmapp,
+ __dest, __src, __len, __ps);
+}
+
+int wcscoll_l(const wchar_t *__s1, const wchar_t *__s2, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_collate->core.user_api->wcscoll(__l->lc_collate,
+ __s1, __s2);
+}
+
+int strcoll_l(const char *__s1, const char *__s2, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_collate->core.user_api->strcoll(__l->lc_collate,
+ __s1, __s2);
+}
+
+size_t strxfrm_l(char *__s1, const char *__s2, size_t __n, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_collate->core.user_api->strxfrm(__l->lc_collate,
+ __s1, __s2, __n);
+}
+size_t strftime_l(char *__s, size_t __size, const char *__fmt, const struct tm
+ *__tm, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_time->core.user_api->strftime(__l->lc_time,
+ __s, __size, __fmt, __tm);
+}
+
+size_t wcsxfrm_l(wchar_t *__ws1, const wchar_t *__ws2, size_t __n,
+ locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_collate->core.user_api->wcsxfrm(__l->lc_collate,
+ __ws1, __ws2, __n);
+}
+
+#define LOCALE_ISCTYPE(ctype, m) \
+ int is##ctype##_l(int __c, locale_t __l) { \
+ if ((__c < 0) || (__c > 255)) return 0;\
+ FIX_LOCALE(__l);\
+ return __l->lc_ctype->mask[__c] & m;\
+ }\
+ int isw##ctype##_l(wchar_t __c, locale_t __l) { \
+ FIX_LOCALE(__l);\
+ return __l->lc_ctype->core.user_api->iswctype(__l->lc_ctype, __c, m);\
+ }
+
+LOCALE_ISCTYPE(alnum, _ISALNUM)
+LOCALE_ISCTYPE(alpha, _ISALPHA)
+LOCALE_ISCTYPE(blank, _ISALPHA)
+LOCALE_ISCTYPE(cntrl, _ISCNTRL)
+LOCALE_ISCTYPE(digit, _ISDIGIT)
+LOCALE_ISCTYPE(graph, _ISGRAPH)
+LOCALE_ISCTYPE(lower, _ISLOWER)
+LOCALE_ISCTYPE(print, _ISPRINT)
+LOCALE_ISCTYPE(punct, _ISPUNCT)
+LOCALE_ISCTYPE(space, _ISSPACE)
+LOCALE_ISCTYPE(upper, _ISUPPER)
+LOCALE_ISCTYPE(xdigit, _ISXDIGIT)
+
+int iswctype_l(wint_t __c, wctype_t __m, locale_t __l) {
+ FIX_LOCALE(__l);\
+ return __l->lc_ctype->core.user_api->iswctype(__l->lc_ctype, __c, __m);\
+}
+
+int toupper_l(int __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ if ((__c < 0) || (__c > __l->lc_ctype->max_upper)) return __c;
+ return __l->lc_ctype->upper[__c];
+}
+int tolower_l(int __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ if ((__c < 0) || (__c > __l->lc_ctype->max_lower)) return __c;
+ return __l->lc_ctype->lower[__c];
+}
+wint_t towupper_l(wint_t __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->core.user_api->towupper(__l->lc_ctype, __c);
+}
+wint_t towlower_l(wint_t __c, locale_t __l) {
+ FIX_LOCALE(__l);
+ return __l->lc_ctype->core.user_api->towlower(__l->lc_ctype, __c);
+}
+
+// FIXME: This disregards the locale, which is Very Wrong
+#define vsnprintf_l(__s, __n, __l, __format, __va) \
+ vsnprintf(__s, __n, __format, __va)
+
+int sprintf_l(char *__s, locale_t __l, const char *__format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ int __res = vsnprintf_l(__s, SIZE_MAX, __l, __format, __va);
+ va_end(__va);
+ return __res;
+}
+
+int snprintf_l(char *__s, size_t __n, locale_t __l, const char *__format, ...)
+{
+ va_list __va;
+ va_start(__va, __format);
+ int __res = vsnprintf_l(__s, __n , __l, __format, __va);
+ va_end(__va);
+ return __res;
+}
+
+int asprintf_l(char **__s, locale_t __l, const char *__format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ // FIXME:
+ int __res = vasprintf(__s, __format, __va);
+ va_end(__va);
+ return __res;
+}
+
+int sscanf_l(const char *__s, locale_t __l, const char *__format, ...) {
+ va_list __va;
+ va_start(__va, __format);
+ // FIXME:
+ int __res = vsscanf(__s, __format, __va);
+ va_end(__va);
+ return __res;
+}
+
+locale_t newlocale(int mask, const char *locale, locale_t base) {
+
+ if ((locale == NULL) || (locale[0] == '\0') ||
+ ((locale[0] == 'C') && (locale[1] == '\0')))
+ {
+ return __C_locale;
+ }
+
+ // Solaris locales are shared libraries that contain
+ char *path;
+#ifdef __LP64
+ asprintf(&path, "/usr/lib/locale/%1$s/amd64/%1$s.so.3", locale);
+#else
+ asprintf(&path, "/usr/lib/locale/%1$s/%1$s.so.3", locale);
+#endif
+ void *handle = dlopen(path, RTLD_LOCAL | RTLD_NOW);
+ free(path);
+ if (!handle)
+ return 0;
+ _LC_locale_t *(*init)() = dlsym(handle, "instantiate");
+ if (!init)
+ return 0;
+ _LC_locale_t *p = init();
+ if (!p)
+ return 0;
+
+ if (!base)
+ base = __C_locale;
+
+ locale_t ret = calloc(1, sizeof(struct _LC_locale_t));
+ memcpy(ret, p, sizeof (_LC_locale_t));
+ ret->lc_collate = (mask & LC_COLLATE_MASK) ? p->lc_collate : base->lc_collate;
+ ret->lc_ctype = (mask & LC_CTYPE_MASK) ? p->lc_ctype : base->lc_ctype;
+ ret->lc_messages = (mask & LC_MESSAGES_MASK) ? p->lc_messages : base->lc_messages;
+ ret->lc_monetary = (mask & LC_MONETARY_MASK) ? p->lc_monetary : base->lc_monetary;
+ ret->lc_time = (mask & LC_TIME_MASK) ? p->lc_time : base->lc_time;
+ return ret;
+}
+
+void freelocale(locale_t loc)
+{
+ if (loc != __C_locale)
+ free(loc);
+}
+
+__attribute__((constructor))
+static void setupCLocale(void) {
+ // The default initial locale is the C locale. This is a statically
+ // allocated locale inside libc. At program start, __lc_locale will point to
+ // this. We need to grab a copy because it's not a public symbol. If we had
+ // access to the source code for libc, then we'd just use it directly...
+ assert('C' == setlocale(LC_ALL, 0)[0]);
+ __C_locale = __lc_locale;
+}
+#endif