Date: Wed, 21 Sep 2011 20:28:54 +0100 From: David Chisnall <theraven@theravensnest.org> To: hackers@freebsd.org Subject: Re: xlocale patch Message-ID: <C57AA994-0CB1-4875-8DB4-7D728B3E62AB@theravensnest.org> In-Reply-To: <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org> References: <DCAF3E3D-B2E1-40EF-B654-23625A17C3F1@theravensnest.org> <20110919172214.GJ33993@hoeg.nl> <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
And here's an updated version of the patch. I've fixed some other bugs, including where wcstod() and wcstodl() in trunk return the wrong value for any input string starting with spaces, wchar.h's violation of POSIX by not declaring FILE, and a few C++ incompatibilities in other headers (e.g. putchar being a macro, which breaks things like std::putchar(foo)). All of my libcxxrt and libc++ changes have now been pushed upstream, so this should now be repeatable.
The libunwind port still has an irritating bug in the header, where the extern "C" {} block ends with a semicolon, which causes it to be rejected in any C++ program, but with that fixed you can compile libcxxrt (I used cmake .. -DCMAKE_CXX_FLAGS="-I/usr/local/include -nostdlib -g" - hopefully I'll work out how to make CMake add these flags automatically soon...). Libc++ should build out of the box with cmake.
The results are now:
****************************************************
Results for /root/libcxx/test:
using clang version 3.0 (trunk 140248)
Target: x86_64-unknown-freebsd9.0
Thread model: posix
with -std=c++0x -stdlib=libc++ -pthread -I/root/libcxx/include -L/root/libcxx/build/lib
----------------------------------------------------
sections without tests : 1
sections with failures : 16
sections without failures: 1047
+ ----
total number of sections : 1064
----------------------------------------------------
number of tests failed : 53
number of tests passed : 4271
+ ----
total number of tests : 4324
****************************************************
For comparison, the results on OS X are:
****************************************************
Results for /test:
using Apple clang version 3.0 (tags/Apple/clang-211.10.1) (based on LLVM 3.0svn)
Target: x86_64-apple-darwin11.1.0
Thread model: posix
with -std=c++0x -stdlib=libc++
----------------------------------------------------
sections without tests : 1
sections with failures : 17
sections without failures: 1046
+ ----
total number of sections : 1064
----------------------------------------------------
number of tests failed : 71
number of tests passed : 4253
+ ----
total number of tests : 4324
****************************************************
The remaining failures on FreeBSD are:
- 27 caused by clang not fully supporting the atomic operations yet
- 3 caused by clang not fully supporting the C++11 type-trait intrinsics
- 20 that I don't think are real failures - they're caused by the VM where I'm running the tests not having sufficiently fine-grained time reporting for the thread operation timeout tests to work properly
- 1 is caused by FreeBSD lacking the C1x quick_exit() APIs.
- 2 caused by FreeBSD lacking the uchar.h header
The first 30 of these should be fixed in clang soon. The next 20 are probably not real bugs at all. The remaining 3 are fairly minor.
David
[-- Attachment #2 --]
Index: include/wctype.h
===================================================================
--- include/wctype.h (revision 225653)
+++ include/wctype.h (working copy)
@@ -89,6 +89,7 @@
#endif
__END_DECLS
+#ifndef __cplusplus
#define iswalnum(wc) __istype((wc), _CTYPE_A|_CTYPE_D)
#define iswalpha(wc) __istype((wc), _CTYPE_A)
#define iswblank(wc) __istype((wc), _CTYPE_B)
@@ -113,6 +114,7 @@
#define iswphonogram(wc) __istype((wc), _CTYPE_Q)
#define iswrune(wc) __istype((wc), 0xFFFFFF00L)
#define iswspecial(wc) __istype((wc), _CTYPE_T)
-#endif
+#endif /* __BSD_VISIBLE */
+#endif /* __cplusplus */
#endif /* _WCTYPE_H_ */
Index: include/Makefile
===================================================================
--- include/Makefile (revision 225653)
+++ include/Makefile (working copy)
@@ -23,8 +23,9 @@
stdbool.h stddef.h stdio.h stdlib.h string.h stringlist.h \
strings.h sysexits.h tar.h termios.h tgmath.h \
time.h timeconv.h timers.h ttyent.h \
+ uchar.h\
ulimit.h unistd.h utime.h utmpx.h uuid.h varargs.h vis.h \
- wchar.h wctype.h wordexp.h
+ wchar.h wctype.h wordexp.h xlocale.h _xlocale_ctype.h
MHDRS= float.h floatingpoint.h stdarg.h
Index: include/xlocale.h
===================================================================
--- include/xlocale.h (revision 0)
+++ include/xlocale.h (revision 0)
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _XLOCALE_H_
+#define _XLOCALE_H_
+
+#include <locale.h>
+
+__BEGIN_DECLS
+
+/*
+ * Extended locale versions of the locale-aware functions from string.h.
+ *
+ * Include <string.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STRING_H_
+int strcoll_l(const char *, const char *, locale_t);
+size_t strxfrm_l(char *, const char *, size_t, locale_t);
+int strcasecmp_l(const char *, const char *, locale_t);
+char *strcasestr_l(const char *, const char *, locale_t);
+int strncasecmp_l(const char *, const char *, size_t, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from inttypes.h.
+ *
+ * Include <inttypes.h> before <xlocale.h> to expose these.
+ */
+#ifdef _INTTYPES_H_
+intmax_t
+strtoimax_l(const char * __restrict, char ** __restrict, int, locale_t);
+uintmax_t
+strtoumax_l(const char * __restrict, char ** __restrict, int, locale_t);
+intmax_t
+wcstoimax_l(const wchar_t * __restrict, wchar_t ** __restrict, int , locale_t);
+uintmax_t
+wcstoumax_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from monetary.h.
+ *
+ * Include <monetary.h> before <xlocale.h> to expose these.
+ */
+#ifdef _MONETARY_H_
+ssize_t strfmon_l(char *, size_t, locale_t, const char *, ...)
+# if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+ __attribute__((__format__ (__strfmon__, 4, 5)))
+# endif
+ ;
+#endif
+
+/*
+ * Extended locale versions of the locale-aware functions from stdlib.h.
+ *
+ * Include <stdlib.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STDLIB_H_
+double atof_l(const char *, locale_t);
+int atoi_l(const char *, locale_t);
+long atol_l(const char *, locale_t);
+long long atoll_l(const char *, locale_t);
+int mblen_l(const char *, size_t, locale_t);
+size_t
+mbstowcs_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+int
+mbtowc_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+double strtod_l(const char *, char **, locale_t);
+float strtof_l(const char *, char **, locale_t);
+long strtol_l(const char *, char **, int, locale_t);
+long double strtold_l(const char *, char **, locale_t);
+long long strtoll_l(const char *, char **, int, locale_t);
+unsigned long strtoul_l(const char *, char **, int, locale_t);
+unsigned long long strtoull_l(const char *, char **, int, locale_t);
+size_t
+wcstombs_l(char * __restrict, const wchar_t * __restrict, size_t, locale_t);
+int wctomb_l(char *, wchar_t, locale_t);
+
+int ___mb_cur_max_l(locale_t);
+#define MB_CUR_MAX_L(x) (___mb_cur_max_l(x))
+
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from time.h.
+ *
+ * Include <time.h> before <xlocale.h> to expose these.
+ */
+#ifdef _TIME_H_
+size_t
+strftime_l(char * __restrict, size_t, const char * __restrict, const
+ struct tm * __restrict, locale_t)
+# if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+ __attribute__((__format__ (__strftime__, 3, 0)))
+# endif
+ ;
+char *
+strptime_l(const char * __restrict, const char * __restrict,
+ struct tm * __restrict, locale_t);
+#endif
+#ifdef _LANGINFO_H_
+char *nl_langinfo_l(nl_item, locale_t);
+#endif
+#ifdef _CTYPE_H_
+#include <_xlocale_ctype.h>
+#endif
+#ifdef _WCTYPE_H_
+#define XLOCALE_WCTYPES 1
+#include <_xlocale_ctype.h>
+#endif
+
+#ifdef _STDIO_H_
+int fprintf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+ __printflike(3, 4);
+int fscanf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+ __scanflike(3, 4);
+int printf_l(locale_t, const char * __restrict, ...) __printflike(2, 3);
+int scanf_l(locale_t, const char * __restrict, ...) __scanflike(2, 3);
+int sprintf_l(char * __restrict, locale_t, const char * __restrict, ...)
+ __printflike(3, 4);
+int sscanf_l(const char * __restrict, locale_t, const char * __restrict, ...)
+ __scanflike(3, 4);
+int vfprintf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+ __printflike(3, 0);
+int vprintf_l(locale_t, const char * __restrict, __va_list) __printflike(2, 0);
+int vsprintf_l(char * __restrict, locale_t, const char * __restrict, __va_list)
+ __printflike(3, 0);
+
+int snprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+ ...) __printflike(4, 5);
+int vfscanf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+ __scanflike(3, 0);
+int vscanf_l(locale_t, const char * __restrict, __va_list) __scanflike(2, 0);
+int vsnprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+ va_list) __printflike(4, 0);
+int vsscanf_l(const char * __restrict, locale_t, const char * __restrict,
+ va_list) __scanflike(3, 0);
+int dprintf_l(int, locale_t, const char * __restrict, ...) __printflike(3, 4);
+int vdprintf_l(int, locale_t, const char * __restrict, __va_list)
+ __printflike(3, 0);
+int asprintf_l(char **, locale_t, const char *, ...) __printflike(3, 4);
+int vasprintf_l(char **, locale_t, const char *, __va_list) __printflike(3, 0);
+#endif
+#ifdef _WCHAR_H_
+wint_t btowc_l(int, locale_t);
+wint_t fgetwc_l(struct __sFILE *, locale_t);
+wchar_t *
+fgetws_l(wchar_t * __restrict, int, struct __sFILE * __restrict, locale_t);
+wint_t fputwc_l(wchar_t, struct __sFILE *, locale_t);
+int
+fputws_l(const wchar_t * __restrict, struct __sFILE * __restrict, locale_t);
+int
+fwprintf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+ ...);
+int
+fwscanf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict, ...);
+wint_t getwc_l(struct __sFILE *, locale_t);
+wint_t getwchar_l(locale_t);
+size_t
+mbrlen_l(const char * __restrict, size_t, mbstate_t * __restrict, locale_t);
+size_t
+mbrtowc_l(wchar_t * __restrict, const char * __restrict, size_t,
+ mbstate_t * __restrict, locale_t);
+int mbsinit_l(const mbstate_t *, locale_t);
+size_t
+mbsrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t,
+ mbstate_t * __restrict, locale_t);
+wint_t putwc_l(wchar_t, struct __sFILE *, locale_t);
+wint_t putwchar_l(wchar_t, locale_t);
+int
+swprintf_l(wchar_t * __restrict, size_t n, locale_t,
+ const wchar_t * __restrict, ...);
+int
+swscanf_l(const wchar_t * __restrict, locale_t, const wchar_t * __restrict,
+ ...);
+wint_t ungetwc_l(wint_t, struct __sFILE *, locale_t);
+int
+vfwprintf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+ __va_list);
+int
+vswprintf_l(wchar_t * __restrict, size_t n, locale_t,
+ const wchar_t * __restrict, __va_list);
+int vwprintf_l(locale_t, const wchar_t * __restrict, __va_list);
+size_t
+wcrtomb_l(char * __restrict, wchar_t, mbstate_t * __restrict, locale_t);
+int wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
+size_t
+wcsftime_l(wchar_t * __restrict, size_t, const wchar_t * __restrict,
+ const struct tm * __restrict, locale_t);
+size_t
+wcsrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t,
+ mbstate_t * __restrict, locale_t);
+double wcstod_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long
+wcstol_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+unsigned long
+wcstoul_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+int wcswidth_l(const wchar_t *, size_t, locale_t);
+size_t
+wcsxfrm_l(wchar_t * __restrict, const wchar_t * __restrict, size_t, locale_t);
+int wctob_l(wint_t, locale_t);
+int wcwidth_l(wchar_t, locale_t);
+int wprintf_l(locale_t, const wchar_t * __restrict, ...);
+int wscanf_l(locale_t, const wchar_t * __restrict, ...);
+
+int
+vfwscanf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+ __va_list);
+int vswscanf_l(const wchar_t * __restrict, locale_t,
+const wchar_t * __restrict, __va_list);
+int vwscanf_l(locale_t, const wchar_t * __restrict, __va_list);
+float wcstof_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long double
+wcstold_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long long
+wcstoll_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+unsigned long long
+wcstoull_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+size_t
+mbsnrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict, locale_t);
+int wcscasecmp_l(const wchar_t *, const wchar_t *, locale_t);
+int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t n, locale_t);
+size_t
+wcsnrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict, locale_t);
+
+#endif
+
+struct lconv *
+localeconv_l(locale_t loc);
+__END_DECLS
+
+#endif
Index: include/locale.h
===================================================================
--- include/locale.h (revision 225653)
+++ include/locale.h (working copy)
@@ -79,4 +79,48 @@
char *setlocale(int, const char *);
__END_DECLS
+#if __POSIX_VISIBLE >= 200809
+
+#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)
+
+__BEGIN_DECLS
+
+typedef struct _xlocale *locale_t;
+/**
+ * Creates a new locale.
+ */
+locale_t newlocale(int mask, const char *locale, locale_t base);
+
+locale_t duplocale(locale_t base);
+/*
+ * Free a locale_t. This is quite a poorly named function. It actually
+ * disclaims a reference to a locale_t, rather than freeing it.
+ */
+int
+freelocale(locale_t loc);
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc);
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t uselocale(locale_t loc);
+
+__END_DECLS
+
+#endif /* __POSIX_VISIBLE >= 200809 */
+
+
#endif /* _LOCALE_H_ */
Index: include/iso646.h
===================================================================
--- include/iso646.h (revision 225653)
+++ include/iso646.h (working copy)
@@ -29,6 +29,7 @@
#ifndef _ISO646_H_
#define _ISO646_H_
+#ifndef __cplusplus
#define and &&
#define and_eq &=
#define bitand &
@@ -40,5 +41,6 @@
#define or_eq |=
#define xor ^
#define xor_eq ^=
+#endif
#endif /* !_ISO646_H_ */
Index: include/_xlocale_ctype.h
===================================================================
--- include/_xlocale_ctype.h (revision 0)
+++ include/_xlocale_ctype.h (revision 0)
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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.
+ */
+#ifndef _XLOCALE_H_
+#error This header should only be included by <xlocale.h>, never directly.
+#endif
+
+#ifndef _XLOCALE_CTYPE_H_
+__BEGIN_DECLS
+unsigned long ___runetype_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t ___tolower_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t ___toupper_l(__ct_rune_t, locale_t) __pure;
+_RuneLocale *__runes_for_locale(locale_t, int*);
+__END_DECLS
+#endif
+
+#ifndef _XLOCALE_INLINE
+# if __GNUC__ && !__GNUC_STDC_INLINE__
+# define _XLOCALE_INLINE extern inline
+# else
+# define _XLOCALE_INLINE inline
+# endif
+#endif
+
+#ifdef XLOCALE_WCTYPES
+static __inline int
+__maskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (_c < 0 || _c >= _CACHED_RUNES) ? ___runetype_l(_c, locale) :
+ runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__istype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+ return (!!__maskrune_l(_c, _f, locale));
+}
+
+# define XLOCALE_ISCTYPE(fname, cat) \
+ _XLOCALE_INLINE int isw##fname##_l(int c, locale_t l)\
+ { return __istype_l(c, cat, l); }
+#else
+static __inline int
+__sbmaskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (_c < 0 || _c >= mb_sb_limit) ? 0 :
+ runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__sbistype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+ return (!!__sbmaskrune_l(_c, _f, locale));
+}
+
+# define XLOCALE_ISCTYPE(fname, cat) \
+ _XLOCALE_INLINE int is##fname##_l(int c, locale_t l)\
+ { return __sbistype_l(c, cat, l); }
+#endif
+
+XLOCALE_ISCTYPE(alnum, _CTYPE_A|_CTYPE_D)
+XLOCALE_ISCTYPE(alpha, _CTYPE_A)
+XLOCALE_ISCTYPE(blank, _CTYPE_B)
+XLOCALE_ISCTYPE(cntrl, _CTYPE_C)
+XLOCALE_ISCTYPE(digit, _CTYPE_D)
+XLOCALE_ISCTYPE(graph, _CTYPE_G)
+XLOCALE_ISCTYPE(hexnumber, _CTYPE_X)
+XLOCALE_ISCTYPE(ideogram, _CTYPE_I)
+XLOCALE_ISCTYPE(lower, _CTYPE_L)
+XLOCALE_ISCTYPE(number, _CTYPE_D)
+XLOCALE_ISCTYPE(phonogram, _CTYPE_Q)
+XLOCALE_ISCTYPE(print, _CTYPE_R)
+XLOCALE_ISCTYPE(punct, _CTYPE_P)
+XLOCALE_ISCTYPE(rune, 0xFFFFFF00L)
+XLOCALE_ISCTYPE(space, _CTYPE_S)
+XLOCALE_ISCTYPE(special, _CTYPE_T)
+XLOCALE_ISCTYPE(upper, _CTYPE_U)
+XLOCALE_ISCTYPE(xdigit, _CTYPE_X)
+#undef XLOCALE_ISCTYPE
+
+#ifdef XLOCALE_WCTYPES
+_XLOCALE_INLINE int towlower_l(int c, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (c < 0 || c >= _CACHED_RUNES) ? ___tolower_l(c, locale) :
+ runes->__maplower[c];
+}
+_XLOCALE_INLINE int towupper_l(int c, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (c < 0 || c >= _CACHED_RUNES) ? ___toupper_l(c, locale) :
+ runes->__mapupper[c];
+}
+_XLOCALE_INLINE int
+__wcwidth_l(__ct_rune_t _c, locale_t locale)
+{
+ unsigned int _x;
+
+ if (_c == 0)
+ return (0);
+ _x = (unsigned int)__maskrune_l(_c, _CTYPE_SWM|_CTYPE_R, locale);
+ if ((_x & _CTYPE_SWM) != 0)
+ return ((_x & _CTYPE_SWM) >> _CTYPE_SWS);
+ return ((_x & _CTYPE_R) != 0 ? 1 : -1);
+}
+int iswctype_l(wint_t wc, wctype_t charclass, locale_t locale);
+wctype_t wctype_l(const char *property, locale_t locale);
+wint_t towctrans_l(wint_t wc, wctrans_t desc, locale_t locale);
+wint_t nextwctype_l(wint_t wc, wctype_t wct, locale_t locale);
+wctrans_t wctrans_l(const char *charclass, locale_t locale);
+#undef XLOCALE_WCTYPES
+#else
+_XLOCALE_INLINE int digittoint_l(int c, locale_t locale)
+{ return __sbmaskrune_l((c), 0xFF, locale); }
+
+_XLOCALE_INLINE int tolower_l(int c, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (c < 0 || c >= mb_sb_limit) ? c :
+ runes->__maplower[c];
+}
+_XLOCALE_INLINE int toupper_l(int c, locale_t locale)
+{
+ int mb_sb_limit;
+ _RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+ return (c < 0 || c >= mb_sb_limit) ? c :
+ runes->__mapupper[c];
+}
+#endif
Index: include/runetype.h
===================================================================
--- include/runetype.h (revision 225653)
+++ include/runetype.h (working copy)
@@ -83,8 +83,14 @@
} _RuneLocale;
#define _RUNE_MAGIC_1 "RuneMagi" /* Indicates version 0 of RuneLocale */
-
-extern _RuneLocale _DefaultRuneLocale;
+__BEGIN_DECLS
+extern const _RuneLocale _DefaultRuneLocale;
+__attribute__((deprecated))
extern _RuneLocale *_CurrentRuneLocale;
+/* TODO: This is called quite a lot, so we should use a __thread variable when
+ * it's available. */
+extern _RuneLocale *__getCurrentRuneLocale(void);
+#define _CurrentRuneLocale (__getCurrentRuneLocale())
+__END_DECLS
#endif /* !_RUNETYPE_H_ */
Index: include/stdlib.h
===================================================================
--- include/stdlib.h (revision 225653)
+++ include/stdlib.h (working copy)
@@ -71,10 +71,11 @@
#define RAND_MAX 0x7fffffff
+__BEGIN_DECLS
extern int __mb_cur_max;
-#define MB_CUR_MAX __mb_cur_max
+extern int ___mb_cur_max(void);
+#define MB_CUR_MAX (___mb_cur_max())
-__BEGIN_DECLS
void abort(void) __dead2;
int abs(int) __pure2;
int atexit(void (*)(void));
Index: include/stdio.h
===================================================================
--- include/stdio.h (revision 225653)
+++ include/stdio.h (working copy)
@@ -107,7 +107,7 @@
* inline functions. To preserve ABI compat, these members must not
* be disturbed. These members are marked below with (*).
*/
-typedef struct __sFILE {
+struct __sFILE {
unsigned char *_p; /* (*) current position in (some) buffer */
int _r; /* (*) read space left for getc() */
int _w; /* (*) write space left for putc() */
@@ -144,8 +144,11 @@
int _fl_count; /* recursive lock count */
int _orientation; /* orientation for fwide() */
__mbstate_t _mbstate; /* multibyte conversion state */
-} FILE;
-
+};
+#ifndef _STDFILE_DECLARED
+#define _STDFILE_DECLARED
+typedef struct __sFILE FILE;
+#endif
#ifndef _STDSTREAM_DECLARED
__BEGIN_DECLS
extern FILE *__stdinp;
@@ -454,7 +457,6 @@
else
return (__swbuf(_c, _p));
}
-#else
/*
* This has been tuned to generate reasonable code on the vax using pcc.
*/
@@ -467,6 +469,7 @@
__swbuf((int)(c), p) : \
(*(p)->_p = (c), (int)*(p)->_p++))
#endif
+#ifndef __cplusplus
#define __sfeof(p) (((p)->_flags & __SEOF) != 0)
#define __sferror(p) (((p)->_flags & __SERR) != 0)
@@ -506,6 +509,7 @@
#define getchar_unlocked() getc_unlocked(stdin)
#define putchar_unlocked(x) putc_unlocked(x, stdout)
#endif
+#endif /* __cplusplus */
__END_DECLS
#endif /* !_STDIO_H_ */
Index: include/wchar.h
===================================================================
--- include/wchar.h (revision 225653)
+++ include/wchar.h (working copy)
@@ -97,7 +97,10 @@
#define WEOF ((wint_t)-1)
#endif
-struct __sFILE;
+#ifndef _STDFILE_DECLARED
+#define _STDFILE_DECLARED
+typedef struct __sFILE FILE;
+#endif
struct tm;
__BEGIN_DECLS
Index: include/ctype.h
===================================================================
--- include/ctype.h (revision 225653)
+++ include/ctype.h (working copy)
@@ -80,6 +80,7 @@
#endif
__END_DECLS
+#ifndef __cplusplus
#define isalnum(c) __sbistype((c), _CTYPE_A|_CTYPE_D)
#define isalpha(c) __sbistype((c), _CTYPE_A)
#define iscntrl(c) __sbistype((c), _CTYPE_C)
@@ -93,6 +94,7 @@
#define isxdigit(c) __isctype((c), _CTYPE_X) /* ANSI -- locale independent */
#define tolower(c) __sbtolower(c)
#define toupper(c) __sbtoupper(c)
+#endif /* !__cplusplus */
#if __XSI_VISIBLE
/*
@@ -112,7 +114,7 @@
#define toascii(c) ((c) & 0x7F)
#endif
-#if __ISO_C_VISIBLE >= 1999
+#if __ISO_C_VISIBLE >= 1999 && (!defined(__cplusplus))
#define isblank(c) __sbistype((c), _CTYPE_B)
#endif
Index: contrib/gdtoa/gdtoaimp.h
===================================================================
--- contrib/gdtoa/gdtoaimp.h (revision 225653)
+++ contrib/gdtoa/gdtoaimp.h (working copy)
@@ -201,6 +201,7 @@
#include "namespace.h"
#include <pthread.h>
#include "un-namespace.h"
+#include "xlocale_private.h"
#ifdef KR_headers
#define Char char
@@ -526,10 +527,13 @@
#define strtoIx __strtoIx
#define strtoIxL __strtoIxL
#define strtord __strtord
+#define strtord_l __strtord_l
#define strtordd __strtordd
#define strtorf __strtorf
#define strtorQ __strtorQ
+#define strtorQ_l __strtorQ_l
#define strtorx __strtorx
+#define strtorx_l __strtorx_l
#define strtorxL __strtorxL
#define strtodI __strtodI
#define strtopd __strtopd
@@ -635,6 +639,7 @@
extern Bigint *set_ones ANSI((Bigint*, int));
extern char *strcp ANSI((char*, const char*));
extern int strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+ extern int strtodg_l ANSI((CONST char*, char**, FPI*, Long*, ULong*, locale_t));
extern int strtoId ANSI((CONST char *, char **, double *, double *));
extern int strtoIdd ANSI((CONST char *, char **, double *, double *));
@@ -644,6 +649,7 @@
extern int strtoIx ANSI((CONST char *, char **, void *, void *));
extern int strtoIxL ANSI((CONST char *, char **, void *, void *));
extern double strtod ANSI((const char *s00, char **se));
+ extern double strtod_l ANSI((const char *s00, char **se, locale_t));
extern int strtopQ ANSI((CONST char *, char **, Void *));
extern int strtopf ANSI((CONST char *, char **, float *));
extern int strtopd ANSI((CONST char *, char **, double *));
@@ -651,10 +657,13 @@
extern int strtopx ANSI((CONST char *, char **, Void *));
extern int strtopxL ANSI((CONST char *, char **, Void *));
extern int strtord ANSI((CONST char *, char **, int, double *));
+ extern int strtord_l ANSI((CONST char *, char **, int, double *, locale_t));
extern int strtordd ANSI((CONST char *, char **, int, double *));
extern int strtorf ANSI((CONST char *, char **, int, float *));
extern int strtorQ ANSI((CONST char *, char **, int, void *));
+ extern int strtorQ_l ANSI((CONST char *, char **, int, void *, locale_t));
extern int strtorx ANSI((CONST char *, char **, int, void *));
+ extern int strtorx_l ANSI((CONST char *, char **, int, void *, locale_t));
extern int strtorxL ANSI((CONST char *, char **, int, void *));
extern Bigint *sum ANSI((Bigint*, Bigint*));
extern int trailz ANSI((Bigint*));
Index: contrib/gdtoa/strtopQ.c
===================================================================
--- contrib/gdtoa/strtopQ.c (revision 225653)
+++ contrib/gdtoa/strtopQ.c (working copy)
@@ -56,7 +56,7 @@
strtopQ(CONST char *s, char **sp, void *V)
#endif
{
- static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI };
+ static const FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI };
ULong bits[4];
Long exp;
int k;
Index: contrib/gdtoa/strtorQ.c
===================================================================
--- contrib/gdtoa/strtorQ.c (revision 225653)
+++ contrib/gdtoa/strtorQ.c (working copy)
@@ -103,9 +103,10 @@
int
#ifdef KR_headers
-strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorQ_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
#else
-strtorQ(CONST char *s, char **sp, int rounding, void *L)
+strtorQ_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
#endif
{
static FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI };
@@ -120,7 +121,17 @@
fpi1.rounding = rounding;
fpi = &fpi1;
}
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, locale);
ULtoQ((ULong*)L, bits, exp, k);
return k;
}
+
+ int
+#ifdef KR_headers
+strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+#else
+strtorQ(CONST char *s, char **sp, int rounding, void *L)
+#endif
+{
+ return strtorQ_l(s, sp, rounding, L, __get_locale());
+}
Index: contrib/gdtoa/strtodg.c
===================================================================
--- contrib/gdtoa/strtodg.c (revision 225653)
+++ contrib/gdtoa/strtodg.c (working copy)
@@ -34,6 +34,7 @@
#ifdef USE_LOCALE
#include "locale.h"
#endif
+#include "xlocale_private.h"
static CONST int
fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21,
@@ -313,12 +314,12 @@
}
int
-strtodg
+strtodg_l
#ifdef KR_headers
- (s00, se, fpi, exp, bits)
- CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits;
+ (s00, se, fpi, exp, bits, l)
+ CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; locale_t l;
#else
- (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits)
+ (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits, locale_t l)
#endif
{
int abe, abits, asub;
@@ -334,14 +335,14 @@
Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
#ifdef USE_LOCALE /*{{*/
#ifdef NO_LOCALE_CACHE
- char *decimalpoint = localeconv()->decimal_point;
+ char *decimalpoint = localeconv_l(l)->decimal_point;
int dplen = strlen(decimalpoint);
#else
char *decimalpoint;
static char *decimalpoint_cache;
static int dplen;
if (!(s0 = decimalpoint_cache)) {
- s0 = localeconv()->decimal_point;
+ s0 = localeconv_l(l)->decimal_point;
if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
strcpy(decimalpoint_cache, s0);
s0 = decimalpoint_cache;
@@ -1063,3 +1064,15 @@
}
return irv;
}
+
+ int
+strtodg
+#ifdef KR_headers
+ (s00, se, fpi, exp, bits)
+ CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits;
+#else
+ (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits)
+#endif
+{
+ return strtodg_l(s00, se, fpi, exp, bits, __get_locale());
+}
Index: contrib/gdtoa/strtord.c
===================================================================
--- contrib/gdtoa/strtord.c (revision 225653)
+++ contrib/gdtoa/strtord.c (working copy)
@@ -70,9 +70,10 @@
int
#ifdef KR_headers
-strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d;
+strtord_l(s, sp, rounding, d, locale) CONST char *s; char **sp; int rounding;
+double *d; locale_t locale;
#else
-strtord(CONST char *s, char **sp, int rounding, double *d)
+strtord_l(CONST char *s, char **sp, int rounding, double *d, locale_t locale)
#endif
{
static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
@@ -87,7 +88,17 @@
fpi1.rounding = rounding;
fpi = &fpi1;
}
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, locale);
ULtod((ULong*)d, bits, exp, k);
return k;
}
+ int
+#ifdef KR_headers
+strtord(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L;
+#else
+strtord(CONST char *s, char **sp, int rounding, double *d)
+#endif
+{
+ return strtord_l(s, sp, rounding, d, __get_locale());
+}
Index: contrib/gdtoa/strtod.c
===================================================================
--- contrib/gdtoa/strtod.c (revision 225653)
+++ contrib/gdtoa/strtod.c (working copy)
@@ -39,6 +39,7 @@
#ifdef USE_LOCALE
#include "locale.h"
#endif
+#include "xlocale_private.h"
#ifdef IEEE_Arith
#ifndef NO_IEEE_Scale
@@ -82,11 +83,11 @@
#endif /*}*/
double
-strtod
+strtod_l
#ifdef KR_headers
- (s00, se) CONST char *s00; char **se;
+ (s00, se, l) CONST char *s00; char **se; locale_t l
#else
- (CONST char *s00, char **se)
+ (CONST char *s00, char **se, locale_t l)
#endif
{
#ifdef Avoid_Underflow
@@ -108,14 +109,14 @@
#endif
#ifdef USE_LOCALE /*{{*/
#ifdef NO_LOCALE_CACHE
- char *decimalpoint = localeconv()->decimal_point;
+ char *decimalpoint = localeconv_l(l)->decimal_point;
int dplen = strlen(decimalpoint);
#else
char *decimalpoint;
static char *decimalpoint_cache;
static int dplen;
if (!(s0 = decimalpoint_cache)) {
- s0 = localeconv()->decimal_point;
+ s0 = localeconv_l(l)->decimal_point;
if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
strcpy(decimalpoint_cache, s0);
s0 = decimalpoint_cache;
@@ -168,7 +169,7 @@
if (*s == '0') {
#ifndef NO_HEX_FP /*{*/
{
- static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
+ static const FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
Long exp;
ULong bits[2];
switch(s[1]) {
@@ -295,7 +296,7 @@
#ifdef INFNAN_CHECK
/* Check for Nan and Infinity */
ULong bits[2];
- static FPI fpinan = /* only 52 explicit bits */
+ static const FPI fpinan = /* only 52 explicit bits */
{ 52, 1-1023-53+1, 2046-1023-53+1, 1, SI };
if (!decpt)
switch(c) {
@@ -1074,3 +1075,13 @@
return sign ? -dval(&rv) : dval(&rv);
}
+ double
+strtod
+#ifdef KR_headers
+ (s00, se, l) CONST char *s00; char **se; locale_t
+#else
+ (CONST char *s00, char **se)
+#endif
+{
+ return strtod_l(s00, se, __get_locale());
+}
Index: contrib/gdtoa/strtof.c
===================================================================
--- contrib/gdtoa/strtof.c (revision 225653)
+++ contrib/gdtoa/strtof.c (working copy)
@@ -32,15 +32,16 @@
/* $FreeBSD$ */
#include "gdtoaimp.h"
+#include "xlocale_private.h"
float
#ifdef KR_headers
-strtof(s, sp) CONST char *s; char **sp;
+strtof_l(s, sp, l) CONST char *s; char **sp; locale_t l;
#else
-strtof(CONST char *s, char **sp)
+strtof_l(CONST char *s, char **sp, locale_t l)
#endif
{
- static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI };
+ static const FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI };
ULong bits[1];
Long exp;
int k;
@@ -51,7 +52,7 @@
#define fpi &fpi0
#endif
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, l);
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
@@ -82,3 +83,13 @@
u.L[0] |= 0x80000000L;
return u.f;
}
+
+ float
+#ifdef KR_headers
+strtof(s, sp) CONST char *s; char **sp;
+#else
+strtof(CONST char *s, char **sp)
+#endif
+{
+ return strtof_l(s, sp, __get_locale());
+}
Index: contrib/gdtoa/strtorx.c
===================================================================
--- contrib/gdtoa/strtorx.c (revision 225653)
+++ contrib/gdtoa/strtorx.c (working copy)
@@ -106,9 +106,10 @@
int
#ifdef KR_headers
-strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorx_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
#else
-strtorx(CONST char *s, char **sp, int rounding, void *L)
+strtorx_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
#endif
{
static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI };
@@ -123,7 +124,16 @@
fpi1.rounding = rounding;
fpi = &fpi1;
}
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, locale);
ULtox((UShort*)L, bits, exp, k);
return k;
}
+ int
+#ifdef KR_headers
+strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+#else
+strtorx(CONST char *s, char **sp, int rounding, void *L)
+#endif
+{
+ return strtorx_l(s, sp, rounding, L, __get_locale());
+}
Index: share/monetdef/zh_CN.UTF-8.src
===================================================================
--- share/monetdef/zh_CN.UTF-8.src (revision 225653)
+++ share/monetdef/zh_CN.UTF-8.src (working copy)
@@ -18,9 +18,9 @@
# negative_sign
-
# int_frac_digits
-0
+2
# frac_digits
-0
+2
# p_cs_precedes
1
# p_sep_by_space
Index: lib/msun/Symbol.map
===================================================================
--- lib/msun/Symbol.map (revision 225653)
+++ lib/msun/Symbol.map (working copy)
@@ -227,4 +227,21 @@
cexpf;
log2;
log2f;
+ coshl;
+ asinhl;
+ atanhl;
+ acoshl;
+ erfcl;
+ erfl;
+ expl;
+ expm1l;
+ lgammal;
+ log10l;
+ log1pl;
+ log2l;
+ logl;
+ tanhl;
+ sinhl;
+ tgammal;
+ powl;
};
Index: lib/msun/src/math.h
===================================================================
--- lib/msun/src/math.h (revision 225653)
+++ lib/msun/src/math.h (working copy)
@@ -230,8 +230,13 @@
double fma(double, double, double);
double hypot(double, double);
int ilogb(double) __pure2;
+#ifdef __cplusplus
+bool (isinf)(double) __pure2;
+bool (isnan)(double) __pure2;
+#else
int (isinf)(double) __pure2;
int (isnan)(double) __pure2;
+#endif
double lgamma(double);
long long llrint(double);
long long llround(double);
@@ -398,32 +403,32 @@
* long double versions of ISO/POSIX math functions
*/
#if __ISO_C_VISIBLE >= 1999
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double acoshl(long double);
#endif
long double acosl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double asinhl(long double);
#endif
long double asinl(long double);
long double atan2l(long double, long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double atanhl(long double);
#endif
long double atanl(long double);
long double cbrtl(long double);
long double ceill(long double);
long double copysignl(long double, long double) __pure2;
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double coshl(long double);
#endif
long double cosl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double erfcl(long double);
long double erfl(long double);
#endif
long double exp2l(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double expl(long double);
long double expm1l(long double);
#endif
@@ -438,18 +443,18 @@
long double hypotl(long double, long double);
int ilogbl(long double) __pure2;
long double ldexpl(long double, int);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double lgammal(long double);
#endif
long long llrintl(long double);
long long llroundl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double log10l(long double);
long double log1pl(long double);
long double log2l(long double);
#endif
long double logbl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double logl(long double);
#endif
long lrintl(long double);
@@ -461,7 +466,7 @@
double nexttoward(double, long double);
float nexttowardf(float, long double);
long double nexttowardl(long double, long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double powl(long double, long double);
#endif
long double remainderl(long double, long double);
@@ -470,16 +475,16 @@
long double roundl(long double);
long double scalblnl(long double, long);
long double scalbnl(long double, int);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double sinhl(long double);
#endif
long double sinl(long double);
long double sqrtl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double tanhl(long double);
#endif
long double tanl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
long double tgammal(long double);
#endif
long double truncl(long double);
Index: lib/msun/src/stubs.c
===================================================================
--- lib/msun/src/stubs.c (revision 0)
+++ lib/msun/src/stubs.c (revision 0)
@@ -0,0 +1,22 @@
+#include <math.h>
+
+#define LIBCXX_LONG_DOUBLE_STUB(fn) __attribute__((weak)) long double fn ## l(long double x) { return fn(x); }
+#define LIBCXX_LONG_DOUBLE_STUB2(fn) __attribute__((weak)) long double fn ## l(long double x, long double y) { return fn(x, y); }
+
+LIBCXX_LONG_DOUBLE_STUB(cosh)
+LIBCXX_LONG_DOUBLE_STUB(asinh)
+LIBCXX_LONG_DOUBLE_STUB(atanh)
+LIBCXX_LONG_DOUBLE_STUB(acosh)
+LIBCXX_LONG_DOUBLE_STUB(erfc)
+LIBCXX_LONG_DOUBLE_STUB(erf)
+LIBCXX_LONG_DOUBLE_STUB(exp)
+LIBCXX_LONG_DOUBLE_STUB(expm1)
+LIBCXX_LONG_DOUBLE_STUB(lgamma)
+LIBCXX_LONG_DOUBLE_STUB(log10)
+LIBCXX_LONG_DOUBLE_STUB(log1p)
+LIBCXX_LONG_DOUBLE_STUB(log2)
+LIBCXX_LONG_DOUBLE_STUB(log)
+LIBCXX_LONG_DOUBLE_STUB(tanh)
+LIBCXX_LONG_DOUBLE_STUB(sinh)
+LIBCXX_LONG_DOUBLE_STUB(tgamma)
+LIBCXX_LONG_DOUBLE_STUB2(pow)
Index: lib/msun/Makefile
===================================================================
--- lib/msun/Makefile (revision 225653)
+++ lib/msun/Makefile (working copy)
@@ -70,7 +70,7 @@
s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \
s_signgam.c s_significand.c s_significandf.c s_sin.c s_sinf.c \
s_tan.c s_tanf.c s_tanh.c s_tanhf.c s_tgammaf.c s_trunc.c s_truncf.c \
- w_cabs.c w_cabsf.c w_drem.c w_dremf.c
+ w_cabs.c w_cabsf.c w_drem.c w_dremf.c stubs.c
# Location of fpmath.h and _fpmath.h
LIBCDIR= ${.CURDIR}/../libc
Index: lib/libc/stdlib/Symbol.map
===================================================================
--- lib/libc/stdlib/Symbol.map (revision 225653)
+++ lib/libc/stdlib/Symbol.map (working copy)
@@ -90,6 +90,21 @@
tfind;
tsearch;
twalk;
+ atof_l;
+ atoi_l;
+ atol_l;
+ atoll_l;
+ strtod_l;
+ strtol_l;
+ strtoll_l;
+ strtof_l;
+ strtoimax_l;
+ strtold_l;
+ strtoq_l;
+ strtoul_l;
+ strtoull_l;
+ strtoumax_l;
+ strtouq_l;
};
FBSDprivate_1.0 {
Index: lib/libc/stdlib/atoll.c
===================================================================
--- lib/libc/stdlib/atoll.c (revision 225653)
+++ lib/libc/stdlib/atoll.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,6 +36,7 @@
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
long long
atoll(str)
@@ -38,3 +44,11 @@
{
return strtoll(str, (char **)NULL, 10);
}
+
+long long
+atoll_l(str, locale)
+ const char *str;
+ locale_t locale;
+{
+ return strtoll_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdlib/strfmon.c
===================================================================
--- lib/libc/stdlib/strfmon.c (revision 225653)
+++ lib/libc/stdlib/strfmon.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,6 +43,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "xlocale_private.h"
/* internal flags */
#define NEED_GROUPING 0x01 /* print digits grouped (default) */
@@ -92,11 +98,10 @@
static int __calc_left_pad(int, char *);
static char *__format_grouped_double(double, int *, int, int, int);
-ssize_t
-strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
- ...)
+static ssize_t
+vstrfmon_l(char * __restrict s, size_t maxsize, locale_t loc,
+ const char * __restrict format, va_list ap)
{
- va_list ap;
char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */
struct lconv *lc; /* pointer to lconv structure */
@@ -119,10 +124,10 @@
char *tmpptr; /* temporary vars */
int sverrno;
+ FIX_LOCALE(loc);
- va_start(ap, format);
- lc = localeconv();
+ lc = localeconv_l(loc);
dst = s;
fmt = format;
asciivalue = NULL;
@@ -380,7 +385,6 @@
}
PRINT('\0');
- va_end(ap);
free(asciivalue);
free(currency_symbol);
return (dst - s - 1); /* return size of put data except trailing '\0' */
@@ -399,10 +403,34 @@
if (currency_symbol != NULL)
free(currency_symbol);
errno = sverrno;
- va_end(ap);
return (-1);
}
+ssize_t
+strfmon_l(char * __restrict s, size_t maxsize, locale_t loc, const char * __restrict format,
+ ...)
+{
+ size_t ret;
+ va_list ap;
+ FIX_LOCALE(loc);
+ va_start(ap, format);
+ ret = vstrfmon_l(s, maxsize, loc, format, ap);
+ va_end(ap);
+ return ret;
+}
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
+ ...)
+{
+ size_t ret;
+ va_list ap;
+ va_start(ap, format);
+ ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap);
+ va_end(ap);
+ return ret;
+}
+
+
static void
__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
char *sign_posn, char **signstr) {
Index: lib/libc/stdlib/atof.c
===================================================================
--- lib/libc/stdlib/atof.c (revision 225653)
+++ lib/libc/stdlib/atof.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,6 +39,7 @@
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
double
atof(ascii)
@@ -41,3 +47,11 @@
{
return strtod(ascii, (char **)NULL);
}
+
+double
+atof_l(ascii, locale)
+ const char *ascii;
+ locale_t locale;
+{
+ return strtod_l(ascii, (char **)NULL, locale);
+}
Index: lib/libc/stdlib/strtoimax.c
===================================================================
--- lib/libc/stdlib/strtoimax.c (revision 225653)
+++ lib/libc/stdlib/strtoimax.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
+#include "xlocale_private.h"
/*
* Convert a string to an intmax_t integer.
@@ -45,13 +51,15 @@
* alphabets and digits are each contiguous.
*/
intmax_t
-strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
{
const char *s;
uintmax_t acc;
char c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
@@ -61,7 +69,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -138,3 +146,8 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoimax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/atol.c
===================================================================
--- lib/libc/stdlib/atol.c (revision 225653)
+++ lib/libc/stdlib/atol.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,6 +39,7 @@
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
long
atol(str)
@@ -41,3 +47,11 @@
{
return strtol(str, (char **)NULL, 10);
}
+
+long
+atol_l(str, locale)
+ const char *str;
+ locale_t locale;
+{
+ return strtol_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdlib/strtoumax.c
===================================================================
--- lib/libc/stdlib/strtoumax.c (revision 225653)
+++ lib/libc/stdlib/strtoumax.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
+#include "xlocale_private.h"
/*
* Convert a string to a uintmax_t integer.
@@ -45,13 +51,15 @@
* alphabets and digits are each contiguous.
*/
uintmax_t
-strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
{
const char *s;
uintmax_t acc;
char c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -59,7 +67,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -116,3 +124,8 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoumax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoul.c
===================================================================
--- lib/libc/stdlib/strtoul.c (revision 225653)
+++ lib/libc/stdlib/strtoul.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
* Convert a string to an unsigned long integer.
@@ -45,13 +51,14 @@
* alphabets and digits are each contiguous.
*/
unsigned long
-strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale)
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -59,7 +66,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -116,3 +123,8 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoul_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoull.c
===================================================================
--- lib/libc/stdlib/strtoull.c (revision 225653)
+++ lib/libc/stdlib/strtoull.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
* Convert a string to an unsigned long long integer.
@@ -45,13 +51,15 @@
* alphabets and digits are each contiguous.
*/
unsigned long long
-strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
{
const char *s;
unsigned long long acc;
char c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoq for comments as to the logic used.
@@ -59,7 +67,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -116,3 +124,8 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long long
+strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoull_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoll.c
===================================================================
--- lib/libc/stdlib/strtoll.c (revision 225653)
+++ lib/libc/stdlib/strtoll.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
+#include <xlocale_private.h>
/*
* Convert a string to a long long integer.
@@ -45,13 +51,15 @@
* alphabets and digits are each contiguous.
*/
long long
-strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
{
const char *s;
unsigned long long acc;
char c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
@@ -61,7 +69,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -138,3 +146,8 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+long long
+strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoll_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtol.c
===================================================================
--- lib/libc/stdlib/strtol.c (revision 225653)
+++ lib/libc/stdlib/strtol.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
@@ -46,13 +52,15 @@
* alphabets and digits are each contiguous.
*/
long
-strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
@@ -62,7 +70,7 @@
s = nptr;
do {
c = *s++;
- } while (isspace((unsigned char)c));
+ } while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -138,3 +146,13 @@
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtol_l(nptr, endptr, base, __get_locale());
+}
+long double
+strtold(const char * __restrict nptr, char ** __restrict endptr)
+{
+ return strtold_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/stdlib/atoi.c
===================================================================
--- lib/libc/stdlib/atoi.c (revision 225653)
+++ lib/libc/stdlib/atoi.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,6 +39,7 @@
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
int
atoi(str)
@@ -41,3 +47,11 @@
{
return (int)strtol(str, (char **)NULL, 10);
}
+
+int
+atoi_l(str, locale)
+ const char *str;
+ locale_t locale;
+{
+ return (int)strtol_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdio/putwc.c
===================================================================
--- lib/libc/stdio/putwc.c (revision 225653)
+++ lib/libc/stdio/putwc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,6 +38,7 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#undef putwc
@@ -41,8 +47,13 @@
* macro, may evaluate `fp' more than once.
*/
wint_t
+putwc_l(wchar_t wc, FILE *fp, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (fputwc_l(wc, fp, locale));
+}
+wint_t
putwc(wchar_t wc, FILE *fp)
{
-
- return (fputwc(wc, fp));
+ return putwc_l(wc, fp, __get_locale());
}
Index: lib/libc/stdio/printf.c
===================================================================
--- lib/libc/stdio/printf.c (revision 225653)
+++ lib/libc/stdio/printf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,6 +43,7 @@
#include <stdio.h>
#include <stdarg.h>
+#include <xlocale.h>
int
printf(char const * __restrict fmt, ...)
@@ -50,3 +56,14 @@
va_end(ap);
return (ret);
}
+int
+printf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf_l(stdout, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/getwchar.c
===================================================================
--- lib/libc/stdio/getwchar.c (revision 225653)
+++ lib/libc/stdio/getwchar.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
@@ -42,6 +48,10 @@
wint_t
getwchar(void)
{
-
return (fgetwc(stdin));
}
+wint_t
+getwchar_l(locale_t locale)
+{
+ return (fgetwc_l(stdin, locale));
+}
Index: lib/libc/stdio/Symbol.map
===================================================================
--- lib/libc/stdio/Symbol.map (revision 225653)
+++ lib/libc/stdio/Symbol.map (working copy)
@@ -108,6 +108,43 @@
__swbuf;
wprintf;
wscanf;
+ asprintf_l;
+ fprintf_l;
+ fwprintf_l;
+ printf_l;
+ snprintf_l;
+ sprintf_l;
+ swprintf_l;
+ vasprintf_l;
+ vfprintf_l;
+ vfwprintf_l;
+ vprintf_l;
+ vsnprintf_l;
+ vsprintf_l;
+ vswprintf_l;
+ vwprintf_l;
+ wprintf_l;
+ fgetwc_l;
+ fputwc_l;
+ ungetwc_l;
+ vfwscanf_l;
+ vswscanf_l;
+ fscanf_l;
+ fwscanf_l;
+ scanf_l;
+ sscanf_l;
+ swscanf_l;
+ vfscanf_l;
+ vscanf_l;
+ vsscanf_l;
+ vwscanf_l;
+ wscanf_l;
+ fgetws_l;
+ fputws_l;
+ getwc_l;
+ getwchar_l;
+ putwc_l;
+ putwchar_l;
};
FBSD_1.1 {
Index: lib/libc/stdio/fgetwln.c
===================================================================
--- lib/libc/stdio/fgetwln.c (revision 225653)
+++ lib/libc/stdio/fgetwln.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,18 +38,20 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
wchar_t *
-fgetwln(FILE * __restrict fp, size_t *lenp)
+fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
{
wint_t wc;
size_t len;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
len = 0;
- while ((wc = __fgetwc(fp)) != WEOF) {
+ while ((wc = __fgetwc(fp, locale)) != WEOF) {
#define GROW 512
if (len * sizeof(wchar_t) >= fp->_lb._size &&
__slbexpand(fp, (len + GROW) * sizeof(wchar_t)))
@@ -65,3 +72,8 @@
*lenp = 0;
return (NULL);
}
+wchar_t *
+fgetwln(FILE * __restrict fp, size_t *lenp)
+{
+ return fgetwln_l(fp, lenp, __get_locale());
+}
Index: lib/libc/stdio/getwc.c
===================================================================
--- lib/libc/stdio/getwc.c (revision 225653)
+++ lib/libc/stdio/getwc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
@@ -43,6 +49,10 @@
wint_t
getwc(FILE *fp)
{
-
return (fgetwc(fp));
}
+wint_t
+getwc_l(FILE *fp, locale_t locale)
+{
+ return (fgetwc_l(fp, locale));
+}
Index: lib/libc/stdio/vsnprintf.c
===================================================================
--- lib/libc/stdio/vsnprintf.c (revision 225653)
+++ lib/libc/stdio/vsnprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,15 +44,17 @@
#include <limits.h>
#include <stdio.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
- __va_list ap)
+vsnprintf_l(char * __restrict str, size_t n, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
{
size_t on;
int ret;
char dummy[2];
FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
on = n;
if (n != 0)
@@ -64,8 +71,14 @@
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = n;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
if (on > 0)
*f._p = '\0';
return (ret);
}
+int
+vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
+ __va_list ap)
+{
+ return vsnprintf_l(str, n, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/putwchar.c
===================================================================
--- lib/libc/stdio/putwchar.c (revision 225653)
+++ lib/libc/stdio/putwchar.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,6 +38,7 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#undef putwchar
@@ -40,8 +46,13 @@
* Synonym for fputwc(wc, stdout).
*/
wint_t
+putwchar_l(wchar_t wc, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (fputwc_l(wc, stdout, locale));
+}
+wint_t
putwchar(wchar_t wc)
{
-
- return (fputwc(wc, stdout));
+ return putwchar_l(wc, __get_locale());
}
Index: lib/libc/stdio/vswprintf.c
===================================================================
--- lib/libc/stdio/vswprintf.c (revision 225653)
+++ lib/libc/stdio/vswprintf.c (working copy)
@@ -4,6 +4,11 @@
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,11 @@
#include <stdlib.h>
#include <wchar.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
- __va_list ap)
+vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+ const wchar_t * __restrict fmt, __va_list ap)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -49,6 +55,7 @@
char *mbp;
int ret, sverrno;
size_t nwc;
+ FIX_LOCALE(locale);
if (n == 0) {
errno = EINVAL;
@@ -62,7 +69,7 @@
return (-1);
}
f._bf._size = f._w = 127; /* Leave room for the NUL */
- ret = __vfwprintf(&f, fmt, ap);
+ ret = __vfwprintf(&f, locale, fmt, ap);
if (ret < 0) {
sverrno = errno;
free(f._bf._base);
@@ -76,7 +83,7 @@
* fputwc() did in __vfwprintf().
*/
mbs = initial;
- nwc = mbsrtowcs(s, (const char **)&mbp, n, &mbs);
+ nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
free(f._bf._base);
if (nwc == (size_t)-1) {
errno = EILSEQ;
@@ -90,3 +97,9 @@
return (ret);
}
+int
+vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
+ __va_list ap)
+{
+ return vswprintf_l(s, n, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vsscanf.c
===================================================================
--- lib/libc/stdio/vsscanf.c (revision 225653)
+++ lib/libc/stdio/vsscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
@@ -39,6 +44,7 @@
#include <stdio.h>
#include <string.h>
#include "local.h"
+#include "xlocale_private.h"
static int
eofread(void *, char *, int);
@@ -52,14 +58,21 @@
}
int
-vsscanf(const char * __restrict str, const char * __restrict fmt,
- __va_list ap)
+vsscanf_l(const char * __restrict str, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
{
FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
f._flags = __SRD;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._r = strlen(str);
f._read = eofread;
- return (__svfscanf(&f, fmt, ap));
+ return (__svfscanf(&f, locale, fmt, ap));
}
+int
+vsscanf(const char * __restrict str, const char * __restrict fmt,
+ __va_list ap)
+{
+ return vsscanf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/snprintf.c
===================================================================
--- lib/libc/stdio/snprintf.c (revision 225653)
+++ lib/libc/stdio/snprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
@@ -39,6 +44,7 @@
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
+#include "xlocale_private.h"
#include "local.h"
@@ -59,9 +65,34 @@
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = n;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, __get_locale(), fmt, ap);
if (on > 0)
*f._p = '\0';
va_end(ap);
return (ret);
}
+int
+snprintf_l(char * __restrict str, size_t n, locale_t locale,
+ char const * __restrict fmt, ...)
+{
+ size_t on;
+ int ret;
+ va_list ap;
+ FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX)
+ n = INT_MAX;
+ va_start(ap, fmt);
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ ret = __vfprintf(&f, locale, fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/ungetwc.c
===================================================================
--- lib/libc/stdio/ungetwc.c (revision 225653)
+++ lib/libc/stdio/ungetwc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,19 +42,21 @@
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
+#include "xlocale_private.h"
/*
* Non-MT-safe version.
*/
wint_t
-__ungetwc(wint_t wc, FILE *fp)
+__ungetwc(wint_t wc, FILE *fp, locale_t locale)
{
char buf[MB_LEN_MAX];
size_t len;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
if (wc == WEOF)
return (WEOF);
- if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+ if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
}
@@ -64,14 +71,20 @@
* MT-safe version.
*/
wint_t
-ungetwc(wint_t wc, FILE *fp)
+ungetwc_l(wint_t wc, FILE *fp, locale_t locale)
{
wint_t r;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
- r = __ungetwc(wc, fp);
+ r = __ungetwc(wc, fp, locale);
FUNLOCKFILE(fp);
return (r);
}
+wint_t
+ungetwc(wint_t wc, FILE *fp)
+{
+ return ungetwc_l(wc, fp, __get_locale());
+}
Index: lib/libc/stdio/swprintf.c
===================================================================
--- lib/libc/stdio/swprintf.c (revision 225653)
+++ lib/libc/stdio/swprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@
return (ret);
}
+int
+swprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+ const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vswprintf_l(s, n, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
Index: lib/libc/stdio/wscanf.c
===================================================================
--- lib/libc/stdio/wscanf.c (revision 225653)
+++ lib/libc/stdio/wscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
wscanf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
return (r);
}
+int
+wscanf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf_l(stdin, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
Index: lib/libc/stdio/fscanf.c
===================================================================
--- lib/libc/stdio/fscanf.c (revision 225653)
+++ lib/libc/stdio/fscanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -42,6 +47,7 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
int
fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
@@ -51,8 +57,22 @@
va_start(ap, fmt);
FLOCKFILE(fp);
- ret = __svfscanf(fp, fmt, ap);
+ ret = __svfscanf(fp, __get_locale(), fmt, ap);
va_end(ap);
FUNLOCKFILE(fp);
return (ret);
}
+int
+fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, locale, fmt, ap);
+ va_end(ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
Index: lib/libc/stdio/fprintf.c
===================================================================
--- lib/libc/stdio/fprintf.c (revision 225653)
+++ lib/libc/stdio/fprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,6 +43,7 @@
#include <stdio.h>
#include <stdarg.h>
+#include "xlocale_private.h"
int
fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
@@ -46,7 +52,19 @@
va_list ap;
va_start(ap, fmt);
- ret = vfprintf(fp, fmt, ap);
+ ret = vfprintf_l(fp, __get_locale(), fmt, ap);
va_end(ap);
return (ret);
}
+int
+fprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ ret = vfprintf_l(fp, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/vscanf.c
===================================================================
--- lib/libc/stdio/vscanf.c (revision 225653)
+++ lib/libc/stdio/vscanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,16 +46,26 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
int
-vscanf(fmt, ap)
+vscanf_l(locale, fmt, ap)
+ locale_t locale;
const char * __restrict fmt;
__va_list ap;
{
int retval;
+ FIX_LOCALE(locale);
FLOCKFILE(stdin);
- retval = __svfscanf(stdin, fmt, ap);
+ retval = __svfscanf(stdin, locale, fmt, ap);
FUNLOCKFILE(stdin);
return (retval);
}
+int
+vscanf(fmt, ap)
+ const char * __restrict fmt;
+ __va_list ap;
+{
+ return vscanf_l(__get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/printfcommon.h
===================================================================
--- lib/libc/stdio/printfcommon.h (revision 225653)
+++ lib/libc/stdio/printfcommon.h (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -79,14 +84,14 @@
* remain valid until io_flush() is called.
*/
static inline int
-io_print(struct io_state *iop, const CHAR * __restrict ptr, int len)
+io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale)
{
iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
iop->iov[iop->uio.uio_iovcnt].iov_len = len;
iop->uio.uio_resid += len;
if (++iop->uio.uio_iovcnt >= NIOV)
- return (__sprint(iop->fp, &iop->uio));
+ return (__sprint(iop->fp, &iop->uio, locale));
else
return (0);
}
@@ -107,13 +112,14 @@
* or the zeroes array.
*/
static inline int
-io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
+io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with,
+ locale_t locale)
{
int n;
while (howmany > 0) {
n = (howmany >= PADSIZE) ? PADSIZE : howmany;
- if (io_print(iop, with, n))
+ if (io_print(iop, with, n, locale))
return (-1);
howmany -= n;
}
@@ -126,7 +132,7 @@
*/
static inline int
io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
- int len, const CHAR * __restrict with)
+ int len, const CHAR * __restrict with, locale_t locale)
{
int p_len;
@@ -134,19 +140,19 @@
if (p_len > len)
p_len = len;
if (p_len > 0) {
- if (io_print(iop, p, p_len))
+ if (io_print(iop, p, p_len, locale))
return (-1);
} else {
p_len = 0;
}
- return (io_pad(iop, len - p_len, with));
+ return (io_pad(iop, len - p_len, with, locale));
}
static inline int
-io_flush(struct io_state *iop)
+io_flush(struct io_state *iop, locale_t locale)
{
- return (__sprint(iop->fp, &iop->uio));
+ return (__sprint(iop->fp, &iop->uio, locale));
}
/*
Index: lib/libc/stdio/sprintf.c
===================================================================
--- lib/libc/stdio/sprintf.c (revision 225653)
+++ lib/libc/stdio/sprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -40,6 +45,7 @@
#include <stdarg.h>
#include <limits.h>
#include "local.h"
+#include "xlocale_private.h"
int
sprintf(char * __restrict str, char const * __restrict fmt, ...)
@@ -52,3 +58,16 @@
va_end(ap);
return (ret);
}
+int
+sprintf_l(char * __restrict str, locale_t locale, char const * __restrict fmt,
+ ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ ret = vsprintf_l(str, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/vprintf.c
===================================================================
--- lib/libc/stdio/vprintf.c (revision 225653)
+++ lib/libc/stdio/vprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,10 +42,15 @@
__FBSDID("$FreeBSD$");
#include <stdio.h>
+#include <xlocale.h>
int
vprintf(const char * __restrict fmt, __va_list ap)
{
-
return (vfprintf(stdout, fmt, ap));
}
+int
+vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
+{
+ return (vfprintf_l(stdout, locale, fmt, ap));
+}
Index: lib/libc/stdio/wprintf.c
===================================================================
--- lib/libc/stdio/wprintf.c (revision 225653)
+++ lib/libc/stdio/wprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
wprintf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
return (ret);
}
+int
+wprintf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf_l(stdout, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
Index: lib/libc/stdio/vfwprintf.c
===================================================================
--- lib/libc/stdio/vfwprintf.c (revision 225653)
+++ lib/libc/stdio/vfwprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -65,10 +70,11 @@
#include "local.h"
#include "fvwrite.h"
#include "printflocal.h"
+#include "xlocale_private.h"
-static int __sprint(FILE *, struct __suio *);
-static int __sbprintf(FILE *, const wchar_t *, va_list) __noinline;
-static wint_t __xfputwc(wchar_t, FILE *);
+static int __sprint(FILE *, struct __suio *, locale_t);
+static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline;
+static wint_t __xfputwc(wchar_t, FILE *, locale_t);
static wchar_t *__mbsconv(char *, int);
#define CHAR wchar_t
@@ -85,28 +91,28 @@
static const mbstate_t initial_mbs;
static inline wchar_t
-get_decpt(void)
+get_decpt(locale_t locale)
{
mbstate_t mbs;
wchar_t decpt;
int nconv;
mbs = initial_mbs;
- nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+ nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs);
if (nconv == (size_t)-1 || nconv == (size_t)-2)
decpt = '.'; /* failsafe */
return (decpt);
}
static inline wchar_t
-get_thousep(void)
+get_thousep(locale_t locale)
{
mbstate_t mbs;
wchar_t thousep;
int nconv;
mbs = initial_mbs;
- nconv = mbrtowc(&thousep, localeconv()->thousands_sep,
+ nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep,
MB_CUR_MAX, &mbs);
if (nconv == (size_t)-1 || nconv == (size_t)-2)
thousep = '\0'; /* failsafe */
@@ -119,11 +125,11 @@
* of wide characters that will be printed.
*/
static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t locale)
{
- gs->grouping = localeconv()->grouping;
- gs->thousands_sep = get_thousep();
+ gs->grouping = localeconv_l(locale)->grouping;
+ gs->thousands_sep = get_thousep(locale);
gs->nseps = gs->nrepeats = 0;
gs->lead = ndigits;
@@ -145,11 +151,11 @@
*/
static int
grouping_print(struct grouping_state *gs, struct io_state *iop,
- const CHAR *cp, const CHAR *ep)
+ const CHAR *cp, const CHAR *ep, locale_t locale)
{
const CHAR *cp0 = cp;
- if (io_printandpad(iop, cp, ep, gs->lead, zeroes))
+ if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
return (-1);
cp += gs->lead;
while (gs->nseps > 0 || gs->nrepeats > 0) {
@@ -159,9 +165,9 @@
gs->grouping--;
gs->nseps--;
}
- if (io_print(iop, &gs->thousands_sep, 1))
+ if (io_print(iop, &gs->thousands_sep, 1, locale))
return (-1);
- if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes))
+ if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
return (-1);
cp += *gs->grouping;
}
@@ -180,7 +186,7 @@
* string eclipses the benefits of buffering.
*/
static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
{
struct __siov *iov;
wchar_t *p;
@@ -191,7 +197,7 @@
p = (wchar_t *)iov->iov_base;
len = iov->iov_len;
for (i = 0; i < len; i++) {
- if (__xfputwc(p[i], fp) == WEOF)
+ if (__xfputwc(p[i], fp, locale) == WEOF)
return (-1);
}
}
@@ -205,7 +211,7 @@
* worries about ungetc buffers and so forth.
*/
static int
-__sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap)
{
int ret;
FILE fake;
@@ -229,7 +235,7 @@
fake._lbfsize = 0; /* not actually used, but Just In Case */
/* do the work, then copy any error status */
- ret = __vfwprintf(&fake, fmt, ap);
+ ret = __vfwprintf(&fake, locale, fmt, ap);
if (ret >= 0 && __fflush(&fake))
ret = WEOF;
if (fake._flags & __SERR)
@@ -242,7 +248,7 @@
* File must already be locked.
*/
static wint_t
-__xfputwc(wchar_t wc, FILE *fp)
+__xfputwc(wchar_t wc, FILE *fp, locale_t locale)
{
mbstate_t mbs;
char buf[MB_LEN_MAX];
@@ -251,7 +257,7 @@
size_t len;
if ((fp->_flags & __SSTR) == 0)
- return (__fputwc(wc, fp));
+ return (__fputwc(wc, fp, locale));
mbs = initial_mbs;
if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
@@ -343,21 +349,27 @@
* MT-safe version
*/
int
-vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+vfwprintf_l(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt0, va_list ap)
{
int ret;
-
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
- ret = __sbprintf(fp, fmt0, ap);
+ ret = __sbprintf(fp, locale, fmt0, ap);
else
- ret = __vfwprintf(fp, fmt0, ap);
+ ret = __vfwprintf(fp, locale, fmt0, ap);
FUNLOCKFILE(fp);
return (ret);
}
+int
+vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+{
+ return vfwprintf_l(fp, __get_locale(), fmt0, ap);
+}
/*
* The size of the buffer we use as scratch space for integer
@@ -374,7 +386,7 @@
* Non-MT-safe version
*/
int
-__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
+__vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap)
{
wchar_t *fmt; /* format string */
wchar_t ch; /* character from fmt */
@@ -437,19 +449,19 @@
/* BEWARE, these `goto error' on error. */
#define PRINT(ptr, len) do { \
- if (io_print(&io, (ptr), (len))) \
+ if (io_print(&io, (ptr), (len), locale)) \
goto error; \
} while (0)
#define PAD(howmany, with) { \
- if (io_pad(&io, (howmany), (with))) \
+ if (io_pad(&io, (howmany), (with), locale)) \
goto error; \
}
#define PRINTANDPAD(p, ep, len, with) { \
- if (io_printandpad(&io, (p), (ep), (len), (with))) \
+ if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
goto error; \
}
#define FLUSH() { \
- if (io_flush(&io)) \
+ if (io_flush(&io, locale)) \
goto error; \
}
@@ -529,7 +541,7 @@
io_init(&io, fp);
ret = 0;
#ifndef NO_FLOATING_POINT
- decimal_point = get_decpt();
+ decimal_point = get_decpt(locale);
#endif
/*
@@ -816,7 +828,7 @@
if (prec || flags & ALT)
size += prec + 1;
if ((flags & GROUPING) && expt > 0)
- size += grouping_init(&gs, expt);
+ size += grouping_init(&gs, expt, locale);
}
break;
#endif /* !NO_FLOATING_POINT */
@@ -955,7 +967,7 @@
if (size > BUF) /* should never happen */
abort();
if ((flags & GROUPING) && size != 0)
- size += grouping_init(&gs, size);
+ size += grouping_init(&gs, size, locale);
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
@@ -1018,7 +1030,7 @@
/* leading zeroes from decimal precision */
PAD(dprec - size, zeroes);
if (gs.grouping) {
- if (grouping_print(&gs, &io, cp, buf+BUF) < 0)
+ if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
goto error;
} else {
PRINT(cp, size);
@@ -1036,7 +1048,7 @@
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
- cp, convbuf + ndig);
+ cp, convbuf + ndig, locale);
if (n < 0)
goto error;
cp += n;
Index: lib/libc/stdio/vdprintf.c
===================================================================
--- lib/libc/stdio/vdprintf.c (revision 225653)
+++ lib/libc/stdio/vdprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,6 +40,7 @@
#include "un-namespace.h"
#include "local.h"
+#include "xlocale_private.h"
int
vdprintf(int fd, const char * __restrict fmt, va_list ap)
@@ -57,7 +63,7 @@
f._bf._base = buf;
f._bf._size = sizeof(buf);
- if ((ret = __vfprintf(&f, fmt, ap)) < 0)
+ if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
return (ret);
return (__fflush(&f) ? EOF : ret);
Index: lib/libc/stdio/vfprintf.c
===================================================================
--- lib/libc/stdio/vfprintf.c (revision 225653)
+++ lib/libc/stdio/vfprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -57,6 +62,7 @@
#include <printf.h>
#include <stdarg.h>
+#include "xlocale_private.h"
#include "un-namespace.h"
#include "libc_private.h"
@@ -64,8 +70,8 @@
#include "fvwrite.h"
#include "printflocal.h"
-static int __sprint(FILE *, struct __suio *);
-static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0)
+static int __sprint(FILE *, struct __suio *, locale_t);
+static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0)
__noinline;
static char *__wcsconv(wchar_t *, int);
@@ -87,11 +93,11 @@
* of bytes that will be needed.
*/
static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
{
struct lconv *locale;
- locale = localeconv();
+ locale = localeconv_l(loc);
gs->grouping = locale->grouping;
gs->thousands_sep = locale->thousands_sep;
gs->thousep_len = strlen(gs->thousands_sep);
@@ -116,11 +122,11 @@
*/
static int
grouping_print(struct grouping_state *gs, struct io_state *iop,
- const CHAR *cp, const CHAR *ep)
+ const CHAR *cp, const CHAR *ep, locale_t locale)
{
const CHAR *cp0 = cp;
- if (io_printandpad(iop, cp, ep, gs->lead, zeroes))
+ if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
return (-1);
cp += gs->lead;
while (gs->nseps > 0 || gs->nrepeats > 0) {
@@ -130,9 +136,9 @@
gs->grouping--;
gs->nseps--;
}
- if (io_print(iop, gs->thousands_sep, gs->thousep_len))
+ if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
return (-1);
- if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes))
+ if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
return (-1);
cp += *gs->grouping;
}
@@ -146,7 +152,7 @@
* then reset it so that it can be reused.
*/
static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
{
int err;
@@ -166,7 +172,7 @@
* worries about ungetc buffers and so forth.
*/
static int
-__sbprintf(FILE *fp, const char *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
{
int ret;
FILE fake = FAKE_FILE;
@@ -190,7 +196,7 @@
fake._lbfsize = 0; /* not actually used, but Just In Case */
/* do the work, then copy any error status */
- ret = __vfprintf(&fake, fmt, ap);
+ ret = __vfprintf(&fake, locale, fmt, ap);
if (ret >= 0 && __fflush(&fake))
ret = EOF;
if (fake._flags & __SERR)
@@ -261,21 +267,27 @@
* MT-safe version
*/
int
-vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
-
+vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
+ va_list ap)
{
int ret;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
- ret = __sbprintf(fp, fmt0, ap);
+ ret = __sbprintf(fp, locale, fmt0, ap);
else
- ret = __vfprintf(fp, fmt0, ap);
+ ret = __vfprintf(fp, locale, fmt0, ap);
FUNLOCKFILE(fp);
return (ret);
}
+int
+vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+{
+ return vfprintf_l(fp, __get_locale(), fmt0, ap);
+}
/*
* The size of the buffer we use as scratch space for integer
@@ -292,7 +304,7 @@
* Non-MT-safe version
*/
int
-__vfprintf(FILE *fp, const char *fmt0, va_list ap)
+__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
{
char *fmt; /* format string */
int ch; /* character from fmt */
@@ -357,19 +369,19 @@
/* BEWARE, these `goto error' on error. */
#define PRINT(ptr, len) { \
- if (io_print(&io, (ptr), (len))) \
+ if (io_print(&io, (ptr), (len), locale)) \
goto error; \
}
#define PAD(howmany, with) { \
- if (io_pad(&io, (howmany), (with))) \
+ if (io_pad(&io, (howmany), (with), locale)) \
goto error; \
}
#define PRINTANDPAD(p, ep, len, with) { \
- if (io_printandpad(&io, (p), (ep), (len), (with))) \
+ if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
goto error; \
}
#define FLUSH() { \
- if (io_flush(&io)) \
+ if (io_flush(&io, locale)) \
goto error; \
}
@@ -454,7 +466,7 @@
ret = 0;
#ifndef NO_FLOATING_POINT
dtoaresult = NULL;
- decimal_point = localeconv()->decimal_point;
+ decimal_point = localeconv_l(locale)->decimal_point;
/* The overwhelmingly common case is decpt_len == 1. */
decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
#endif
@@ -750,7 +762,7 @@
if (prec || flags & ALT)
size += prec + decpt_len;
if ((flags & GROUPING) && expt > 0)
- size += grouping_init(&gs, expt);
+ size += grouping_init(&gs, expt, locale);
}
break;
#endif /* !NO_FLOATING_POINT */
@@ -887,7 +899,7 @@
if (size > BUF) /* should never happen */
abort();
if ((flags & GROUPING) && size != 0)
- size += grouping_init(&gs, size);
+ size += grouping_init(&gs, size, locale);
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
@@ -950,7 +962,7 @@
/* leading zeroes from decimal precision */
PAD(dprec - size, zeroes);
if (gs.grouping) {
- if (grouping_print(&gs, &io, cp, buf+BUF) < 0)
+ if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
goto error;
} else {
PRINT(cp, size);
@@ -968,7 +980,7 @@
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
- cp, dtoaend);
+ cp, dtoaend, locale);
if (n < 0)
goto error;
cp += n;
Index: lib/libc/stdio/local.h
===================================================================
--- lib/libc/stdio/local.h (revision 225653)
+++ lib/libc/stdio/local.h (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <pthread.h>
#include <string.h>
#include <wchar.h>
+#include <locale.h>
/*
* Information local to this implementation of stdio,
@@ -50,8 +56,8 @@
extern int _fseeko(FILE *, off_t, int, int);
extern int __fflush(FILE *fp);
extern void __fcloseall(void);
-extern wint_t __fgetwc(FILE *);
-extern wint_t __fputwc(wchar_t, FILE *);
+extern wint_t __fgetwc(FILE *, locale_t);
+extern wint_t __fputwc(wchar_t, FILE *, locale_t);
extern int __sflush(FILE *);
extern FILE *__sfp(void);
extern int __slbexpand(FILE *, size_t);
@@ -65,15 +71,15 @@
extern void __smakebuf(FILE *);
extern int __swhatbuf(FILE *, size_t *, int *);
extern int _fwalk(int (*)(FILE *));
-extern int __svfscanf(FILE *, const char *, __va_list);
+extern int __svfscanf(FILE *, locale_t, const char *, __va_list);
extern int __swsetup(FILE *);
extern int __sflags(const char *, int *);
extern int __ungetc(int, FILE *);
-extern wint_t __ungetwc(wint_t, FILE *);
-extern int __vfprintf(FILE *, const char *, __va_list);
+extern wint_t __ungetwc(wint_t, FILE *, locale_t);
+extern int __vfprintf(FILE *, locale_t, const char *, __va_list);
extern int __vfscanf(FILE *, const char *, __va_list);
-extern int __vfwprintf(FILE *, const wchar_t *, __va_list);
-extern int __vfwscanf(FILE * __restrict, const wchar_t * __restrict,
+extern int __vfwprintf(FILE *, locale_t, const wchar_t *, __va_list);
+extern int __vfwscanf(FILE * __restrict, locale_t, const wchar_t * __restrict,
__va_list);
extern size_t __fread(void * __restrict buf, size_t size, size_t count,
FILE * __restrict fp);
Index: lib/libc/stdio/fwprintf.c
===================================================================
--- lib/libc/stdio/fwprintf.c (revision 225653)
+++ lib/libc/stdio/fwprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
return (ret);
}
+int
+fwprintf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf_l(fp, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
Index: lib/libc/stdio/fputwc.c
===================================================================
--- lib/libc/stdio/fputwc.c (revision 225653)
+++ lib/libc/stdio/fputwc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -42,10 +47,11 @@
* Non-MT-safe version.
*/
wint_t
-__fputwc(wchar_t wc, FILE *fp)
+__fputwc(wchar_t wc, FILE *fp, locale_t locale)
{
char buf[MB_LEN_MAX];
size_t i, len;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
/*
@@ -56,7 +62,7 @@
*buf = (unsigned char)wc;
len = 1;
} else {
- if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+ if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
}
@@ -73,14 +79,20 @@
* MT-safe version.
*/
wint_t
-fputwc(wchar_t wc, FILE *fp)
+fputwc_l(wchar_t wc, FILE *fp, locale_t locale)
{
wint_t r;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
- r = __fputwc(wc, fp);
+ r = __fputwc(wc, fp, locale);
FUNLOCKFILE(fp);
return (r);
}
+wint_t
+fputwc(wchar_t wc, FILE *fp)
+{
+ return fputwc_l(wc, fp, __get_locale());
+}
Index: lib/libc/stdio/vsprintf.c
===================================================================
--- lib/libc/stdio/vsprintf.c (revision 225653)
+++ lib/libc/stdio/vsprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,17 +44,25 @@
#include <stdio.h>
#include <limits.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+vsprintf_l(char * __restrict str, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
{
int ret;
FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = INT_MAX;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
*f._p = 0;
return (ret);
}
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+ return vsprintf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vwprintf.c
===================================================================
--- lib/libc/stdio/vwprintf.c (revision 225653)
+++ lib/libc/stdio/vwprintf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,10 +35,15 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
vwprintf(const wchar_t * __restrict fmt, va_list ap)
{
-
return (vfwprintf(stdout, fmt, ap));
}
+int
+vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwprintf_l(stdout, locale, fmt, ap));
+}
Index: lib/libc/stdio/fwscanf.c
===================================================================
--- lib/libc/stdio/fwscanf.c (revision 225653)
+++ lib/libc/stdio/fwscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
return (r);
}
+int
+fwscanf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf_l(fp, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
Index: lib/libc/stdio/fputws.c
===================================================================
--- lib/libc/stdio/fputws.c (revision 225653)
+++ lib/libc/stdio/fputws.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,13 +44,15 @@
#include "mblocal.h"
int
-fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale)
{
size_t nbytes;
char buf[BUFSIZ];
struct __suio uio;
struct __siov iov;
const wchar_t *wsp;
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
@@ -56,7 +63,7 @@
iov.iov_base = buf;
do {
wsp = ws;
- nbytes = __wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
+ nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
&fp->_mbstate);
if (nbytes == (size_t)-1)
goto error;
@@ -71,3 +78,9 @@
FUNLOCKFILE(fp);
return (-1);
}
+
+int
+fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+{
+ return fputws_l(ws, fp, __get_locale());
+}
Index: lib/libc/stdio/scanf.c
===================================================================
--- lib/libc/stdio/scanf.c (revision 225653)
+++ lib/libc/stdio/scanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -42,6 +47,7 @@
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
int
scanf(char const * __restrict fmt, ...)
@@ -51,8 +57,22 @@
va_start(ap, fmt);
FLOCKFILE(stdin);
- ret = __svfscanf(stdin, fmt, ap);
+ ret = __svfscanf(stdin, __get_locale(), fmt, ap);
FUNLOCKFILE(stdin);
va_end(ap);
return (ret);
}
+int
+scanf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ FLOCKFILE(stdin);
+ ret = __svfscanf(stdin, locale, fmt, ap);
+ FUNLOCKFILE(stdin);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/swscanf.c
===================================================================
--- lib/libc/stdio/swscanf.c (revision 225653)
+++ lib/libc/stdio/swscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@
return (r);
}
+int
+swscanf_l(const wchar_t * __restrict str, locale_t locale,
+ const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vswscanf_l(str, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
Index: lib/libc/stdio/vwscanf.c
===================================================================
--- lib/libc/stdio/vwscanf.c (revision 225653)
+++ lib/libc/stdio/vwscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,10 +35,15 @@
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
vwscanf(const wchar_t * __restrict fmt, va_list ap)
{
-
return (vfwscanf(stdin, fmt, ap));
}
+int
+vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwscanf_l(stdin, locale, fmt, ap));
+}
Index: lib/libc/stdio/sscanf.c
===================================================================
--- lib/libc/stdio/sscanf.c (revision 225653)
+++ lib/libc/stdio/sscanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,6 +44,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <xlocale.h>
#include "local.h"
int
@@ -52,3 +58,15 @@
va_end(ap);
return (ret);
}
+int
+sscanf_l(const char * __restrict str, locale_t locale,
+ char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsscanf_l(str, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/fgetwc.c
===================================================================
--- lib/libc/stdio/fgetwc.c (revision 225653)
+++ lib/libc/stdio/fgetwc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,31 +41,39 @@
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
+#include "xlocale_private.h"
/*
* MT-safe version.
*/
wint_t
-fgetwc(FILE *fp)
+fgetwc_l(FILE *fp, locale_t locale)
{
wint_t r;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
- r = __fgetwc(fp);
+ r = __fgetwc(fp, locale);
FUNLOCKFILE(fp);
return (r);
}
+wint_t
+fgetwc(FILE *fp)
+{
+ return fgetwc_l(fp, __get_locale());
+}
/*
* Non-MT-safe version.
*/
wint_t
-__fgetwc(FILE *fp)
+__fgetwc(FILE *fp, locale_t locale)
{
wchar_t wc;
size_t nconv;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
if (fp->_r <= 0 && __srefill(fp))
return (WEOF);
@@ -71,7 +84,7 @@
return (wc);
}
do {
- nconv = __mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate);
+ nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate);
if (nconv == (size_t)-1)
break;
else if (nconv == (size_t)-2)
Index: lib/libc/stdio/vfscanf.c
===================================================================
--- lib/libc/stdio/vfscanf.c (revision 225653)
+++ lib/libc/stdio/vfscanf.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
@@ -51,6 +56,7 @@
#include "collate.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#ifndef NO_FLOATING_POINT
#include <locale.h>
@@ -95,11 +101,12 @@
static const u_char *__sccl(char *, const u_char *);
#ifndef NO_FLOATING_POINT
-static int parsefloat(FILE *, char *, char *);
+static int parsefloat(FILE *, char *, char *, locale_t);
#endif
__weak_reference(__vfscanf, vfscanf);
+
/*
* __vfscanf - MT-safe version
*/
@@ -109,16 +116,27 @@
int ret;
FLOCKFILE(fp);
- ret = __svfscanf(fp, fmt0, ap);
+ ret = __svfscanf(fp, __get_locale(), fmt0, ap);
FUNLOCKFILE(fp);
return (ret);
}
+int
+vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
+{
+ int ret;
+ FIX_LOCALE(locale);
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, locale, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
/*
* __svfscanf - non-MT-safe version of __vfscanf
*/
int
-__svfscanf(FILE *fp, const char *fmt0, va_list ap)
+__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
{
const u_char *fmt = (const u_char *)fmt0;
int c; /* character from format, or conversion */
@@ -455,8 +473,7 @@
!ccltab[wctob(*wcp)]) {
while (n != 0) {
n--;
- __ungetc(buf[n],
- fp);
+ __ungetc(buf[n], fp);
}
break;
}
@@ -555,8 +572,7 @@
if (iswspace(*wcp)) {
while (n != 0) {
n--;
- __ungetc(buf[n],
- fp);
+ __ungetc(buf[n], fp);
}
break;
}
@@ -733,9 +749,9 @@
*p = 0;
if ((flags & UNSIGNED) == 0)
- res = strtoimax(buf, (char **)NULL, base);
+ res = strtoimax_l(buf, (char **)NULL, base, locale);
else
- res = strtoumax(buf, (char **)NULL, base);
+ res = strtoumax_l(buf, (char **)NULL, base, locale);
if (flags & POINTER)
*va_arg(ap, void **) =
(void *)(uintptr_t)res;
@@ -766,17 +782,17 @@
/* scan a floating point number as if by strtod */
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
- if ((width = parsefloat(fp, buf, buf + width)) == 0)
+ if ((width = parsefloat(fp, buf, buf + width, locale)) == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
if (flags & LONGDBL) {
- long double res = strtold(buf, &p);
+ long double res = strtold_l(buf, &p, locale);
*va_arg(ap, long double *) = res;
} else if (flags & LONG) {
- double res = strtod(buf, &p);
+ double res = strtod_l(buf, &p, locale);
*va_arg(ap, double *) = res;
} else {
- float res = strtof(buf, &p);
+ float res = strtof_l(buf, &p, locale);
*va_arg(ap, float *) = res;
}
nassigned++;
@@ -805,6 +821,8 @@
const u_char *fmt;
{
int c, n, v, i;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
/* first `clear' the whole table */
c = *fmt++; /* first char hat => negated scanset */
@@ -858,8 +876,8 @@
*/
n = *fmt;
if (n == ']'
- || (__collate_load_error ? n < c :
- __collate_range_cmp (n, c) < 0
+ || (table->__collate_load_error ? n < c :
+ __collate_range_cmp (table, n, c) < 0
)
) {
c = '-';
@@ -867,14 +885,14 @@
}
fmt++;
/* fill in the range */
- if (__collate_load_error) {
+ if (table->__collate_load_error) {
do {
tab[++c] = v;
} while (c < n);
} else {
for (i = 0; i < 256; i ++)
- if ( __collate_range_cmp (c, i) < 0
- && __collate_range_cmp (i, n) <= 0
+ if ( __collate_range_cmp (table, c, i) < 0
+ && __collate_range_cmp (table, i, n) <= 0
)
tab[i] = v;
}
@@ -908,7 +926,7 @@
#ifndef NO_FLOATING_POINT
static int
-parsefloat(FILE *fp, char *buf, char *end)
+parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
{
char *commit, *p;
int infnanpos = 0, decptpos = 0;
@@ -917,7 +935,7 @@
S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
} state = S_START;
unsigned char c;
- const char *decpt = localeconv()->decimal_point;
+ const char *decpt = localeconv_l(locale)->decimal_point;
_Bool gotmantdig = 0, ishex = 0;
/*
Index: lib/libc/stdio/fgetws.c
===================================================================
--- lib/libc/stdio/fgetws.c (revision 225653)
+++ lib/libc/stdio/fgetws.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,12 +43,14 @@
#include "mblocal.h"
wchar_t *
-fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale)
{
wchar_t *wsp;
size_t nconv;
const char *src;
unsigned char *nl;
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
@@ -60,7 +67,7 @@
do {
src = fp->_p;
nl = memchr(fp->_p, '\n', fp->_r);
- nconv = __mbsnrtowcs(wsp, &src,
+ nconv = l->__mbsnrtowcs(wsp, &src,
nl != NULL ? (nl - fp->_p + 1) : fp->_r,
n - 1, &fp->_mbstate);
if (nconv == (size_t)-1)
@@ -86,7 +93,7 @@
if (wsp == ws)
/* EOF */
goto error;
- if (!__mbsinit(&fp->_mbstate))
+ if (!l->__mbsinit(&fp->_mbstate))
/* Incomplete character */
goto error;
*wsp = L'\0';
@@ -98,3 +105,8 @@
FUNLOCKFILE(fp);
return (NULL);
}
+wchar_t *
+fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+{
+ return fgetws_l(ws, n, fp, __get_locale());
+}
Index: lib/libc/stdio/vasprintf.c
===================================================================
--- lib/libc/stdio/vasprintf.c (revision 225653)
+++ lib/libc/stdio/vasprintf.c (working copy)
@@ -4,6 +4,11 @@
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
+#include "xlocale_private.h"
#include "local.h"
int
-vasprintf(char **str, const char *fmt, __va_list ap)
+vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
{
FILE f = FAKE_FILE;
int ret;
+ FIX_LOCALE(locale);
f._flags = __SWR | __SSTR | __SALC;
f._bf._base = f._p = malloc(128);
@@ -49,7 +56,7 @@
return (-1);
}
f._bf._size = f._w = 127; /* Leave room for the NUL */
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
if (ret < 0) {
free(f._bf._base);
*str = NULL;
@@ -60,3 +67,8 @@
*str = (char *)f._bf._base;
return (ret);
}
+int
+vasprintf(char **str, const char *fmt, __va_list ap)
+{
+ return vasprintf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vfwscanf.c
===================================================================
--- lib/libc/stdio/vfwscanf.c (revision 225653)
+++ lib/libc/stdio/vfwscanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -53,11 +58,8 @@
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
-#ifndef NO_FLOATING_POINT
-#include <locale.h>
-#endif
-
#define BUF 513 /* Maximum length of numeric string. */
/*
@@ -96,7 +98,7 @@
#define CT_FLOAT 4 /* %[efgEFG] conversion */
#ifndef NO_FLOATING_POINT
-static int parsefloat(FILE *, wchar_t *, wchar_t *);
+static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t);
#endif
#define INCCL(_c) \
@@ -109,22 +111,30 @@
* MT-safe version.
*/
int
-vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+vfwscanf_l(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
{
int ret;
+ FIX_LOCALE(locale);
FLOCKFILE(fp);
ORIENT(fp, 1);
- ret = __vfwscanf(fp, fmt, ap);
+ ret = __vfwscanf(fp, locale, fmt, ap);
FUNLOCKFILE(fp);
return (ret);
}
+int
+vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+{
+ return vfwscanf_l(fp, __get_locale(), fmt, ap);
+}
/*
* Non-MT-safe version.
*/
int
-__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+__vfwscanf(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
{
wint_t c; /* character from format, or conversion */
size_t width; /* field width, or 0 */
@@ -159,11 +169,11 @@
if (c == 0)
return (nassigned);
if (iswspace(c)) {
- while ((c = __fgetwc(fp)) != WEOF &&
- iswspace(c))
+ while ((c = __fgetwc(fp, locale)) != WEOF &&
+ iswspace_l(c, locale))
;
if (c != WEOF)
- __ungetwc(c, fp);
+ __ungetwc(c, fp, locale);
continue;
}
if (c != '%')
@@ -178,10 +188,10 @@
switch (c) {
case '%':
literal:
- if ((wi = __fgetwc(fp)) == WEOF)
+ if ((wi = __fgetwc(fp, locale)) == WEOF)
goto input_failure;
if (wi != c) {
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
goto input_failure;
}
nread++;
@@ -341,11 +351,11 @@
* that suppress this.
*/
if ((flags & NOSKIP) == 0) {
- while ((wi = __fgetwc(fp)) != WEOF && iswspace(wi))
+ while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi))
nread++;
if (wi == WEOF)
goto input_failure;
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
}
/*
@@ -362,7 +372,7 @@
p = va_arg(ap, wchar_t *);
n = 0;
while (width-- != 0 &&
- (wi = __fgetwc(fp)) != WEOF) {
+ (wi = __fgetwc(fp, locale)) != WEOF) {
if (!(flags & SUPPRESS))
*p++ = (wchar_t)wi;
n++;
@@ -378,7 +388,7 @@
n = 0;
mbs = initial_mbs;
while (width != 0 &&
- (wi = __fgetwc(fp)) != WEOF) {
+ (wi = __fgetwc(fp, locale)) != WEOF) {
if (width >= MB_CUR_MAX &&
!(flags & SUPPRESS)) {
nconv = wcrtomb(mbp, wi, &mbs);
@@ -390,7 +400,7 @@
if (nconv == (size_t)-1)
goto input_failure;
if (nconv > width) {
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
break;
}
if (!(flags & SUPPRESS))
@@ -418,20 +428,20 @@
/* take only those things in the class */
if ((flags & SUPPRESS) && (flags & LONG)) {
n = 0;
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && INCCL(wi))
n++;
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
if (n == 0)
goto match_failure;
} else if (flags & LONG) {
p0 = p = va_arg(ap, wchar_t *);
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && INCCL(wi))
*p++ = (wchar_t)wi;
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
n = p - p0;
if (n == 0)
goto match_failure;
@@ -442,7 +452,7 @@
mbp = va_arg(ap, char *);
n = 0;
mbs = initial_mbs;
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width != 0 && INCCL(wi)) {
if (width >= MB_CUR_MAX &&
!(flags & SUPPRESS)) {
@@ -466,7 +476,7 @@
n++;
}
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
if (!(flags & SUPPRESS)) {
*mbp = 0;
nassigned++;
@@ -481,29 +491,29 @@
if (width == 0)
width = (size_t)~0;
if ((flags & SUPPRESS) && (flags & LONG)) {
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 &&
!iswspace(wi))
nread++;
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
} else if (flags & LONG) {
p0 = p = va_arg(ap, wchar_t *);
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 &&
!iswspace(wi)) {
*p++ = (wchar_t)wi;
nread++;
}
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
*p = '\0';
nassigned++;
} else {
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
mbs = initial_mbs;
- while ((wi = __fgetwc(fp)) != WEOF &&
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
width != 0 &&
!iswspace(wi)) {
if (width >= MB_CUR_MAX &&
@@ -528,7 +538,7 @@
nread++;
}
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
if (!(flags & SUPPRESS)) {
*mbp = 0;
nassigned++;
@@ -544,7 +554,7 @@
width = sizeof(buf) / sizeof(*buf) - 1;
flags |= SIGNOK | NDIGITS | NZDIGITS;
for (p = buf; width; width--) {
- c = __fgetwc(fp);
+ c = __fgetwc(fp, locale);
/*
* Switch on the character; `goto ok'
* if we accept it as a part of number.
@@ -628,7 +638,7 @@
* for a number. Stop accumulating digits.
*/
if (c != WEOF)
- __ungetwc(c, fp);
+ __ungetwc(c, fp, locale);
break;
ok:
/*
@@ -644,13 +654,13 @@
*/
if (flags & NDIGITS) {
if (p > buf)
- __ungetwc(*--p, fp);
+ __ungetwc(*--p, fp, locale);
goto match_failure;
}
c = p[-1];
if (c == 'x' || c == 'X') {
--p;
- __ungetwc(c, fp);
+ __ungetwc(c, fp, locale);
}
if ((flags & SUPPRESS) == 0) {
uintmax_t res;
@@ -691,7 +701,7 @@
if (width == 0 || width > sizeof(buf) /
sizeof(*buf) - 1)
width = sizeof(buf) / sizeof(*buf) - 1;
- if ((width = parsefloat(fp, buf, buf + width)) == 0)
+ if ((width = parsefloat(fp, buf, buf + width, locale)) == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
if (flags & LONGDBL) {
@@ -720,7 +730,7 @@
#ifndef NO_FLOATING_POINT
static int
-parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
+parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale)
{
mbstate_t mbs;
size_t nconv;
@@ -751,7 +761,7 @@
commit = buf - 1;
c = WEOF;
for (p = buf; p < end; ) {
- if ((c = __fgetwc(fp)) == WEOF)
+ if ((c = __fgetwc(fp, locale)) == WEOF)
break;
reswitch:
switch (state) {
@@ -871,9 +881,9 @@
parsedone:
if (c != WEOF)
- __ungetwc(c, fp);
+ __ungetwc(c, fp, locale);
while (commit < --p)
- __ungetwc(*p, fp);
+ __ungetwc(*p, fp, locale);
*++commit = '\0';
return (commit - buf);
}
Index: lib/libc/stdio/asprintf.c
===================================================================
--- lib/libc/stdio/asprintf.c (revision 225653)
+++ lib/libc/stdio/asprintf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,6 +40,7 @@
#include <stdio.h>
#include <stdarg.h>
+#include <xlocale.h>
int
asprintf(char ** __restrict s, char const * __restrict fmt, ...)
@@ -47,3 +53,15 @@
va_end(ap);
return (ret);
}
+int
+asprintf_l(char ** __restrict s, locale_t locale, char const * __restrict fmt,
+ ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vasprintf_l(s, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
Index: lib/libc/stdio/vswscanf.c
===================================================================
--- lib/libc/stdio/vswscanf.c (revision 225653)
+++ lib/libc/stdio/vswscanf.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -46,6 +51,7 @@
#include <string.h>
#include <wchar.h>
#include "local.h"
+#include "xlocale_private.h"
static int eofread(void *, char *, int);
@@ -57,8 +63,8 @@
}
int
-vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
- va_list ap)
+vswscanf_l(const wchar_t * __restrict str, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -67,6 +73,7 @@
size_t mlen;
int r;
const wchar_t *strp;
+ FIX_LOCALE(locale);
/*
* XXX Convert the wide character string to multibyte, which
@@ -76,7 +83,7 @@
return (EOF);
mbs = initial;
strp = str;
- if ((mlen = wcsrtombs(mbstr, &strp, SIZE_T_MAX, &mbs)) == (size_t)-1) {
+ if ((mlen = wcsrtombs_l(mbstr, &strp, SIZE_T_MAX, &mbs, locale)) == (size_t)-1) {
free(mbstr);
return (EOF);
}
@@ -84,8 +91,14 @@
f._bf._base = f._p = (unsigned char *)mbstr;
f._bf._size = f._r = mlen;
f._read = eofread;
- r = __vfwscanf(&f, fmt, ap);
+ r = __vfwscanf(&f, locale, fmt, ap);
free(mbstr);
return (r);
}
+int
+vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
+ va_list ap)
+{
+ return vswscanf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/locale/collate.c
===================================================================
--- lib/libc/locale/collate.c (revision 225653)
+++ lib/libc/locale/collate.c (working copy)
@@ -3,6 +3,16 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -44,24 +54,77 @@
#include "libc_private.h"
-int __collate_load_error = 1;
-int __collate_substitute_nontrivial;
+/*
+ * To avoid modifying the original (single-threaded) code too much, we'll just
+ * define the old globals as fields inside the table.
+ *
+ * We also modify the collation table test functions to search the thread-local
+ * table first and the global table second.
+ */
+#define __collate_load_error (table->__collate_load_error)
+#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
+#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
+#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
+#define __collate_chain_pri_table (table->__collate_chain_pri_table)
-u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
-struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
-struct __collate_st_chain_pri *__collate_chain_pri_table;
+struct xlocale_collate __xlocale_global_collate = {
+ {{0}, "C"}, 1, 0
+};
+
+static struct xlocale_collate c_collate= {
+ {{0}, "C"}, 1, 0
+};
+
void __collate_err(int ex, const char *f) __dead2;
int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
+
+static void
+destruct_collate(void *t)
+{
+ struct xlocale_collate *table = t;
+ if (__collate_chain_pri_table) {
+ free(__collate_chain_pri_table);
+ }
+ free(t);
+}
+
+void *
+__collate_load(const char *encoding, locale_t unused)
+{
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ return &c_collate;
+ }
+ struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 1);
+ table->header.header.destructor = destruct_collate;
+ // FIXME: Make sure that _LDP_CACHE is never returned. We should be doing
+ // the caching outside of this section
+ if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
+ xlocale_release(table);
+ return NULL;
+ }
+ return table;
+}
+
+/**
+ * Load the collation tables for the specified encoding into the global table.
+ */
+int
__collate_load_tables(const char *encoding)
{
+ return __collate_load_tables_l(encoding, &__xlocale_global_collate);
+}
+
+int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
+{
FILE *fp;
int i, saverr, chains;
uint32_t u32;
char strbuf[STR_LEN], buf[PATH_MAX];
void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
- static char collate_encoding[ENCODING_LEN + 1];
/* 'encoding' must be already checked. */
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
@@ -69,18 +132,6 @@
return (_LDP_CACHE);
}
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (strcmp(encoding, collate_encoding) == 0) {
- __collate_load_error = 0;
- return (_LDP_CACHE);
- }
-
- /*
- * Slurp the locale file into the cache.
- */
-
/* 'PathLocale' must be already set & checked. */
/* Range checking not needed, encoding has fixed size */
(void)strcpy(buf, _PathLocale);
@@ -165,7 +216,6 @@
sizeof(*__collate_chain_pri_table), chains, fp);
(void)fclose(fp);
- (void)strcpy(collate_encoding, encoding);
if (__collate_substitute_table_ptr != NULL)
free(__collate_substitute_table_ptr);
__collate_substitute_table_ptr = TMP_substitute_table;
@@ -201,7 +251,7 @@
}
u_char *
-__collate_substitute(const u_char *s)
+__collate_substitute(struct xlocale_collate *table, const u_char *s)
{
int dest_len, len, nlen;
int delta = strlen(s);
@@ -228,7 +278,7 @@
}
void
-__collate_lookup(const u_char *t, int *len, int *prim, int *sec)
+__collate_lookup(struct xlocale_collate *table, const u_char *t, int *len, int *prim, int *sec)
{
struct __collate_st_chain_pri *p2;
Index: lib/libc/locale/xlocale.c
===================================================================
--- lib/libc/locale/xlocale.c (revision 0)
+++ lib/libc/locale/xlocale.c (revision 0)
@@ -0,0 +1,312 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "libc_private.h"
+#include "xlocale_private.h"
+
+/**
+ * Each locale loader declares a global component. This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+/*
+ * Private functions in setlocale.c.
+ */
+const char *
+__get_locale_env(int category);
+int
+__detect_path_locale(void);
+
+struct _xlocale __xlocale_global_locale = {
+ {0},
+ {
+ &__xlocale_global_collate,
+ &__xlocale_global_ctype,
+ &__xlocale_global_monetary,
+ &__xlocale_global_numeric,
+ &__xlocale_global_time,
+ &__xlocale_global_messages
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+ __collate_load,
+ __ctype_load,
+ __monetary_load,
+ __numeric_load,
+ __time_load,
+ __messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void init_key(void)
+{
+ pthread_key_create(&locale_info_key, xlocale_release);
+ pthread_setspecific(locale_info_key, (void*)42);
+ if (pthread_getspecific(locale_info_key) == (void*)42) {
+ pthread_setspecific(locale_info_key, 0);
+ } else {
+ fake_tls = 1;
+ }
+ __detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+ _once(&once_control, init_key);
+
+ return fake_tls ? thread_local_locale :
+ pthread_getspecific(locale_info_key);
+}
+
+locale_t
+__get_locale(void)
+{
+ locale_t l = get_thread_locale();
+ return l ? l : &__xlocale_global_locale;
+
+}
+
+static void
+set_thread_locale(locale_t loc)
+{
+ pthread_once(&once_control, init_key);
+
+ if (NULL != loc) {
+ xlocale_retain((struct xlocale_refcounted*)loc);
+ }
+ locale_t old = pthread_getspecific(locale_info_key);
+ if ((NULL != old) && (loc != old)) {
+ xlocale_release((struct xlocale_refcounted*)old);
+ }
+ if (fake_tls) {
+ thread_local_locale = loc;
+ } else {
+ pthread_setspecific(locale_info_key, loc);
+ }
+}
+
+/**
+ * Clean up a locale, once its reference count reaches zero. This function is
+ * called by xlocale_release(), it should not be called directly.
+ */
+static void
+destruct_locale(void *l)
+{
+ locale_t loc = l;
+ for (int type=0 ; type<XLC_LAST ; type++) {
+ if (loc->components[type]) {
+ xlocale_release(loc->components[type]);
+ }
+ }
+ if (loc->csym) {
+ free(loc->csym);
+ }
+ free(l);
+}
+
+/**
+ * Allocates a new, uninitialised, locale.
+ */
+static locale_t
+alloc_locale(void)
+{
+ locale_t new = calloc(sizeof(struct _xlocale), 1);
+ new->header.destructor = destruct_locale;
+ new->monetary_locale_changed = 1;
+ new->numeric_locale_changed = 1;
+ return new;
+}
+static void
+copyflags(locale_t new, locale_t old)
+{
+ new->using_monetary_locale = old->using_monetary_locale;
+ new->using_numeric_locale = old->using_numeric_locale;
+ new->using_time_locale = old->using_time_locale;
+ new->using_messages_locale = old->using_messages_locale;
+}
+
+static int dupcomponent(int type, locale_t base, locale_t new)
+{
+ /* Always copy from the global locale, since it has mutable components. */
+ struct xlocale_component *src = base->components[type];
+ if (&__xlocale_global_locale == base) {
+ new->components[type] = constructors[type](src->locale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, src->locale, ENCODING_LEN);
+ }
+ } else {
+ new->components[type] = xlocale_retain(base->components[type]);
+ }
+ return 0 != new->components[type];
+}
+
+/*
+ * Public interfaces. These are the five public functions described by the
+ * xlocale interface.
+ */
+
+locale_t newlocale(int mask, const char *locale, locale_t base)
+{
+ int type;
+ const char *realLocale = locale;
+ int useenv = 0;
+ int success = 1;
+
+ _once(&once_control, init_key);
+
+ locale_t new = alloc_locale();
+ if (NULL == new) {
+ return NULL;
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ if (NULL == locale) {
+ realLocale = "C";
+ } else if ('\0' == locale[0]) {
+ useenv = 1;
+ }
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ if (mask & 1) {
+ if (useenv) {
+ realLocale = __get_locale_env(type);
+ }
+ new->components[type] = constructors[type](realLocale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, realLocale, ENCODING_LEN);
+ } else {
+ success = 0;
+ }
+ } else {
+ if (!dupcomponent(type, base, new)) {
+ success = 0;
+ }
+ }
+ mask >>= 1;
+ }
+ if (0 == success) {
+ xlocale_release(new);
+ new = NULL;
+ }
+
+ return new;
+}
+
+locale_t duplocale(locale_t base)
+{
+ locale_t new = alloc_locale();
+ int type;
+
+ _once(&once_control, init_key);
+
+ if (NULL == new) {
+ return NULL;
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ dupcomponent(type, base, new);
+ }
+
+ return new;
+}
+
+/*
+ * Free a locale_t. This is quite a poorly named function. It actually
+ * disclaims a reference to a locale_t, rather than freeing it.
+ */
+int
+freelocale(locale_t loc)
+{
+ /* Fail if we're passed something that isn't a locale. */
+ if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) {
+ return -1;
+ }
+ /* If we're passed the global locale, pretend that we freed it but don't
+ * actually do anything. */
+ if (&__xlocale_global_locale == loc) {
+ return 0;
+ }
+ xlocale_release(loc);
+ return 0;
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc)
+{
+ FIX_LOCALE(loc);
+ for (int type=0 ; type<XLC_LAST ; type++) {
+ if (mask & 1) {
+ return loc->components[type]->locale;
+ }
+ mask >>= 1;
+ }
+ return NULL;
+}
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t uselocale(locale_t loc)
+{
+ locale_t old = get_thread_locale();
+ if (NULL != loc) {
+ if (LC_GLOBAL_LOCALE == loc) {
+ loc = NULL;
+ }
+ set_thread_locale(loc);
+ }
+ return old ? old : LC_GLOBAL_LOCALE;
+}
+
Index: lib/libc/locale/ascii.c
===================================================================
--- lib/libc/locale/ascii.c (revision 225653)
+++ lib/libc/locale/ascii.c (working copy)
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -56,17 +61,17 @@
size_t, size_t, mbstate_t * __restrict);
int
-_ascii_init(_RuneLocale *rl)
+_ascii_init(struct xlocale_ctype *l,_RuneLocale *rl)
{
- __mbrtowc = _ascii_mbrtowc;
- __mbsinit = _ascii_mbsinit;
- __mbsnrtowcs = _ascii_mbsnrtowcs;
- __wcrtomb = _ascii_wcrtomb;
- __wcsnrtombs = _ascii_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 1;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _ascii_mbrtowc;
+ l->__mbsinit = _ascii_mbsinit;
+ l->__mbsnrtowcs = _ascii_mbsnrtowcs;
+ l->__wcrtomb = _ascii_wcrtomb;
+ l->__wcsnrtombs = _ascii_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 128;
return(0);
}
Index: lib/libc/locale/collate.h
===================================================================
--- lib/libc/locale/collate.h (revision 225653)
+++ lib/libc/locale/collate.h (working copy)
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,6 +38,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
+#include "xlocale_private.h"
#define STR_LEN 10
#define TABLE_SIZE 100
@@ -47,20 +53,26 @@
int prim, sec;
};
-extern int __collate_load_error;
-extern int __collate_substitute_nontrivial;
#define __collate_substitute_table (*__collate_substitute_table_ptr)
-extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
-extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
-extern struct __collate_st_chain_pri *__collate_chain_pri_table;
+struct xlocale_collate {
+ struct xlocale_component header;
+ int __collate_load_error;
+ int __collate_substitute_nontrivial;
+
+ u_char (*__collate_substitute_table_ptr)[UCHAR_MAX + 1][STR_LEN];
+ struct __collate_st_char_pri (*__collate_char_pri_table_ptr)[UCHAR_MAX + 1];
+ struct __collate_st_chain_pri *__collate_chain_pri_table;
+};
+
+
__BEGIN_DECLS
u_char *__collate_strdup(u_char *);
-u_char *__collate_substitute(const u_char *);
+u_char *__collate_substitute(struct xlocale_collate *, const u_char *);
int __collate_load_tables(const char *);
-void __collate_lookup(const u_char *, int *, int *, int *);
-int __collate_range_cmp(int, int);
+void __collate_lookup(struct xlocale_collate *, const u_char *, int *, int *, int *);
+int __collate_range_cmp(struct xlocale_collate *, int, int);
#ifdef COLLATE_DEBUG
void __collate_print_tables(void);
#endif
Index: lib/libc/locale/wcstoumax.c
===================================================================
--- lib/libc/locale/wcstoumax.c (revision 225653)
+++ lib/libc/locale/wcstoumax.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a uintmax_t integer.
*/
uintmax_t
-wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@
cutlim = UINTMAX_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -120,3 +127,9 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+uintmax_t
+wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoumax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/mbtowc.c
===================================================================
--- lib/libc/locale/mbtowc.c (revision 225653)
+++ lib/libc/locale/mbtowc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,19 +37,24 @@
#include "mblocal.h"
int
-mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+mbtowc_l(wchar_t * __restrict pwc, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->mbtowc = initial;
return (0);
}
- rval = __mbrtowc(pwc, s, n, &mbs);
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, &locale->mbtowc);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+int
+mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+{
+ return mbtowc_l(pwc, s, n, __get_locale());
+}
Index: lib/libc/locale/wcstoul.c
===================================================================
--- lib/libc/locale/wcstoul.c (revision 225653)
+++ lib/libc/locale/wcstoul.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,18 +40,21 @@
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long integer.
*/
unsigned long
-wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -79,8 +87,8 @@
cutlim = ULONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -113,3 +121,8 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long
+wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoul_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/gb2312.c
===================================================================
--- lib/libc/locale/gb2312.c (revision 225653)
+++ lib/libc/locale/gb2312.c (working copy)
@@ -3,6 +3,11 @@
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,8 +40,6 @@
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB2312_mbsinit(const mbstate_t *);
@@ -49,15 +52,15 @@
} _GB2312State;
int
-_GB2312_init(_RuneLocale *rl)
+_GB2312_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- _CurrentRuneLocale = rl;
- __mbrtowc = _GB2312_mbrtowc;
- __wcrtomb = _GB2312_wcrtomb;
- __mbsinit = _GB2312_mbsinit;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->runes = rl;
+ l->__mbrtowc = _GB2312_mbrtowc;
+ l->__wcrtomb = _GB2312_wcrtomb;
+ l->__mbsinit = _GB2312_mbsinit;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
Index: lib/libc/locale/Symbol.map
===================================================================
--- lib/libc/locale/Symbol.map (revision 225653)
+++ lib/libc/locale/Symbol.map (working copy)
@@ -99,6 +99,98 @@
iswctype;
wctype;
wcwidth;
+ newlocale;
+ duplocale;
+ freelocale;
+ querylocale;
+ uselocale;
+ __getCurrentRuneLocale;
+ btowc_l;
+ localeconv_l;
+ mblen_l;
+ mbrlen_l;
+ mbrtowc_l;
+ mbsinit_l;
+ mbsnrtowcs_l;
+ mbsrtowcs_l;
+ mbstowcs_l;
+ mbtowc_l;
+ nl_langinfo_l;
+ strcoll_l;
+ strfmon_l;
+ strftime_l;
+ strptime_l;
+ strxfrm_l;
+ wcrtomb_l;
+ wcscoll_l;
+ wcsnrtombs_l;
+ wcsrtombs_l;
+ wcstombs_l;
+ wcsxfrm_l;
+ wctob_l;
+ wctomb_l;
+ ___tolower_l;
+ ___toupper_l;
+ ___runetype_l;
+ digittoint_l;
+ isalnum_l;
+ isalpha_l;
+ isblank_l;
+ iscntrl_l;
+ isdigit_l;
+ isgraph_l;
+ ishexnumber_l;
+ isideogram_l;
+ islower_l;
+ isnumber_l;
+ isphonogram_l;
+ isprint_l;
+ ispunct_l;
+ isrune_l;
+ isspace_l;
+ isspecial_l;
+ isupper_l;
+ isxdigit_l;
+ tolower_l;
+ toupper_l;
+ iswalnum_l;
+ iswalpha_l;
+ iswblank_l;
+ iswcntrl_l;
+ iswdigit_l;
+ iswgraph_l;
+ iswhexnumber_l;
+ iswideogram_l;
+ iswlower_l;
+ iswnumber_l;
+ iswphonogram_l;
+ iswprint_l;
+ iswpunct_l;
+ iswrune_l;
+ iswspace_l;
+ iswspecial_l;
+ iswupper_l;
+ iswxdigit_l;
+ towlower_l;
+ towupper_l;
+ iswctype_l;
+ wctype_l;
+ nextwctype_l;
+ ___mb_cur_max;
+ ___mb_cur_max_l;
+ towctrans_l;
+ wctrans_l;
+ wcsftime_l;
+ wcstod_l;
+ wcstof_l;
+ wcstoimax_l;
+ wcstol_l;
+ wcstold_l;
+ wcstoll_l;
+ wcstoul_l;
+ wcstoull_l;
+ wcstoumax_l;
+ __runes_for_locale;
};
FBSDprivate_1.0 {
Index: lib/libc/locale/mblocal.h
===================================================================
--- lib/libc/locale/mblocal.h (revision 225653)
+++ lib/libc/locale/mblocal.h (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,35 +35,45 @@
#define _MBLOCAL_H_
#include <runetype.h>
+#include "xlocale_private.h"
+
/*
- * Rune initialization function prototypes.
+ * Conversion function pointers for current encoding.
*/
-int _none_init(_RuneLocale *);
-int _ascii_init(_RuneLocale *);
-int _UTF8_init(_RuneLocale *);
-int _EUC_init(_RuneLocale *);
-int _GB18030_init(_RuneLocale *);
-int _GB2312_init(_RuneLocale *);
-int _GBK_init(_RuneLocale *);
-int _BIG5_init(_RuneLocale *);
-int _MSKanji_init(_RuneLocale *);
+struct xlocale_ctype {
+ struct xlocale_component header;
+ _RuneLocale *runes;
+ size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+ int (*__mbsinit)(const mbstate_t *);
+ size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
+ size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ int __mb_cur_max;
+ int __mb_sb_limit;
+};
+#define XLOCALE_CTYPE(x) ((struct xlocale_ctype*)(x)->components[XLC_CTYPE])
+extern struct xlocale_ctype __xlocale_global_ctype;
/*
- * Conversion function pointers for current encoding.
+ * Rune initialization function prototypes.
*/
-extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
- size_t, mbstate_t * __restrict);
-extern int (*__mbsinit)(const mbstate_t *);
-extern size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
-extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
-extern size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+int _none_init(struct xlocale_ctype *, _RuneLocale *);
+int _ascii_init(struct xlocale_ctype *, _RuneLocale *);
+int _UTF8_init(struct xlocale_ctype *, _RuneLocale *);
+int _EUC_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB18030_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB2312_init(struct xlocale_ctype *, _RuneLocale *);
+int _GBK_init(struct xlocale_ctype *, _RuneLocale *);
+int _BIG5_init(struct xlocale_ctype *, _RuneLocale *);
+int _MSKanji_init(struct xlocale_ctype *, _RuneLocale *);
extern size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
#endif /* _MBLOCAL_H_ */
Index: lib/libc/locale/DESIGN.xlocale
===================================================================
--- lib/libc/locale/DESIGN.xlocale (revision 0)
+++ lib/libc/locale/DESIGN.xlocale (revision 0)
@@ -0,0 +1,157 @@
+Design of xlocale
+=================
+
+The xlocale APIs come from Darwin, although a subset is now part of POSIX 2008.
+They fall into two broad categories:
+
+- Manipulation of per-thread locales (POSIX)
+- Locale-aware functions taking an explicit locale argument (Darwin)
+
+This document describes the implementation of these APIs for FreeBSD.
+
+Goals
+-----
+
+The overall goal of this implementation is to be compatible with the Darwin
+version. Additionally, it should include minimal changes to the existing
+locale code. A lot of the existing locale code originates with 4BSD or earlier
+and has had over a decade of testing. Replacing this code, unless absolutely
+necessary, gives us the potential for more bugs without much benefit.
+
+With this in mind, various libc-private functions have been modified to take a
+locale_t parameter. This causes a compiler error if they are accidentally
+called without a locale. This approach was taken, rather than adding _l
+variants of these functions, to make it harder for accidental uses of the
+global-locale versions to slip in.
+
+Locale Objects
+--------------
+
+A locale is encapsulated in a `locale_t`, which is an opaque type: a pointer to
+a `struct _xlocale`. The name `_xlocale` is unfortunate, as it does not fit
+well with existing conventions, but is used because this is the name the Darwin
+implementation gives to this structure and so may be used by existing (bad) code.
+
+This structure should include all of the information corresponding to a locale.
+A locale_t is almost immutable after creation. There are no functions that modify it,
+and it can therefore be used without locking. It is the responsibility of the
+caller to ensure that a locale is not deallocated during a call that uses it.
+
+Each locale contains a number of components, one for each of the categories
+supported by `setlocale()`. These are likewise immutable after creation. This
+differs from the Darwin implementation, which includes a deprecated
+`setinvalidrune()` function that can modify the rune locale.
+
+The exception to these mutability rules is a set of `mbstate_t` flags stored
+with each locale. These are used by various functions that previously had a
+static local `mbstate_t` variable.
+
+The components are reference counted, and so can be aliased between locale
+objects. This makes copying locales very cheap.
+
+The Global Locale
+-----------------
+
+All locales and locale components are reference counted. The global locale,
+however, is special. It, and all of its components, are static and so no
+malloc() memory is required when using a single locale.
+
+This means that threads using the global locale are subject to the same
+constraints as with the pre-xlocale libc. Calls to any locale-aware functions
+in threads using the global locale, while modifying the global locale, have
+undefined behaviour.
+
+Because of this, we have to ensure that we always copy the components of the
+global locale, rather than alias them.
+
+It would be cleaner to simply remove the special treatment of the global locale
+and have a locale_t lazily allocated for the global context. This would cost a
+little more `malloc()` memory, so is not done in the initial version.
+
+Caching
+-------
+
+The existing locale implementation included several ad-hoc caching layers.
+None of these were thread safe. Caching is only really of use for supporting
+the pattern where the locale is briefly changed to something and then changed
+back.
+
+The current xlocale implementation removes the caching entirely. This pattern
+is not one that should be encouraged. If you need to make some calls with a
+modified locale, then you should use the _l suffix versions of the calls,
+rather than switch the global locale. If you do need to temporarily switch the
+locale and then switch it back, `uselocale()` provides a way of doing this very
+easily: It returns the old locale, which can then be passed to a subsequent
+call to `uselocale()` to restore it, without the need to load any locale data
+from the disk.
+
+If, in the future, it is determined that caching is beneficial, it can be added
+quite easily in xlocale.c. Given, however, that any locale-aware call is going
+to be a preparation for presenting data to the user, and so is invariably going
+to be part of an I/O operation, this seems like a case of premature
+optimisation.
+
+localeconv
+----------
+
+The `localeconv()` function is an exception to the immutable-after-creation
+rule. In the classic implementation, this function returns a pointer to some
+global storage, which is initialised with the data from the current locale.
+This is not possible in a multithreaded environment, with multiple locales.
+
+Instead, each locale contains a `struct lconv` that is lazily initialised on
+calls to `localeconv()`. This is not protected by any locking, however this is
+still safe on any machine where word-sized stores are atomic: two concurrent
+calls will write the same data into the structure.
+
+Explicit Locale Calls
+---------------------
+
+A large number of functions have been modified to take an explicit `locale_t`
+parameter. The old APIs are then reimplemented with a call to `__get_locale()`
+to supply the `locale_t` parameter. This is in line with the Darwin public
+APIs, but also simplifies the modifications to these functions. The
+`__get_locale()` function is now the only way to access the current locale
+within libc. All of the old globals have gone, so there is now a linker error
+if any functions attempt to use them.
+
+The ctype.h functions are a little different. These are not implemented in
+terms of their locale-aware versions, for performance reasons. Each of these
+is implemented as a short inline function.
+
+Differences to Darwin APIs
+--------------------------
+
+`strtoq_l()` and `strtouq_l() `are not provided. These are extensions to
+deprecated functions - we should not be encouraging people to use deprecated
+interfaces.
+
+Locale Placeholders
+-------------------
+
+The pointer values 0 and -1 have special meanings as `locale_t` values. Any
+public function that accepts a `locale_t` parameter must use the `FIX_LOCALE()`
+macro on it before using it. For efficiency, this can be emitted in functions
+which *only* use their locale parameter as an argument to another public
+function, as the callee will do the `FIX_LOCALE()` itself.
+
+Potential Improvements
+----------------------
+
+Currently, the current rune set is accessed via a function call. This makes it
+fairly expensive to use any of the ctype.h functions. We could improve this
+quite a lot by storing the rune locale data in a __thread-qualified variable.
+
+Several of the existing FreeBSD locale-aware functions appear to be wrong. For
+example, most of the `strto*()` family should probably use `digittoint_l()`,
+but instead they assume ASCII. These will break if using a character encoding
+that does not put numbers and the letters A-F in the same location as ASCII.
+Some functions, like `strcoll()` only work on single-byte encodings. No
+attempt has been made to fix existing limitations in the libc functions other
+than to add support for xlocale.
+
+Intuitively, setting a thread-local locale should ensure that all locale-aware
+functions can be used safely from that thread. In fact, this is not the case
+in either this implementation or the Darwin one. You must call `duplocale()`
+or `newlocale()` before calling `uselocale()`. This is a bit ugly, and it
+would be better if libc ensure that every thread had its own locale object.
Index: lib/libc/locale/mbsrtowcs.c
===================================================================
--- lib/libc/locale/mbsrtowcs.c (revision 225653)
+++ lib/libc/locale/mbsrtowcs.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,12 +39,17 @@
#include "mblocal.h"
size_t
+mbsrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+}
+size_t
mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+ return mbsrtowcs_l(dst, src, len, ps, __get_locale());
}
Index: lib/libc/locale/utf8.c
===================================================================
--- lib/libc/locale/utf8.c (revision 225653)
+++ lib/libc/locale/utf8.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -55,22 +60,22 @@
} _UTF8State;
int
-_UTF8_init(_RuneLocale *rl)
+_UTF8_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _UTF8_mbrtowc;
- __wcrtomb = _UTF8_wcrtomb;
- __mbsinit = _UTF8_mbsinit;
- __mbsnrtowcs = _UTF8_mbsnrtowcs;
- __wcsnrtombs = _UTF8_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 6;
+ l->__mbrtowc = _UTF8_mbrtowc;
+ l->__wcrtomb = _UTF8_wcrtomb;
+ l->__mbsinit = _UTF8_mbsinit;
+ l->__mbsnrtowcs = _UTF8_mbsnrtowcs;
+ l->__wcsnrtombs = _UTF8_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 6;
/*
* UCS-4 encoding used as the internal representation, so
* slots 0x0080-0x00FF are occuped and must be excluded
* from the single byte ctype by setting the limit.
*/
- __mb_sb_limit = 128;
+ l->__mb_sb_limit = 128;
return (0);
}
Index: lib/libc/locale/collcmp.c
===================================================================
--- lib/libc/locale/collcmp.c (revision 225653)
+++ lib/libc/locale/collcmp.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,17 +33,20 @@
__FBSDID("$FreeBSD$");
#include <string.h>
+#include <xlocale.h>
#include "collate.h"
/*
* Compare two characters using collate
*/
-int __collate_range_cmp(int c1, int c2)
+int __collate_range_cmp(struct xlocale_collate *table, int c1, int c2)
{
static char s1[2], s2[2];
s1[0] = c1;
s2[0] = c2;
- return (strcoll(s1, s2));
+ struct _xlocale l = {{0}};
+ l.components[XLC_COLLATE] = (struct xlocale_component *)table;
+ return (strcoll_l(s1, s2, &l));
}
Index: lib/libc/locale/Makefile.inc
===================================================================
--- lib/libc/locale/Makefile.inc (revision 225653)
+++ lib/libc/locale/Makefile.inc (working copy)
@@ -5,7 +5,7 @@
.PATH: ${.CURDIR}/${LIBC_ARCH}/locale ${.CURDIR}/locale
SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
- gb18030.c gb2312.c gbk.c isctype.c iswctype.c \
+ gb18030.c gb2312.c gbk.c ctype.c isctype.c iswctype.c \
ldpart.c lmessages.c lmonetary.c lnumeric.c localeconv.c mblen.c \
mbrlen.c \
mbrtowc.c mbsinit.c mbsnrtowcs.c \
@@ -20,7 +20,8 @@
wcstoimax.c wcstol.c wcstold.c wcstoll.c \
wcstombs.c \
wcstoul.c wcstoull.c wcstoumax.c wctob.c wctomb.c wctrans.c wctype.c \
- wcwidth.c
+ wcwidth.c\
+ xlocale.c
SYM_MAPS+=${.CURDIR}/locale/Symbol.map
Index: lib/libc/locale/wcstof.c
===================================================================
--- lib/libc/locale/wcstof.c (revision 225653)
+++ lib/libc/locale/wcstof.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,12 +35,14 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
float
-wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -43,13 +50,14 @@
char *buf, *end;
const wchar_t *wcp;
size_t len;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
+ while (iswspace_l(*nptr, locale))
nptr++;
wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -57,9 +65,9 @@
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
- val = strtof(buf, &end);
+ val = strtof_l(buf, &end, locale);
if (endptr != NULL)
*endptr = (wchar_t *)nptr + (end - buf);
@@ -68,3 +76,8 @@
return (val);
}
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstof_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/locale/localeconv.3
===================================================================
--- lib/libc/locale/localeconv.3 (revision 225653)
+++ lib/libc/locale/localeconv.3 (working copy)
@@ -44,6 +44,9 @@
.In locale.h
.Ft struct lconv *
.Fn localeconv "void"
+.In xlocale.h
+.Ft struct lconv *
+.Fn localeconv_l "locale_t locale"
.Sh DESCRIPTION
The
.Fn localeconv
@@ -196,6 +199,11 @@
A
.Dv CHAR_MAX
result similarly denotes an unavailable value.
+.Pp
+The
+.Fn localeconv_l
+function takes an explicit locale parameter. For more information, see
+.Xr xlocale 3 .
.Sh RETURN VALUES
The
.Fn localeconv
@@ -204,6 +212,13 @@
.Xr setlocale 3
or
.Fn localeconv .
+The return value for
+.Fn localeconv_l
+is stored with the locale. It will remain valid until a subsequent call to
+.Xr freelocale 3 .
+If a thread-local locale is in effect then the return value from
+.Fn localeconv
+will remain valid until the locale is destroyed.
.Sh ERRORS
No errors are defined.
.Sh SEE ALSO
Index: lib/libc/locale/mbsinit.c
===================================================================
--- lib/libc/locale/mbsinit.c (revision 225653)
+++ lib/libc/locale/mbsinit.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,8 +36,13 @@
#include "mblocal.h"
int
+mbsinit_l(const mbstate_t *ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (XLOCALE_CTYPE(locale)->__mbsinit(ps));
+}
+int
mbsinit(const mbstate_t *ps)
{
-
- return (__mbsinit(ps));
+ return mbsinit_l(ps, __get_locale());
}
Index: lib/libc/locale/wcwidth.c
===================================================================
--- lib/libc/locale/wcwidth.c (revision 225653)
+++ lib/libc/locale/wcwidth.c (working copy)
@@ -10,6 +10,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,12 +44,18 @@
__FBSDID("$FreeBSD$");
#include <wchar.h>
+#include <wctype.h>
+#include <xlocale.h>
#undef wcwidth
int
wcwidth(wchar_t wc)
{
-
return (__wcwidth(wc));
}
+int
+wcwidth_l(wchar_t wc, locale_t locale)
+{
+ return (__wcwidth_l(wc, locale));
+}
Index: lib/libc/locale/setlocale.c
===================================================================
--- lib/libc/locale/setlocale.c (revision 225653)
+++ lib/libc/locale/setlocale.c (working copy)
@@ -95,7 +95,7 @@
static char *currentlocale(void);
static char *loadlocale(int);
-static const char *__get_locale_env(int);
+const char *__get_locale_env(int);
char *
setlocale(category, locale)
@@ -278,13 +278,14 @@
if (func(new) != _LDP_ERROR) {
(void)strcpy(old, new);
+ (void)strcpy(__xlocale_global_locale.components[category-1]->locale, new);
return (old);
}
return (NULL);
}
-static const char *
+const char *
__get_locale_env(category)
int category;
{
Index: lib/libc/locale/runetype.c
===================================================================
--- lib/libc/locale/runetype.c (revision 225653)
+++ lib/libc/locale/runetype.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,12 +41,15 @@
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
unsigned long
-___runetype(__ct_rune_t c)
+___runetype_l(__ct_rune_t c, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext);
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -64,3 +72,18 @@
return(0L);
}
+unsigned long
+___runetype(__ct_rune_t c)
+{
+ return ___runetype_l(c, __get_locale());
+}
+
+int ___mb_cur_max(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->__mb_cur_max;
+}
+int ___mb_cur_max_l(locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return XLOCALE_CTYPE(locale)->__mb_cur_max;
+}
Index: lib/libc/locale/btowc.c
===================================================================
--- lib/libc/locale/btowc.c (revision 225653)
+++ lib/libc/locale/btowc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,12 +37,13 @@
#include "mblocal.h"
wint_t
-btowc(int c)
+btowc_l(int c, locale_t l)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char cc;
wchar_t wc;
+ FIX_LOCALE(l);
if (c == EOF)
return (WEOF);
@@ -47,7 +53,12 @@
* counts.
*/
cc = (char)c;
- if (__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
return (WEOF);
return (wc);
}
+wint_t
+btowc(int c)
+{
+ return btowc_l(c, __get_locale());
+}
Index: lib/libc/locale/mbrlen.c
===================================================================
--- lib/libc/locale/mbrlen.c (revision 225653)
+++ lib/libc/locale/mbrlen.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,11 +36,16 @@
#include "mblocal.h"
size_t
-mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale)
{
- static mbstate_t mbs;
-
+ FIX_LOCALE(locale);
if (ps == NULL)
- ps = &mbs;
- return (__mbrtowc(NULL, s, n, ps));
+ ps = &locale->mbrlen;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps));
}
+
+size_t
+mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+{
+ return mbrlen_l(s, n, ps, __get_locale());
+}
Index: lib/libc/locale/lmessages.c
===================================================================
--- lib/libc/locale/lmessages.c (revision 225653)
+++ lib/libc/locale/lmessages.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,6 +41,14 @@
#define LCMESSAGES_SIZE_MIN \
(offsetof(struct lc_messages_T, yesstr) / sizeof(char *))
+struct xlocale_messages {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_messages_T locale;
+};
+
+struct xlocale_messages __xlocale_global_messages;
+
static char empty[] = "";
static const struct lc_messages_T _C_messages_locale = {
@@ -45,33 +58,55 @@
"no" /* nostr */
};
-static struct lc_messages_T _messages_locale;
-static int _messages_using_locale;
-static char *_messages_locale_buf;
+static void destruct_messages(void *v)
+{
+ struct xlocale_messages *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
-int
-__messages_load_locale(const char *name)
+static int
+messages_load_locale(struct xlocale_messages *loc, int *using_locale, const char *name)
{
int ret;
+ struct lc_messages_T *l = &loc->locale;
- ret = __part_load_locale(name, &_messages_using_locale,
- &_messages_locale_buf, "LC_MESSAGES",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MESSAGES",
LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
- (const char **)&_messages_locale);
+ (const char **)l);
if (ret == _LDP_LOADED) {
- if (_messages_locale.yesstr == NULL)
- _messages_locale.yesstr = empty;
- if (_messages_locale.nostr == NULL)
- _messages_locale.nostr = empty;
+ if (l->yesstr == NULL)
+ l->yesstr = empty;
+ if (l->nostr == NULL)
+ l->nostr = empty;
}
return (ret);
}
+int
+__messages_load_locale(const char *name)
+{
+ return messages_load_locale(&__xlocale_global_messages,
+ &__xlocale_global_locale.using_messages_locale, name);
+}
+void *
+__messages_load(const char *name, locale_t l)
+{
+ struct xlocale_messages *new = calloc(sizeof(struct xlocale_messages), 1);
+ new->header.header.destructor = destruct_messages;
+ if (messages_load_locale(new, &l->using_messages_locale, name) == _LDP_ERROR) {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
struct lc_messages_T *
-__get_current_messages_locale(void)
+__get_current_messages_locale(locale_t loc)
{
- return (_messages_using_locale
- ? &_messages_locale
+ return (loc->using_messages_locale
+ ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale
: (struct lc_messages_T *)&_C_messages_locale);
}
Index: lib/libc/locale/big5.c
===================================================================
--- lib/libc/locale/big5.c (revision 225653)
+++ lib/libc/locale/big5.c (working copy)
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -62,15 +67,15 @@
} _BIG5State;
int
-_BIG5_init(_RuneLocale *rl)
+_BIG5_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _BIG5_mbrtowc;
- __wcrtomb = _BIG5_wcrtomb;
- __mbsinit = _BIG5_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _BIG5_mbrtowc;
+ l->__wcrtomb = _BIG5_wcrtomb;
+ l->__mbsinit = _BIG5_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
Index: lib/libc/locale/lmessages.h
===================================================================
--- lib/libc/locale/lmessages.h (revision 225653)
+++ lib/libc/locale/lmessages.h (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -29,6 +34,8 @@
#ifndef _LMESSAGES_H_
#define _LMESSAGES_H_
+#include "xlocale_private.h"
+
struct lc_messages_T {
const char *yesexpr;
const char *noexpr;
@@ -36,7 +43,7 @@
const char *nostr;
};
-struct lc_messages_T *__get_current_messages_locale(void);
+struct lc_messages_T *__get_current_messages_locale(locale_t);
int __messages_load_locale(const char *);
#endif /* !_LMESSAGES_H_ */
Index: lib/libc/locale/duplocale.3
===================================================================
--- lib/libc/locale/duplocale.3 (revision 0)
+++ lib/libc/locale/duplocale.3 (revision 0)
@@ -0,0 +1,76 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.Dd September 17 2011
+.Dt DUPLOCALE 3
+.Os
+.Sh NAME
+.Nm duplocale
+.Nd duplicate an locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft locale_t
+.Fn duplocale "locale_t locale"
+.Sh DESCRIPTION
+Duplicates an existing
+.Fa locale_t
+returning a new
+.Fa locale_t
+that refers to the same locale values but has independent internal state.
+Various functions, such as
+.Xr mblen 3
+require presistent state. These functions formerly used static variables and
+calls to them from multiple threads had undefined behavior. They now use
+fields in the
+.Fa locale_t
+associated with the current thread by
+.Xr uselocale 3 .
+These calls are therefore only thread safe on threads with a unique per-thread
+locale.
+.Pt
+The locale returned by this call must be freed with
+.Xr freelocale 3 .
+.Sh BUGS
+Ideally,
+.Xr uselocale 3
+should make a copy of the
+.Fa locale_t
+implicitly to ensure thread safety, and a copy of the global locale should be
+installed lazily on each thread. The FreeBSD implementation does not do this,
+for compatibility with Darwin.
+.Sh SEE ALSO
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
Index: lib/libc/locale/uselocale.3
===================================================================
--- lib/libc/locale/uselocale.3 (revision 0)
+++ lib/libc/locale/uselocale.3 (revision 0)
@@ -0,0 +1,60 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)ctype.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: head/lib/libc/locale/ctype.3 196820 2009-09-04 07:44:58Z des $
+.\"
+.Dd September 17 2011
+.Dt USELOCALE 3
+.Os
+.Sh NAME
+.Nm uselocale
+.Nd Sets a thread-local locale.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft locale_t
+.Fn uselocale "locale_t locale"
+.Sh DESCRIPTION
+Specifies the locale for this thread to use. Specifying
+.Fa LC_GLOBAL_LOCALE
+disables the per-thread locale, while NULL returns the current locale without
+setting a new one.
+.Sh RETURN VALUES
+Returns the previous locale, or LC_GLOBAL_LOCALE if this thread has no locale
+associated with it.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
Index: lib/libc/locale/freelocale.3
===================================================================
--- lib/libc/locale/freelocale.3 (revision 0)
+++ lib/libc/locale/freelocale.3 (revision 0)
@@ -0,0 +1,60 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.Dd September 17 2011
+.Dt FREELOCALE 3
+.Os
+.Sh NAME
+.Nm freelocale
+.Nd Frees a locale created with
+.Xr duplocale 3
+or
+.Xr newlocale 3 .
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft int
+.Fn freelocale "locale_t locale"
+.Sh DESCRIPTION
+Frees a
+.Fa locale_t .
+This relinquishes any resources held exclusively by this locale. Note that
+locales share reference-counted components, so a call to this function is not
+guaranteed to free all of the components.
+.Sh RETURN VALUES
+Returns 0 on success or -1 on error.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008 .
Index: lib/libc/locale/wcsrtombs.c
===================================================================
--- lib/libc/locale/wcsrtombs.c (revision 225653)
+++ lib/libc/locale/wcsrtombs.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,12 +39,18 @@
#include "mblocal.h"
size_t
+wcsrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+}
+
+size_t
wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+ return wcsrtombs_l(dst, src, len, ps, __get_locale());
}
Index: lib/libc/locale/localeconv.c
===================================================================
--- lib/libc/locale/localeconv.c (revision 225653)
+++ lib/libc/locale/localeconv.c (working copy)
@@ -3,6 +3,11 @@
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -48,25 +53,24 @@
* lconv structure are computed only when the monetary or numeric
* locale has been changed.
*/
-int __mlocale_changed = 1;
-int __nlocale_changed = 1;
/*
* Return the current locale conversion.
*/
struct lconv *
-localeconv()
+localeconv_l(locale_t loc)
{
- static struct lconv ret;
+ FIX_LOCALE(loc);
+ struct lconv *ret = &loc->lconv;
- if (__mlocale_changed) {
+ if (loc->monetary_locale_changed) {
/* LC_MONETARY part */
struct lc_monetary_T * mptr;
-#define M_ASSIGN_STR(NAME) (ret.NAME = (char*)mptr->NAME)
-#define M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0])
+#define M_ASSIGN_STR(NAME) (ret->NAME = (char*)mptr->NAME)
+#define M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0])
- mptr = __get_current_monetary_locale();
+ mptr = __get_current_monetary_locale(loc);
M_ASSIGN_STR(int_curr_symbol);
M_ASSIGN_STR(currency_symbol);
M_ASSIGN_STR(mon_decimal_point);
@@ -88,21 +92,26 @@
M_ASSIGN_CHAR(int_n_sep_by_space);
M_ASSIGN_CHAR(int_p_sign_posn);
M_ASSIGN_CHAR(int_n_sign_posn);
- __mlocale_changed = 0;
+ loc->monetary_locale_changed = 0;
}
- if (__nlocale_changed) {
+ if (loc->numeric_locale_changed) {
/* LC_NUMERIC part */
struct lc_numeric_T * nptr;
-#define N_ASSIGN_STR(NAME) (ret.NAME = (char*)nptr->NAME)
+#define N_ASSIGN_STR(NAME) (ret->NAME = (char*)nptr->NAME)
- nptr = __get_current_numeric_locale();
+ nptr = __get_current_numeric_locale(loc);
N_ASSIGN_STR(decimal_point);
N_ASSIGN_STR(thousands_sep);
N_ASSIGN_STR(grouping);
- __nlocale_changed = 0;
+ loc->numeric_locale_changed = 0;
}
- return (&ret);
+ return ret;
}
+struct lconv *
+localeconv(void)
+{
+ return localeconv_l(__get_locale());
+}
Index: lib/libc/locale/wcsnrtombs.c
===================================================================
--- lib/libc/locale/wcsnrtombs.c (revision 225653)
+++ lib/libc/locale/wcsnrtombs.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,16 +39,22 @@
#include "mblocal.h"
size_t
+wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsnrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, nwc, len, ps));
+}
+size_t
wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
size_t len, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__wcsnrtombs(dst, src, nwc, len, ps));
+ return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale());
}
+
size_t
__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps)
@@ -53,13 +64,14 @@
const wchar_t *s;
size_t nbytes;
size_t nb;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(__get_locale());
s = *src;
nbytes = 0;
if (dst == NULL) {
while (nwc-- > 0) {
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1)
+ if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1)
/* Invalid character - wcrtomb() sets errno. */
return ((size_t)-1);
else if (*s == L'\0')
@@ -73,7 +85,7 @@
while (len > 0 && nwc-- > 0) {
if (len > (size_t)MB_CUR_MAX) {
/* Enough space to translate in-place. */
- if ((nb = __wcrtomb(dst, *s, ps)) == (size_t)-1) {
+ if ((nb = l->__wcrtomb(dst, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
@@ -86,7 +98,7 @@
* character is too long for the buffer.
*/
mbsbak = *ps;
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) {
+ if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
Index: lib/libc/locale/gbk.c
===================================================================
--- lib/libc/locale/gbk.c (revision 225653)
+++ lib/libc/locale/gbk.c (working copy)
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -55,15 +60,15 @@
} _GBKState;
int
-_GBK_init(_RuneLocale *rl)
+_GBK_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _GBK_mbrtowc;
- __wcrtomb = _GBK_wcrtomb;
- __mbsinit = _GBK_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _GBK_mbrtowc;
+ l->__wcrtomb = _GBK_wcrtomb;
+ l->__mbsinit = _GBK_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
Index: lib/libc/locale/querylocale.3
===================================================================
--- lib/libc/locale/querylocale.3 (revision 0)
+++ lib/libc/locale/querylocale.3 (revision 0)
@@ -0,0 +1,55 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.Dd September 17 2011
+.Dt QUERYLOCALE 3
+.Os
+.Sh NAME
+.Nm querylocale
+.Nd Look up the locale name for a specified category.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft const char *
+.Fn querylocale "int mask" "locale_t locale"
+.Sh DESCRIPTION
+Returns the name of the locale for the category specified by
+.Fa mask.
+This possible values for the mask are the same as those in
+.Xr newlocale 3 . If more than one bit in the mask is set, the returned value
+is undefined.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
Index: lib/libc/locale/wctype.c
===================================================================
--- lib/libc/locale/wctype.c (revision 225653)
+++ lib/libc/locale/wctype.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,17 +35,27 @@
#include <ctype.h>
#include <string.h>
#include <wctype.h>
+#include <xlocale.h>
#undef iswctype
int
iswctype(wint_t wc, wctype_t charclass)
{
-
return (__istype(wc, charclass));
}
+int
+iswctype_l(wint_t wc, wctype_t charclass, locale_t locale)
+{
+ return __istype_l(wc, charclass, locale);
+}
+/*
+ * IMPORTANT: The 0 in the call to this function in wctype() must be changed to
+ * __get_locale() if wctype_l() ie ever modified to actually use the locale
+ * parameter.
+ */
wctype_t
-wctype(const char *property)
+wctype_l(const char *property, locale_t locale)
{
static const struct {
const char *name;
@@ -72,3 +87,8 @@
return (props[i].mask);
}
+
+wctype_t wctype(const char *property)
+{
+ return wctype_l(property, 0);
+}
Index: lib/libc/locale/lnumeric.c
===================================================================
--- lib/libc/locale/lnumeric.c (revision 225653)
+++ lib/libc/locale/lnumeric.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,7 +37,6 @@
#include "ldpart.h"
#include "lnumeric.h"
-extern int __nlocale_changed;
extern const char *__fix_locale_grouping_str(const char *);
#define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
@@ -45,37 +49,67 @@
numempty /* grouping */
};
-static struct lc_numeric_T _numeric_locale;
-static int _numeric_using_locale;
-static char *_numeric_locale_buf;
+static void
+destruct_numeric(void *v)
+{
+ struct xlocale_numeric *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
-int
-__numeric_load_locale(const char *name)
+struct xlocale_numeric __xlocale_global_numeric;
+
+static int
+numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed,
+ const char *name)
{
int ret;
+ struct lc_numeric_T *l = &loc->locale;
- ret = __part_load_locale(name, &_numeric_using_locale,
- &_numeric_locale_buf, "LC_NUMERIC",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_NUMERIC",
LCNUMERIC_SIZE, LCNUMERIC_SIZE,
- (const char **)&_numeric_locale);
+ (const char**)l);
if (ret != _LDP_ERROR)
- __nlocale_changed = 1;
+ *changed= 1;
if (ret == _LDP_LOADED) {
/* Can't be empty according to C99 */
- if (*_numeric_locale.decimal_point == '\0')
- _numeric_locale.decimal_point =
+ if (*l->decimal_point == '\0')
+ l->decimal_point =
_C_numeric_locale.decimal_point;
- _numeric_locale.grouping =
- __fix_locale_grouping_str(_numeric_locale.grouping);
+ l->grouping =
+ __fix_locale_grouping_str(l->grouping);
}
return (ret);
}
+int
+__numeric_load_locale(const char *name)
+{
+ return numeric_load_locale(&__xlocale_global_numeric,
+ &__xlocale_global_locale.using_numeric_locale,
+ &__xlocale_global_locale.numeric_locale_changed, name);
+}
+void *
+__numeric_load(const char *name, locale_t l)
+{
+ struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric), 1);
+ new->header.header.destructor = destruct_numeric;
+ if (numeric_load_locale(new, &l->using_numeric_locale,
+ &l->numeric_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
struct lc_numeric_T *
-__get_current_numeric_locale(void)
+__get_current_numeric_locale(locale_t loc)
{
- return (_numeric_using_locale
- ? &_numeric_locale
+ return (loc->using_numeric_locale
+ ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale
: (struct lc_numeric_T *)&_C_numeric_locale);
}
Index: lib/libc/locale/wcstoimax.c
===================================================================
--- lib/libc/locale/wcstoimax.c (revision 225653)
+++ lib/libc/locale/wcstoimax.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an intmax_t integer.
*/
intmax_t
-wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -88,8 +95,8 @@
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -122,3 +129,9 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+intmax_t
+wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoimax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/lnumeric.h
===================================================================
--- lib/libc/locale/lnumeric.h (revision 225653)
+++ lib/libc/locale/lnumeric.h (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,14 +33,20 @@
#ifndef _LNUMERIC_H_
#define _LNUMERIC_H_
+#include "xlocale_private.h"
struct lc_numeric_T {
const char *decimal_point;
const char *thousands_sep;
const char *grouping;
};
+struct xlocale_numeric {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_numeric_T locale;
+};
-struct lc_numeric_T *__get_current_numeric_locale(void);
+struct lc_numeric_T *__get_current_numeric_locale(locale_t loc);
int __numeric_load_locale(const char *);
#endif /* !_LNUMERIC_H_ */
Index: lib/libc/locale/wctomb.c
===================================================================
--- lib/libc/locale/wctomb.c (revision 225653)
+++ lib/libc/locale/wctomb.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,18 +37,23 @@
#include "mblocal.h"
int
-wctomb(char *s, wchar_t wchar)
+wctomb_l(char *s, wchar_t wchar, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->wctomb = initial;
return (0);
}
- if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1)
+ if ((rval = XLOCALE_CTYPE(locale)->__wcrtomb(s, wchar, &locale->wctomb)) == (size_t)-1)
return (-1);
return ((int)rval);
}
+int
+wctomb(char *s, wchar_t wchar)
+{
+ return wctomb_l(s, wchar, __get_locale());
+}
Index: lib/libc/locale/toupper.c
===================================================================
--- lib/libc/locale/toupper.c (revision 225653)
+++ lib/libc/locale/toupper.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,13 +41,17 @@
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___toupper(c)
+___toupper_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__mapupper_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -53,7 +62,9 @@
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= c && c <= re->__max)
+ {
return (re->__map + c - re->__min);
+ }
else if (c > re->__max) {
base = re + 1;
lim--;
@@ -62,3 +73,9 @@
return(c);
}
+__ct_rune_t
+___toupper(c)
+ __ct_rune_t c;
+{
+ return ___toupper_l(c, __get_locale());
+}
Index: lib/libc/locale/wcstombs.c
===================================================================
--- lib/libc/locale/wcstombs.c (revision 225653)
+++ lib/libc/locale/wcstombs.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,21 @@
#include "mblocal.h"
size_t
-wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+wcstombs_l(char * __restrict s, const wchar_t * __restrict pwcs, size_t n,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const wchar_t *pwcsp;
+ FIX_LOCALE(locale);
mbs = initial;
pwcsp = pwcs;
- return (__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
}
+size_t
+wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+{
+ return wcstombs_l(s, pwcs, n, __get_locale());
+}
+
Index: lib/libc/locale/wcstoull.c
===================================================================
--- lib/libc/locale/wcstoull.c (revision 225653)
+++ lib/libc/locale/wcstoull.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long long integer.
*/
unsigned long long
-wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoull for comments as to the logic used.
@@ -61,7 +68,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@
cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -120,3 +127,9 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long long
+wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoull_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/euc.c
===================================================================
--- lib/libc/locale/euc.c (revision 225653)
+++ lib/libc/locale/euc.c (working copy)
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -70,7 +75,7 @@
} _EucState;
int
-_EUC_init(_RuneLocale *rl)
+_EUC_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
_EucInfo *ei;
int x, new__mb_cur_max;
@@ -113,12 +118,12 @@
}
rl->__variable = ei;
rl->__variable_len = sizeof(_EucInfo);
- _CurrentRuneLocale = rl;
- __mb_cur_max = new__mb_cur_max;
- __mbrtowc = _EUC_mbrtowc;
- __wcrtomb = _EUC_wcrtomb;
- __mbsinit = _EUC_mbsinit;
- __mb_sb_limit = 256;
+ l->runes = rl;
+ l->__mb_cur_max = new__mb_cur_max;
+ l->__mbrtowc = _EUC_mbrtowc;
+ l->__wcrtomb = _EUC_wcrtomb;
+ l->__mbsinit = _EUC_mbsinit;
+ l->__mb_sb_limit = 256;
return (0);
}
Index: lib/libc/locale/wctob.c
===================================================================
--- lib/libc/locale/wctob.c (revision 225653)
+++ lib/libc/locale/wctob.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,19 @@
#include "mblocal.h"
int
-wctob(wint_t c)
+wctob_l(wint_t c, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char buf[MB_LEN_MAX];
+ FIX_LOCALE(locale);
- if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1)
+ if (c == WEOF || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1)
return (EOF);
return ((unsigned char)*buf);
}
+int
+wctob(wint_t c)
+{
+ return wctob_l(c, __get_locale());
+}
Index: lib/libc/locale/wcstold.c
===================================================================
--- lib/libc/locale/wcstold.c (revision 225653)
+++ lib/libc/locale/wcstold.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,26 +35,32 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
long double
-wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
long double val;
char *buf, *end;
- const wchar_t *wcp;
+ const wchar_t *wcp = nptr;
size_t len;
+ size_t spaces = 0;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
- nptr++;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -57,14 +68,23 @@
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
- val = strtold(buf, &end);
+ val = strtold_l(buf, &end, locale);
- if (endptr != NULL)
+ if (endptr != NULL) {
+ /* XXX Assume each wide char is one byte. */
*endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
free(buf);
return (val);
}
+long double
+wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstold_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/locale/wctrans.c
===================================================================
--- lib/libc/locale/wctrans.c (revision 225653)
+++ lib/libc/locale/wctrans.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <errno.h>
#include <string.h>
#include <wctype.h>
+#include "xlocale_private.h"
enum {
_WCT_ERROR = 0,
@@ -38,15 +44,14 @@
};
wint_t
-towctrans(wint_t wc, wctrans_t desc)
+towctrans_l(wint_t wc, wctrans_t desc, locale_t locale)
{
-
switch (desc) {
case _WCT_TOLOWER:
- wc = towlower(wc);
+ wc = towlower_l(wc, locale);
break;
case _WCT_TOUPPER:
- wc = towupper(wc);
+ wc = towupper_l(wc, locale);
break;
case _WCT_ERROR:
default:
@@ -56,9 +61,18 @@
return (wc);
}
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+ return towctrans_l(wc, desc, __get_locale());
+}
+/*
+ * wctrans() calls this will a 0 locale. If this is ever modified to actually
+ * use the locale, wctrans() must be modified to call __get_locale().
+ */
wctrans_t
-wctrans(const char *charclass)
+wctrans_l(const char *charclass, locale_t locale)
{
struct {
const char *name;
@@ -78,3 +92,10 @@
errno = EINVAL;
return (ccls[i].trans);
}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ return wctrans_l(charclass, 0);
+}
+
Index: lib/libc/locale/gb18030.c
===================================================================
--- lib/libc/locale/gb18030.c (revision 225653)
+++ lib/libc/locale/gb18030.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,8 +44,6 @@
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB18030_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB18030_mbsinit(const mbstate_t *);
@@ -53,15 +56,15 @@
} _GB18030State;
int
-_GB18030_init(_RuneLocale *rl)
+_GB18030_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _GB18030_mbrtowc;
- __wcrtomb = _GB18030_wcrtomb;
- __mbsinit = _GB18030_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 4;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _GB18030_mbrtowc;
+ l->__wcrtomb = _GB18030_wcrtomb;
+ l->__mbsinit = _GB18030_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ l->__mb_sb_limit = 128;
return (0);
}
Index: lib/libc/locale/nl_langinfo.c
===================================================================
--- lib/libc/locale/nl_langinfo.c (revision 225653)
+++ lib/libc/locale/nl_langinfo.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,15 +46,16 @@
#define _REL(BASE) ((int)item-BASE)
char *
-nl_langinfo(nl_item item)
+nl_langinfo_l(nl_item item, locale_t loc)
{
- char *ret, *s, *cs;
- static char *csym = NULL;
+ char *ret, *cs;
+ const char *s;
+ FIX_LOCALE(loc);
switch (item) {
case CODESET:
ret = "";
- if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
+ if ((s = querylocale(LC_CTYPE_MASK, loc)) != NULL) {
if ((cs = strchr(s, '.')) != NULL)
ret = cs + 1;
else if (strcmp(s, "C") == 0 ||
@@ -58,46 +64,46 @@
}
break;
case D_T_FMT:
- ret = (char *) __get_current_time_locale()->c_fmt;
+ ret = (char *) __get_current_time_locale(loc)->c_fmt;
break;
case D_FMT:
- ret = (char *) __get_current_time_locale()->x_fmt;
+ ret = (char *) __get_current_time_locale(loc)->x_fmt;
break;
case T_FMT:
- ret = (char *) __get_current_time_locale()->X_fmt;
+ ret = (char *) __get_current_time_locale(loc)->X_fmt;
break;
case T_FMT_AMPM:
- ret = (char *) __get_current_time_locale()->ampm_fmt;
+ ret = (char *) __get_current_time_locale(loc)->ampm_fmt;
break;
case AM_STR:
- ret = (char *) __get_current_time_locale()->am;
+ ret = (char *) __get_current_time_locale(loc)->am;
break;
case PM_STR:
- ret = (char *) __get_current_time_locale()->pm;
+ ret = (char *) __get_current_time_locale(loc)->pm;
break;
case DAY_1: case DAY_2: case DAY_3:
case DAY_4: case DAY_5: case DAY_6: case DAY_7:
- ret = (char*) __get_current_time_locale()->weekday[_REL(DAY_1)];
+ ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)];
break;
case ABDAY_1: case ABDAY_2: case ABDAY_3:
case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
- ret = (char*) __get_current_time_locale()->wday[_REL(ABDAY_1)];
+ ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)];
break;
case MON_1: case MON_2: case MON_3: case MON_4:
case MON_5: case MON_6: case MON_7: case MON_8:
case MON_9: case MON_10: case MON_11: case MON_12:
- ret = (char*) __get_current_time_locale()->month[_REL(MON_1)];
+ ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)];
break;
case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
- ret = (char*) __get_current_time_locale()->mon[_REL(ABMON_1)];
+ ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)];
break;
case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4:
case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8:
case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12:
ret = (char*)
- __get_current_time_locale()->alt_month[_REL(ALTMON_1)];
+ __get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)];
break;
case ERA:
/* XXX: need to be implemented */
@@ -120,16 +126,16 @@
ret = "";
break;
case RADIXCHAR:
- ret = (char*) __get_current_numeric_locale()->decimal_point;
+ ret = (char*) __get_current_numeric_locale(loc)->decimal_point;
break;
case THOUSEP:
- ret = (char*) __get_current_numeric_locale()->thousands_sep;
+ ret = (char*) __get_current_numeric_locale(loc)->thousands_sep;
break;
case YESEXPR:
- ret = (char*) __get_current_messages_locale()->yesexpr;
+ ret = (char*) __get_current_messages_locale(loc)->yesexpr;
break;
case NOEXPR:
- ret = (char*) __get_current_messages_locale()->noexpr;
+ ret = (char*) __get_current_messages_locale(loc)->noexpr;
break;
/*
* YESSTR and NOSTR items marked with LEGACY are available, but not
@@ -137,45 +143,51 @@
* they're subject to remove in future specification editions.
*/
case YESSTR: /* LEGACY */
- ret = (char*) __get_current_messages_locale()->yesstr;
+ ret = (char*) __get_current_messages_locale(loc)->yesstr;
break;
case NOSTR: /* LEGACY */
- ret = (char*) __get_current_messages_locale()->nostr;
+ ret = (char*) __get_current_messages_locale(loc)->nostr;
break;
/*
* SUSv2 special formatted currency string
*/
case CRNCYSTR:
ret = "";
- cs = (char*) __get_current_monetary_locale()->currency_symbol;
+ cs = (char*) __get_current_monetary_locale(loc)->currency_symbol;
if (*cs != '\0') {
- char pos = localeconv()->p_cs_precedes;
+ char pos = localeconv_l(loc)->p_cs_precedes;
- if (pos == localeconv()->n_cs_precedes) {
+ if (pos == localeconv_l(loc)->n_cs_precedes) {
char psn = '\0';
if (pos == CHAR_MAX) {
- if (strcmp(cs, __get_current_monetary_locale()->mon_decimal_point) == 0)
+ if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0)
psn = '.';
} else
psn = pos ? '-' : '+';
if (psn != '\0') {
int clen = strlen(cs);
- if ((csym = reallocf(csym, clen + 2)) != NULL) {
- *csym = psn;
- strcpy(csym + 1, cs);
- ret = csym;
+ if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) {
+ *loc->csym = psn;
+ strcpy(loc->csym + 1, cs);
+ ret = loc->csym;
}
}
}
}
break;
case D_MD_ORDER: /* FreeBSD local extension */
- ret = (char *) __get_current_time_locale()->md_order;
+ ret = (char *) __get_current_time_locale(loc)->md_order;
break;
default:
ret = "";
}
return (ret);
}
+
+char *
+nl_langinfo(nl_item item)
+{
+ return nl_langinfo_l(item, __get_locale());
+}
Index: lib/libc/locale/table.c
===================================================================
--- lib/libc/locale/table.c (revision 225653)
+++ lib/libc/locale/table.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,7 +46,7 @@
#include <wchar.h>
#include "mblocal.h"
-_RuneLocale _DefaultRuneLocale = {
+const _RuneLocale _DefaultRuneLocale = {
_RUNE_MAGIC_1,
"NONE",
NULL,
@@ -245,5 +250,14 @@
},
};
-_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+#undef _CurrentRuneLocale
+_RuneLocale *_CurrentRuneLocale = (_RuneLocale*)&_DefaultRuneLocale;
+_RuneLocale *
+__runes_for_locale(locale_t locale, int *mb_sb_limit)
+{
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *c = XLOCALE_CTYPE(locale);
+ *mb_sb_limit = c->__mb_sb_limit;
+ return c->runes;
+}
Index: lib/libc/locale/wcstoll.c
===================================================================
--- lib/libc/locale/wcstoll.c (revision 225653)
+++ lib/libc/locale/wcstoll.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,18 +46,21 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a long long integer.
*/
long long
-wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoll for comments as to the logic used.
@@ -60,7 +68,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -87,8 +95,8 @@
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -121,3 +129,8 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+long long
+wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoll_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/tolower.c
===================================================================
--- lib/libc/locale/tolower.c (revision 225653)
+++ lib/libc/locale/tolower.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,13 +41,17 @@
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___tolower(c)
+___tolower_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__maplower_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -62,3 +71,9 @@
return(c);
}
+__ct_rune_t
+___tolower(c)
+ __ct_rune_t c;
+{
+ return ___tolower_l(c, __get_locale());
+}
Index: lib/libc/locale/mskanji.c
===================================================================
--- lib/libc/locale/mskanji.c (revision 225653)
+++ lib/libc/locale/mskanji.c (working copy)
@@ -6,6 +6,11 @@
* (C) Sin'ichiro MIYATANI / Phase One, Inc
* May 12, 1995
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -60,15 +65,15 @@
} _MSKanjiState;
int
-_MSKanji_init(_RuneLocale *rl)
+_MSKanji_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _MSKanji_mbrtowc;
- __wcrtomb = _MSKanji_wcrtomb;
- __mbsinit = _MSKanji_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 256;
+ l->__mbrtowc = _MSKanji_mbrtowc;
+ l->__wcrtomb = _MSKanji_wcrtomb;
+ l->__mbsinit = _MSKanji_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 256;
return (0);
}
Index: lib/libc/locale/mblen.c
===================================================================
--- lib/libc/locale/mblen.c (revision 225653)
+++ lib/libc/locale/mblen.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,19 +37,25 @@
#include "mblocal.h"
int
-mblen(const char *s, size_t n)
+mblen_l(const char *s, size_t n, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->mblen = initial;
return (0);
}
- rval = __mbrtowc(NULL, s, n, &mbs);
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, &locale->mblen);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+
+int
+mblen(const char *s, size_t n)
+{
+ return mblen_l(s, n, __get_locale());
+}
Index: lib/libc/locale/none.c
===================================================================
--- lib/libc/locale/none.c (revision 225653)
+++ lib/libc/locale/none.c (working copy)
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -64,17 +69,17 @@
int __mb_sb_limit = 256; /* Expected to be <= _CACHED_RUNES */
int
-_none_init(_RuneLocale *rl)
+_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _none_mbrtowc;
- __mbsinit = _none_mbsinit;
- __mbsnrtowcs = _none_mbsnrtowcs;
- __wcrtomb = _none_wcrtomb;
- __wcsnrtombs = _none_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 1;
- __mb_sb_limit = 256;
+ l->__mbrtowc = _none_mbrtowc;
+ l->__mbsinit = _none_mbsinit;
+ l->__mbsnrtowcs = _none_mbsnrtowcs;
+ l->__wcrtomb = _none_wcrtomb;
+ l->__wcsnrtombs = _none_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 256;
return(0);
}
@@ -192,3 +197,14 @@
size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
size_t, size_t, mbstate_t * __restrict) = _none_wcsnrtombs;
+struct xlocale_ctype __xlocale_global_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
Index: lib/libc/locale/mbstowcs.c
===================================================================
--- lib/libc/locale/mbstowcs.c (revision 225653)
+++ lib/libc/locale/mbstowcs.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,19 @@
#include "mblocal.h"
size_t
-mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+mbstowcs_l(wchar_t * __restrict pwcs, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const char *sp;
+ FIX_LOCALE(locale);
mbs = initial;
sp = s;
- return (__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
}
+size_t
+mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+{
+ return mbstowcs_l(pwcs, s, n, __get_locale());
+}
Index: lib/libc/locale/wcstod.c
===================================================================
--- lib/libc/locale/wcstod.c (revision 225653)
+++ lib/libc/locale/wcstod.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a double-precision number.
@@ -41,17 +47,22 @@
* for at least the digits, radix character and letters.
*/
double
-wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
double val;
char *buf, *end;
- const wchar_t *wcp;
+ const wchar_t *wcp = nptr;
size_t len;
+ size_t spaces = 0;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
- nptr++;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
/*
* Convert the supplied numeric wide char. string to multibyte.
@@ -63,9 +74,8 @@
* duplicates a lot of strtod()'s functionality and slows down the
* most common cases.
*/
- wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -73,10 +83,10 @@
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
/* Let strtod() do most of the work for us. */
- val = strtod(buf, &end);
+ val = strtod_l(buf, &end, locale);
/*
* We only know where the number ended in the _multibyte_
@@ -84,11 +94,20 @@
* where it ended, count multibyte characters to find the
* corresponding position in the wide char string.
*/
- if (endptr != NULL)
+ if (endptr != NULL) {
/* XXX Assume each wide char is one byte. */
*endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
+
free(buf);
return (val);
}
+double
+wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstod_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/locale/setrunelocale.c
===================================================================
--- lib/libc/locale/setrunelocale.c (revision 225653)
+++ lib/libc/locale/setrunelocale.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -49,68 +54,46 @@
extern _RuneLocale *_Read_RuneMagi(FILE *);
-static int __setrunelocale(const char *);
+static int __setrunelocale(struct xlocale_ctype *l, const char *);
+#define __collate_load_error (table->__collate_load_error)
+#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
+#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
+#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
+#define __collate_chain_pri_table (table->__collate_chain_pri_table)
+
+
+static void destruct_ctype(void *v)
+{
+ struct xlocale_ctype *l = v;
+ if (strcmp(l->runes->__encoding, "EUC") == 0)
+ free(l->runes->__variable);
+ if (&_DefaultRuneLocale != l->runes)
+ free(l->runes);
+ free(l);
+}
+_RuneLocale *__getCurrentRuneLocale(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->runes;
+}
+
static int
-__setrunelocale(const char *encoding)
+__setrunelocale(struct xlocale_ctype *l, const char *encoding)
{
FILE *fp;
char name[PATH_MAX];
_RuneLocale *rl;
int saverr, ret;
- size_t (*old__mbrtowc)(wchar_t * __restrict,
- const char * __restrict, size_t, mbstate_t * __restrict);
- size_t (*old__wcrtomb)(char * __restrict, wchar_t,
- mbstate_t * __restrict);
- int (*old__mbsinit)(const mbstate_t *);
- size_t (*old__mbsnrtowcs)(wchar_t * __restrict,
- const char ** __restrict, size_t, size_t, mbstate_t * __restrict);
- size_t (*old__wcsnrtombs)(char * __restrict,
- const wchar_t ** __restrict, size_t, size_t,
- mbstate_t * __restrict);
- static char ctype_encoding[ENCODING_LEN + 1];
- static _RuneLocale *CachedRuneLocale;
- static int Cached__mb_cur_max;
- static int Cached__mb_sb_limit;
- static size_t (*Cached__mbrtowc)(wchar_t * __restrict,
- const char * __restrict, size_t, mbstate_t * __restrict);
- static size_t (*Cached__wcrtomb)(char * __restrict, wchar_t,
- mbstate_t * __restrict);
- static int (*Cached__mbsinit)(const mbstate_t *);
- static size_t (*Cached__mbsnrtowcs)(wchar_t * __restrict,
- const char ** __restrict, size_t, size_t, mbstate_t * __restrict);
- static size_t (*Cached__wcsnrtombs)(char * __restrict,
- const wchar_t ** __restrict, size_t, size_t,
- mbstate_t * __restrict);
+ struct xlocale_ctype saved = *l;
/*
* The "C" and "POSIX" locale are always here.
*/
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
- (void) _none_init(&_DefaultRuneLocale);
+ (void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
return (0);
}
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (CachedRuneLocale != NULL &&
- strcmp(encoding, ctype_encoding) == 0) {
- _CurrentRuneLocale = CachedRuneLocale;
- __mb_cur_max = Cached__mb_cur_max;
- __mb_sb_limit = Cached__mb_sb_limit;
- __mbrtowc = Cached__mbrtowc;
- __mbsinit = Cached__mbsinit;
- __mbsnrtowcs = Cached__mbsnrtowcs;
- __wcrtomb = Cached__wcrtomb;
- __wcsnrtombs = Cached__wcsnrtombs;
- return (0);
- }
-
- /*
- * Slurp the locale file into the cache.
- */
-
/* Range checking not needed, encoding length already checked before */
(void) strcpy(name, _PathLocale);
(void) strcat(name, "/");
@@ -127,63 +110,47 @@
}
(void)fclose(fp);
- old__mbrtowc = __mbrtowc;
- old__mbsinit = __mbsinit;
- old__mbsnrtowcs = __mbsnrtowcs;
- old__wcrtomb = __wcrtomb;
- old__wcsnrtombs = __wcsnrtombs;
+ l->__mbrtowc = NULL;
+ l->__mbsinit = NULL;
+ l->__mbsnrtowcs = __mbsnrtowcs_std;
+ l->__wcrtomb = NULL;
+ l->__wcsnrtombs = __wcsnrtombs_std;
- __mbrtowc = NULL;
- __mbsinit = NULL;
- __mbsnrtowcs = __mbsnrtowcs_std;
- __wcrtomb = NULL;
- __wcsnrtombs = __wcsnrtombs_std;
-
rl->__sputrune = NULL;
rl->__sgetrune = NULL;
if (strcmp(rl->__encoding, "NONE") == 0)
- ret = _none_init(rl);
+ ret = _none_init(l, rl);
else if (strcmp(rl->__encoding, "ASCII") == 0)
- ret = _ascii_init(rl);
+ ret = _ascii_init(l, rl);
else if (strcmp(rl->__encoding, "UTF-8") == 0)
- ret = _UTF8_init(rl);
+ ret = _UTF8_init(l, rl);
else if (strcmp(rl->__encoding, "EUC") == 0)
- ret = _EUC_init(rl);
+ ret = _EUC_init(l, rl);
else if (strcmp(rl->__encoding, "GB18030") == 0)
- ret = _GB18030_init(rl);
+ ret = _GB18030_init(l, rl);
else if (strcmp(rl->__encoding, "GB2312") == 0)
- ret = _GB2312_init(rl);
+ ret = _GB2312_init(l, rl);
else if (strcmp(rl->__encoding, "GBK") == 0)
- ret = _GBK_init(rl);
+ ret = _GBK_init(l, rl);
else if (strcmp(rl->__encoding, "BIG5") == 0)
- ret = _BIG5_init(rl);
+ ret = _BIG5_init(l, rl);
else if (strcmp(rl->__encoding, "MSKanji") == 0)
- ret = _MSKanji_init(rl);
+ ret = _MSKanji_init(l, rl);
else
ret = EFTYPE;
if (ret == 0) {
- if (CachedRuneLocale != NULL) {
- /* See euc.c */
- if (strcmp(CachedRuneLocale->__encoding, "EUC") == 0)
- free(CachedRuneLocale->__variable);
- free(CachedRuneLocale);
+ /* Free the old runes if it exists. */
+ /* FIXME: The "EUC" check here is a hideous abstraction violation. */
+ if ((saved.runes != &_DefaultRuneLocale) && (saved.runes)) {
+ if (strcmp(saved.runes->__encoding, "EUC") == 0) {
+ free(saved.runes->__variable);
+ }
+ free(saved.runes);
}
- CachedRuneLocale = _CurrentRuneLocale;
- Cached__mb_cur_max = __mb_cur_max;
- Cached__mb_sb_limit = __mb_sb_limit;
- Cached__mbrtowc = __mbrtowc;
- Cached__mbsinit = __mbsinit;
- Cached__mbsnrtowcs = __mbsnrtowcs;
- Cached__wcrtomb = __wcrtomb;
- Cached__wcsnrtombs = __wcsnrtombs;
- (void)strcpy(ctype_encoding, encoding);
} else {
- __mbrtowc = old__mbrtowc;
- __mbsinit = old__mbsinit;
- __mbsnrtowcs = old__mbsnrtowcs;
- __wcrtomb = old__wcrtomb;
- __wcsnrtombs = old__wcsnrtombs;
+ /* Restore the saved version if this failed. */
+ memcpy(l, &saved, sizeof(struct xlocale_ctype));
free(rl);
}
@@ -193,12 +160,24 @@
int
__wrap_setrunelocale(const char *locale)
{
- int ret = __setrunelocale(locale);
+ int ret = __setrunelocale(&__xlocale_global_ctype, locale);
if (ret != 0) {
errno = ret;
return (_LDP_ERROR);
}
+ __mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
+ __mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
return (_LDP_LOADED);
}
-
+void *__ctype_load(const char *locale, locale_t unused)
+{
+ struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
+ l->header.header.destructor = destruct_ctype;
+ if (__setrunelocale(l, locale))
+ {
+ free(l);
+ return NULL;
+ }
+ return l;
+}
Index: lib/libc/locale/lmonetary.c
===================================================================
--- lib/libc/locale/lmonetary.c (revision 225653)
+++ lib/libc/locale/lmonetary.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,7 +39,6 @@
#include "ldpart.h"
#include "lmonetary.h"
-extern int __mlocale_changed;
extern const char * __fix_locale_grouping_str(const char *);
#define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *))
@@ -69,9 +73,7 @@
numempty /* int_n_sign_posn */
};
-static struct lc_monetary_T _monetary_locale;
-static int _monetary_using_locale;
-static char *_monetary_locale_buf;
+struct xlocale_monetary __xlocale_global_monetary;
static char
cnv(const char *str)
@@ -83,23 +85,34 @@
return ((char)i);
}
-int
-__monetary_load_locale(const char *name)
+static void
+destruct_monetary(void *v)
{
+ struct xlocale_monetary *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+static int
+monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
+ int *changed, const char *name)
+{
int ret;
+ struct lc_monetary_T *l = &loc->locale;
- ret = __part_load_locale(name, &_monetary_using_locale,
- &_monetary_locale_buf, "LC_MONETARY",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MONETARY",
LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
- (const char **)&_monetary_locale);
+ (const char **)l);
if (ret != _LDP_ERROR)
- __mlocale_changed = 1;
+ *changed = 1;
if (ret == _LDP_LOADED) {
- _monetary_locale.mon_grouping =
- __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+ l->mon_grouping =
+ __fix_locale_grouping_str(l->mon_grouping);
-#define M_ASSIGN_CHAR(NAME) (((char *)_monetary_locale.NAME)[0] = \
- cnv(_monetary_locale.NAME))
+#define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \
+ cnv(l->NAME))
M_ASSIGN_CHAR(int_frac_digits);
M_ASSIGN_CHAR(frac_digits);
@@ -117,9 +130,9 @@
*/
#define M_ASSIGN_ICHAR(NAME) \
do { \
- if (_monetary_locale.int_##NAME == NULL) \
- _monetary_locale.int_##NAME = \
- _monetary_locale.NAME; \
+ if (l->int_##NAME == NULL) \
+ l->int_##NAME = \
+ l->NAME; \
else \
M_ASSIGN_CHAR(int_##NAME); \
} while (0)
@@ -133,12 +146,32 @@
}
return (ret);
}
+int
+__monetary_load_locale(const char *name)
+{
+ return monetary_load_locale_l(&__xlocale_global_monetary,
+ &__xlocale_global_locale.using_monetary_locale,
+ &__xlocale_global_locale.monetary_locale_changed, name);
+}
+void* __monetary_load(const char *name, locale_t l)
+{
+ struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary), 1);
+ new->header.header.destructor = destruct_monetary;
+ if (monetary_load_locale_l(new, &l->using_monetary_locale,
+ &l->monetary_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
struct lc_monetary_T *
-__get_current_monetary_locale(void)
+__get_current_monetary_locale(locale_t loc)
{
- return (_monetary_using_locale
- ? &_monetary_locale
+ return (loc->using_monetary_locale
+ ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale
: (struct lc_monetary_T *)&_C_monetary_locale);
}
Index: lib/libc/locale/nextwctype.c
===================================================================
--- lib/libc/locale/nextwctype.c (revision 225653)
+++ lib/libc/locale/nextwctype.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,12 +35,15 @@
#include <runetype.h>
#include <wchar.h>
#include <wctype.h>
+#include "mblocal.h"
wint_t
-nextwctype(wint_t wc, wctype_t wct)
+nextwctype_l(wint_t wc, wctype_t wct, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneLocale *runes = XLOCALE_CTYPE(locale)->runes;
+ _RuneRange *rr = &runes->__runetype_ext;
_RuneEntry *base, *re;
int noinc;
@@ -43,7 +51,7 @@
if (wc < _CACHED_RUNES) {
wc++;
while (wc < _CACHED_RUNES) {
- if (_CurrentRuneLocale->__runetype[wc] & wct)
+ if (runes->__runetype[wc] & wct)
return (wc);
wc++;
}
@@ -88,3 +96,8 @@
}
return (-1);
}
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+ return nextwctype_l(wc, wct, __get_locale());
+}
Index: lib/libc/locale/wcstol.c
===================================================================
--- lib/libc/locale/wcstol.c (revision 225653)
+++ lib/libc/locale/wcstol.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,18 +40,21 @@
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a long integer.
*/
long
-wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
+ base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -81,8 +89,8 @@
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -115,3 +123,8 @@
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+long
+wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstol_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/locale/wcrtomb.c
===================================================================
--- lib/libc/locale/wcrtomb.c (revision 225653)
+++ lib/libc/locale/wcrtomb.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,11 +36,17 @@
#include "mblocal.h"
size_t
-wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+wcrtomb_l(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps,
+ locale_t locale)
{
- static mbstate_t mbs;
-
+ FIX_LOCALE(locale);
if (ps == NULL)
- ps = &mbs;
- return (__wcrtomb(s, wc, ps));
+ ps = &locale->wcrtomb;
+ return (XLOCALE_CTYPE(locale)->__wcrtomb(s, wc, ps));
}
+
+size_t
+wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ return wcrtomb_l(s, wc, ps, __get_locale());
+}
Index: lib/libc/locale/lmonetary.h
===================================================================
--- lib/libc/locale/lmonetary.h (revision 225653)
+++ lib/libc/locale/lmonetary.h (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,6 +33,7 @@
#ifndef _LMONETARY_H_
#define _LMONETARY_H_
+#include "xlocale_private.h"
struct lc_monetary_T {
const char *int_curr_symbol;
@@ -52,8 +58,13 @@
const char *int_p_sign_posn;
const char *int_n_sign_posn;
};
+struct xlocale_monetary {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_monetary_T locale;
+};
-struct lc_monetary_T *__get_current_monetary_locale(void);
+struct lc_monetary_T *__get_current_monetary_locale(locale_t loc);
int __monetary_load_locale(const char *);
#endif /* !_LMONETARY_H_ */
Index: lib/libc/locale/wcsftime.c
===================================================================
--- lib/libc/locale/wcsftime.c (revision 225653)
+++ lib/libc/locale/wcsftime.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,6 +37,7 @@
#include <stdlib.h>
#include <time.h>
#include <wchar.h>
+#include "xlocale_private.h"
/*
* Convert date and time to a wide-character string.
@@ -47,8 +53,9 @@
* format specifications in the format string.
*/
size_t
-wcsftime(wchar_t * __restrict wcs, size_t maxsize,
- const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+wcsftime_l(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -57,6 +64,7 @@
const wchar_t *formatp;
size_t n, sflen;
int sverrno;
+ FIX_LOCALE(locale);
sformat = dst = NULL;
@@ -66,13 +74,13 @@
*/
mbs = initial;
formatp = format;
- sflen = wcsrtombs(NULL, &formatp, 0, &mbs);
+ sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale);
if (sflen == (size_t)-1)
goto error;
if ((sformat = malloc(sflen + 1)) == NULL)
goto error;
mbs = initial;
- wcsrtombs(sformat, &formatp, sflen + 1, &mbs);
+ wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale);
/*
* Allocate memory for longest multibyte sequence that will fit
@@ -87,11 +95,11 @@
}
if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
goto error;
- if (strftime(dst, maxsize, sformat, timeptr) == 0)
+ if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0)
goto error;
dstp = dst;
mbs = initial;
- n = mbsrtowcs(wcs, &dstp, maxsize, &mbs);
+ n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale);
if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
goto error;
@@ -106,3 +114,9 @@
errno = sverrno;
return (0);
}
+size_t
+wcsftime(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+{
+ return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale());
+}
Index: lib/libc/locale/xlocale_private.h
===================================================================
--- lib/libc/locale/xlocale_private.h (revision 0)
+++ lib/libc/locale/xlocale_private.h (revision 0)
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "setlocale.h"
+
+enum {
+ XLC_COLLATE = 0,
+ XLC_CTYPE,
+ XLC_MONETARY,
+ XLC_NUMERIC,
+ XLC_TIME,
+ XLC_MESSAGES,
+ XLC_LAST
+};
+
+
+/**
+ * Header used for objects that are reference counted. Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure. Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0. When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+ /** Number of references to this component. */
+ long retain_count;
+ /** Function used to destroy this component, if one is required*/
+ void(*destructor)(void*);
+};
+/**
+ * Header for a locale component. All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+ struct xlocale_refcounted header;
+ /** Name of the locale used for this component. */
+ char locale[ENCODING_LEN+1];
+};
+
+/**
+ * xlocale structure, stores per-thread locale information.
+ *
+ * Note: We could save a few bytes by using a bitfield for the flags at the end
+ * of this structure. I imagine that most programs will not have more than
+ * half a dozen locales though, so this doesn't seem worthwhile.
+ */
+struct _xlocale {
+ struct xlocale_refcounted header;
+ /** Components for the locale. */
+ struct xlocale_component *components[XLC_LAST];
+ /** Flag indicating if components[XLC_MONETARY] has changed since the last
+ * call to localeconv_l() with this locale. */
+ int monetary_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MONETARY (1), or if it should use the C default instead (0). */
+ int using_monetary_locale;
+ /** Flag indicating if components[XLC_NUMERIC] has changed since the last
+ * call to localeconv_l() with this locale. */
+ int numeric_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_NUMERIC (1), or if it should use the C default instead (0). */
+ int using_numeric_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_TIME (1), or if it should use the C default instead (0). */
+ int using_time_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MESSAGES (1), or if it should use the C default instead (0). */
+ int using_messages_locale;
+ /** The structure to be returned from localeconv_l() for this locale. */
+ struct lconv lconv;
+ /** Persistent state used by mblen() calls. */
+ __mbstate_t mblen;
+ /** Persistent state used by mbrlen() calls. */
+ __mbstate_t mbrlen;
+ /** Persistent state used by mbrtowc() calls. */
+ __mbstate_t mbrtowc;
+ /** Persistent state used by mbsnrtowcs() calls. */
+ __mbstate_t mbsnrtowcs;
+ /** Persistent state used by mbsrtowcs() calls. */
+ __mbstate_t mbsrtowcs;
+ /** Persistent state used by mbtowc() calls. */
+ __mbstate_t mbtowc;
+ /** Persistent state used by wcrtomb() calls. */
+ __mbstate_t wcrtomb;
+ /** Persistent state used by wcsnrtombs() calls. */
+ __mbstate_t wcsnrtombs;
+ /** Persistent state used by wcsrtombs() calls. */
+ __mbstate_t wcsrtombs;
+ /** Persistent state used by wctomb() calls. */
+ __mbstate_t wctomb;
+ /** Buffer used by nl_langinfo_l() */
+ char *csym;
+};
+
+/**
+ * Increments the reference count of a reference-counted structure.
+ */
+__attribute__((unused)) static void*
+xlocale_retain(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ __sync_fetch_and_add(&(obj->retain_count), 1);
+ return val;
+}
+/**
+ * Decrements the reference count of a reference-counted structure, freeing it
+ * if this is the last reference, calling its destructor if it has one.
+ */
+__attribute__((unused)) static void
+xlocale_release(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ long count = __sync_sub_and_fetch(&(obj->retain_count), 1);
+ if (count < 0)
+ {
+ if (0 != obj->destructor)
+ {
+ obj->destructor(obj);
+ }
+ }
+}
+
+/**
+ * Load functions. Each takes the name of a locale and a pointer to the data
+ * to be initialised as arguments. Two special values are allowed for the
+ */
+extern void* __collate_load(const char*, locale_t);
+extern void* __ctype_load(const char*, locale_t);
+extern void* __messages_load(const char*, locale_t);
+extern void* __monetary_load(const char*, locale_t);
+extern void* __numeric_load(const char*, locale_t);
+extern void* __time_load(const char*, locale_t);
+
+extern struct _xlocale __xlocale_global_locale;
+
+/**
+ * Returns the current locale for this thread, or the global locale if none is
+ * set. The caller does not have to free the locale. The return value from
+ * this call is not guaranteed to remain valid after the locale changes. As
+ * such, this should only be called within libc functions.
+ */
+locale_t __get_locale(void);
+
+/**
+ * Two magic values are allowed for locale_t objects. NULL and -1. This
+ * function maps those to the real locales that they represent.
+ */
+static inline locale_t get_real_locale(locale_t locale)
+{
+ switch ((intptr_t)locale)
+ {
+ case 0: return &__xlocale_global_locale;
+ case -1: return __get_locale();
+ default: return locale;
+ }
+}
+
+/**
+ * Replace a plaecholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
Index: lib/libc/locale/newlocale.3
===================================================================
--- lib/libc/locale/newlocale.3 (revision 0)
+++ lib/libc/locale/newlocale.3 (revision 0)
@@ -0,0 +1,108 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.Dd September 17 2011
+.Dt newlocale 3
+.Os
+.Sh NAME
+.Nm newlocale
+.Nd Creates a new locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale
+.Ft
+.Fn newlocale "int mask" "const char * locale" "locale_t base"
+.Sh DESCRIPTION
+Creates a new locale, inheriting some properties from an existing locale. The
+.Fa mask
+defines the components that the new locale will have set to the locale with the
+name specified in the
+.Fa locale
+parameter. Any other components will be inherited from
+.Fa base .
+.Pt
+The
+.Fa mask
+is either
+.Fa LC_ALL_MASK,
+indicating all possible locale components, or the logical OR of some
+combination of the following:
+.Bl -tag -width "LC_MESSAGES_MASK" -offset indent
+.It LC_COLLATE_MASK
+The locale for string collation routines. This controls alphabetic ordering in
+.Xr strcoll 3
+ and
+.Xr strxfrm 3 .
+.It LC_CTYPE_MASK
+The locale for the
+.Xr ctype 3
+and
+.Xr multibyte 3
+functions. This controls recognition of upper and lower case, alpha- betic or
+non-alphabetic characters, and so on.
+.It LC_MESSAGES_MASK
+Set a locale for message catalogs, see
+.Xr catopen 3
+function.
+.It LC_MONETARY_MASK
+Set a locale for formatting monetary values; this affects
+the
+.Xr localeconv 3
+function.
+.It LC_NUMERIC_MASK
+Set a locale for formatting numbers. This controls the for-
+matting of decimal points in input and output of floating
+point numbers in functions such as
+.Xr printf 3
+and
+.Xr scanf 3 ,
+as well as values returned by
+.Xr localeconv 3 .
+.It LC_TIME_MASK
+Set a locale for formatting dates and times using the
+.Xr strftime 3
+function.
+.El
+
+This function uses the same rules for loading locale components as
+.Xr setlocale 3 .
+.Sh RETURN VALUES
+Returns a new, valid,
+.Fa locale_t
+or NULL if an error occurs. You must free the returned locale with
+.Xr freelocale 3 .
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
Index: lib/libc/locale/mbsnrtowcs.c
===================================================================
--- lib/libc/locale/mbsnrtowcs.c (revision 225653)
+++ lib/libc/locale/mbsnrtowcs.c (working copy)
@@ -1,6 +1,11 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
* All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,14 +39,19 @@
#include "mblocal.h"
size_t
+mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsnrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, nms, len, ps));
+}
+size_t
mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbsnrtowcs(dst, src, nms, len, ps));
+ return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale());
}
size_t
@@ -52,13 +62,14 @@
size_t nchr;
wchar_t wc;
size_t nb;
+ struct xlocale_ctype *ct = XLOCALE_CTYPE(__get_locale());
s = *src;
nchr = 0;
if (dst == NULL) {
for (;;) {
- if ((nb = __mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+ if ((nb = ct->__mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
else if (nb == 0 || nb == (size_t)-2)
@@ -71,7 +82,7 @@
}
while (len-- > 0) {
- if ((nb = __mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+ if ((nb = ct->__mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
Index: lib/libc/locale/xlocale.3
===================================================================
--- lib/libc/locale/xlocale.3 (revision 0)
+++ lib/libc/locale/xlocale.3 (revision 0)
@@ -0,0 +1,265 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" 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 REGENTS 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 REGENTS 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.
+.\"
+.Dd September 17 2011
+.Dt XLOCALE 3
+.Os
+.Sh NAME
+.Nm xlocale
+.Nd Thread-safe extended locale support.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Sh DESCRIPTION
+The extended locale support includes a set of functions for setting
+thread-local locales, as well convenience functions for performing locale-aware
+calls with a specified locale.
+.Pp
+The core of the xlocale API is the
+.Fa locale_t
+type. This is an opqaue type encapsulating a locale. Instances of this can be
+either set as the locale for a specific thread or passed directly to the
+.Fa _l
+suffixed variants of various standard C functions. Two special
+.Fa locale_t
+values are available:
+.Bl -bullet -offset indent
+.It
+NULL refers to the current locale for the thread, or to the global locale if no
+locale has been set for this thread.
+.It
+LC_GLOBAL_LOCALE refers to the global locale.
+.El
+.Pp
+The global locale is the locale set with the
+.Xr setlocale 3
+function.
+.Sh CAVEATS
+The
+.Xr setlocale 3
+function, and others in the family, refer to the global locale. Other
+functions that depend on the locale, however, will take the thread-local locale
+if one has been set. This means that the idiom of setting the locale using
+.Xr setlocale 3 ,
+calling a locale-dependent function, and then restoring the locale will not
+have the expected behavior if the current thread has had a locale set using
+.Xr uselocale 3 .
+You should avoid this idiom and prefer to use the
+.Fa _l
+suffixed versions instead.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Sh CONVENIENCE FUNCTIONS
+The xlocale API includes a number of
+.Fa _l
+suffixed convenience functions. These are variants of standard C functions
+that have been modified to take an explicit
+.Fa locale_t
+parameter as the final argument or, in the case of variadic functions, as an
+additional argument directly before the format string.
+.Pp
+These functions are exposed by including
+.In xlocale.h
+.Em after
+including the relevant headers for the standard variant. For example, the
+.Xr strtol_l 3
+function is exposed by including
+.In xlocale.h
+after
+.In stdlib.h ,
+which defines
+.Xr strtol 3 .
+.Pp
+For reference, a complete list of the locale-aware functions that are available
+in this form, along with the headers that expose them, is provided here:
+.Pp
+.Bl -tag -width "<monetary.h> "
+.It In wctype.h
+.Xr iswalnum_l 3 ,
+.Xr iswalpha_l 3 ,
+.Xr iswcntrl_l 3 ,
+.Xr iswctype_l 3 ,
+.Xr iswdigit_l 3 ,
+.Xr iswgraph_l 3 ,
+.Xr iswlower_l 3 ,
+.Xr iswprint_l 3 ,
+.Xr iswpunct_l 3 ,
+.Xr iswspace_l 3 ,
+.Xr iswupper_l 3 ,
+.Xr iswxdigit_l 3 ,
+.Xr towlower_l 3 ,
+.Xr towupper_l 3 ,
+.Xr wctype_l 3 ,
+.It In ctype.h
+.Xr digittoint_l 3 ,
+.Xr isalnum_l 3 ,
+.Xr isalpha_l 3 ,
+.Xr isblank_l 3 ,
+.Xr iscntrl_l 3 ,
+.Xr isdigit_l 3 ,
+.Xr isgraph_l 3 ,
+.Xr ishexnumber_l 3 ,
+.Xr isideogram_l 3 ,
+.Xr islower_l 3 ,
+.Xr isnumber_l 3 ,
+.Xr isphonogram_l 3 ,
+.Xr isprint_l 3 ,
+.Xr ispunct_l 3 ,
+.Xr isrune_l 3 ,
+.Xr isspace_l 3 ,
+.Xr isspecial_l 3 ,
+.Xr isupper_l 3 ,
+.Xr isxdigit_l 3 ,
+.Xr tolower_l 3 ,
+.Xr toupper_l 3
+.It In inttypes.h
+.Xr strtoimax_l 3 ,
+.Xr strtoumax_l 3 ,
+.Xr wcstoimax_l 3 ,
+.Xr wcstoumax_l 3
+.It In langinfo.h
+.Xr nl_langinfo_l 3
+.It In monetary.h
+.Xr strfmon_l 3
+.It In stdio.h
+.Xr asprintf_l 3 ,
+.Xr fprintf_l 3 ,
+.Xr fscanf_l 3 ,
+.Xr printf_l 3 ,
+.Xr scanf_l 3 ,
+.Xr snprintf_l 3 ,
+.Xr sprintf_l 3 ,
+.Xr sscanf_l 3 ,
+.Xr vasprintf_l 3 ,
+.Xr vfprintf_l 3 ,
+.Xr vfscanf_l 3 ,
+.Xr vprintf_l 3 ,
+.Xr vscanf_l 3 ,
+.Xr vsnprintf_l 3 ,
+.Xr vsprintf_l 3 ,
+.Xr vsscanf_l 3
+.It In stdlib.h
+.Xr atof_l 3 ,
+.Xr atoi_l 3 ,
+.Xr atol_l 3 ,
+.Xr atoll_l 3 ,
+.Xr mblen_l 3 ,
+.Xr mbstowcs_l 3 ,
+.Xr mbtowc_l 3 ,
+.Xr strtod_l 3 ,
+.Xr strtof_l 3 ,
+.Xr strtol_l 3 ,
+.Xr strtold_l 3 ,
+.Xr strtoll_l 3 ,
+.Xr strtoq_l 3 ,
+.Xr strtoul_l 3 ,
+.Xr strtoull_l 3 ,
+.Xr strtouq_l 3 ,
+.Xr wcstombs_l 3 ,
+.Xr wctomb_l 3
+.It In string.h
+.Xr strcoll_l 3 ,
+.Xr strxfrm_l 3 ,
+.Xr strcasecmp_l 3 ,
+.Xr strcasestr_l 3 ,
+.Xr strncasecmp_l 3
+.It In time.h
+.Xr strftime_l 3
+.Xr strptime_l 3
+.It In wchar.h
+.Xr btowc_l 3 ,
+.Xr fgetwc_l 3 ,
+.Xr fgetws_l 3 ,
+.Xr fputwc_l 3 ,
+.Xr fputws_l 3 ,
+.Xr fwprintf_l 3 ,
+.Xr fwscanf_l 3 ,
+.Xr getwc_l 3 ,
+.Xr getwchar_l 3 ,
+.Xr mbrlen_l 3 ,
+.Xr mbrtowc_l 3 ,
+.Xr mbsinit_l 3 ,
+.Xr mbsnrtowcs_l 3 ,
+.Xr mbsrtowcs_l 3 ,
+.Xr putwc_l 3 ,
+.Xr putwchar_l 3 ,
+.Xr swprintf_l 3 ,
+.Xr swscanf_l 3 ,
+.Xr ungetwc_l 3 ,
+.Xr vfwprintf_l 3 ,
+.Xr vfwscanf_l 3 ,
+.Xr vswprintf_l 3 ,
+.Xr vswscanf_l 3 ,
+.Xr vwprintf_l 3 ,
+.Xr vwscanf_l 3 ,
+.Xr wcrtomb_l 3 ,
+.Xr wcscoll_l 3 ,
+.Xr wcsftime_l 3 ,
+.Xr wcsnrtombs_l 3 ,
+.Xr wcsrtombs_l 3 ,
+.Xr wcstod_l 3 ,
+.Xr wcstof_l 3 ,
+.Xr wcstol_l 3 ,
+.Xr wcstold_l 3 ,
+.Xr wcstoll_l 3 ,
+.Xr wcstoul_l 3 ,
+.Xr wcstoull_l 3 ,
+.Xr wcswidth_l 3 ,
+.Xr wcsxfrm_l 3 ,
+.Xr wctob_l 3 ,
+.Xr wcwidth_l 3 ,
+.Xr wprintf_l 3 ,
+.Xr wscanf_l 3
+.It In wctype.h
+.Xr iswblank_l 3 ,
+.Xr iswhexnumber_l 3 ,
+.Xr iswideogram_l 3 ,
+.Xr iswnumber_l 3 ,
+.Xr iswphonogram_l 3 ,
+.Xr iswrune_l 3 ,
+.Xr iswspecial_l 3 ,
+.Xr nextwctype_l 3 ,
+.Xr towctrans_l 3 ,
+.Xr wctrans_l 3
+.It In xlocale.h
+.Xr localeconv_l 3
+.El
+.Sh STANDARDS
+The functions
+conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The xlocale APIs first appeared in Darwin 8.0. This implementation was
+written by David Chisnall, under sponsorship from the FreeBSD Foundation and
+first appeared in
+.Fx 9.1 .
Index: lib/libc/locale/mbrtowc.c
===================================================================
--- lib/libc/locale/mbrtowc.c (revision 225653)
+++ lib/libc/locale/mbrtowc.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,12 +36,18 @@
#include "mblocal.h"
size_t
+mbrtowc_l(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtowc;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, ps));
+}
+
+size_t
mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbrtowc(pwc, s, n, ps));
+ return mbrtowc_l(pwc, s, n, ps, __get_locale());
}
Index: lib/libc/locale/ctype.c
===================================================================
--- lib/libc/locale/ctype.c (revision 0)
+++ lib/libc/locale/ctype.c (revision 0)
@@ -0,0 +1,31 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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.
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
Index: lib/libc/stdtime/timelocal.h
===================================================================
--- lib/libc/stdtime/timelocal.h (revision 225653)
+++ lib/libc/stdtime/timelocal.h (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1997-2002 FreeBSD Project.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,6 +33,7 @@
#ifndef _TIMELOCAL_H_
#define _TIMELOCAL_H_
+#include "xlocale_private.h"
/*
* Private header file for the strftime and strptime localization
@@ -49,7 +55,7 @@
const char *ampm_fmt;
};
-struct lc_time_T *__get_current_time_locale(void);
+struct lc_time_T *__get_current_time_locale(locale_t);
int __time_load_locale(const char *);
#endif /* !_TIMELOCAL_H_ */
Index: lib/libc/stdtime/strptime.c
===================================================================
--- lib/libc/stdtime/strptime.c (revision 225653)
+++ lib/libc/stdtime/strptime.c (working copy)
@@ -22,6 +22,11 @@
/*
* Copyright (c) 1994 Powerdog Industries. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -72,19 +77,20 @@
#include "libc_private.h"
#include "timelocal.h"
-static char * _strptime(const char *, const char *, struct tm *, int *);
+static char * _strptime(const char *, const char *, struct tm *, int *, locale_t);
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
static char *
-_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
+_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
+ locale_t locale)
{
char c;
const char *ptr;
int i,
len;
int Ealternative, Oalternative;
- struct lc_time_T *tptr = __get_current_time_locale();
+ struct lc_time_T *tptr = __get_current_time_locale(locale);
ptr = fmt;
while (*ptr != 0) {
@@ -94,8 +100,8 @@
c = *ptr++;
if (c != '%') {
- if (isspace((unsigned char)c))
- while (*buf != 0 && isspace((unsigned char)*buf))
+ if (isspace_l((unsigned char)c, locale))
+ while (*buf != 0 && isspace_l((unsigned char)*buf, locale))
buf++;
else if (c != *buf++)
return 0;
@@ -114,18 +120,18 @@
break;
case '+':
- buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
+ buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'C':
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
/* XXX This will break for 3-digit centuries. */
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -137,13 +143,13 @@
break;
case 'c':
- buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
+ buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'D':
- buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
+ buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
if (buf == 0)
return 0;
break;
@@ -161,47 +167,47 @@
goto label;
case 'F':
- buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
+ buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'R':
- buf = _strptime(buf, "%H:%M", tm, GMTp);
+ buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'r':
- buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
+ buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'T':
- buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
+ buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'X':
- buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
+ buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'x':
- buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
+ buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
if (buf == 0)
return 0;
break;
case 'j':
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 3;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -214,14 +220,14 @@
case 'M':
case 'S':
- if (*buf == 0 || isspace((unsigned char)*buf))
+ if (*buf == 0 || isspace_l((unsigned char)*buf, locale))
break;
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -237,8 +243,8 @@
tm->tm_sec = i;
}
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -254,11 +260,11 @@
* XXX The %l specifier may gobble one too many
* digits if used incorrectly.
*/
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -271,8 +277,8 @@
tm->tm_hour = i;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -282,7 +288,7 @@
* specifiers.
*/
len = strlen(tptr->am);
- if (strncasecmp(buf, tptr->am, len) == 0) {
+ if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour == 12)
@@ -292,7 +298,7 @@
}
len = strlen(tptr->pm);
- if (strncasecmp(buf, tptr->pm, len) == 0) {
+ if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour != 12)
@@ -307,12 +313,12 @@
case 'a':
for (i = 0; i < asizeof(tptr->weekday); i++) {
len = strlen(tptr->weekday[i]);
- if (strncasecmp(buf, tptr->weekday[i],
- len) == 0)
+ if (strncasecmp_l(buf, tptr->weekday[i],
+ len, locale) == 0)
break;
len = strlen(tptr->wday[i]);
- if (strncasecmp(buf, tptr->wday[i],
- len) == 0)
+ if (strncasecmp_l(buf, tptr->wday[i],
+ len, locale) == 0)
break;
}
if (i == asizeof(tptr->weekday))
@@ -330,11 +336,11 @@
* point to calculate a real value, so just check the
* range for now.
*/
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -342,13 +348,13 @@
if (i > 53)
return 0;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
case 'w':
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
i = *buf - '0';
@@ -357,8 +363,8 @@
tm->tm_wday = i;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -372,11 +378,11 @@
* XXX The %e specifier may gobble one too many
* digits if used incorrectly.
*/
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -386,8 +392,8 @@
tm->tm_mday = i;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -398,15 +404,15 @@
if (Oalternative) {
if (c == 'B') {
len = strlen(tptr->alt_month[i]);
- if (strncasecmp(buf,
+ if (strncasecmp_l(buf,
tptr->alt_month[i],
- len) == 0)
+ len, locale) == 0)
break;
}
} else {
len = strlen(tptr->month[i]);
- if (strncasecmp(buf, tptr->month[i],
- len) == 0)
+ if (strncasecmp_l(buf, tptr->month[i],
+ len, locale) == 0)
break;
}
}
@@ -417,8 +423,8 @@
if (i == asizeof(tptr->month) && !Oalternative) {
for (i = 0; i < asizeof(tptr->month); i++) {
len = strlen(tptr->mon[i]);
- if (strncasecmp(buf, tptr->mon[i],
- len) == 0)
+ if (strncasecmp_l(buf, tptr->mon[i],
+ len, locale) == 0)
break;
}
}
@@ -430,11 +436,11 @@
break;
case 'm':
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -444,8 +450,8 @@
tm->tm_mon = i - 1;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -458,7 +464,7 @@
sverrno = errno;
errno = 0;
- n = strtol(buf, &cp, 10);
+ n = strtol_l(buf, &cp, 10, locale);
if (errno == ERANGE || (long)(t = n) != n) {
errno = sverrno;
return 0;
@@ -472,14 +478,14 @@
case 'Y':
case 'y':
- if (*buf == 0 || isspace((unsigned char)*buf))
+ if (*buf == 0 || isspace_l((unsigned char)*buf, locale))
break;
- if (!isdigit((unsigned char)*buf))
+ if (!isdigit_l((unsigned char)*buf, locale))
return 0;
len = (c == 'Y') ? 4 : 2;
- for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
i *= 10;
i += *buf - '0';
len--;
@@ -493,8 +499,8 @@
tm->tm_year = i;
- if (*buf != 0 && isspace((unsigned char)*buf))
- while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+ while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
ptr++;
break;
@@ -503,7 +509,7 @@
const char *cp;
char *zonestr;
- for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
+ for (cp = buf; *cp && isupper_l((unsigned char)*cp, locale); ++cp) {/*empty*/}
if (cp - buf) {
zonestr = alloca(cp - buf + 1);
strncpy(zonestr, buf, cp - buf);
@@ -537,7 +543,7 @@
buf++;
i = 0;
for (len = 4; len > 0; len--) {
- if (isdigit((unsigned char)*buf)) {
+ if (isdigit_l((unsigned char)*buf, locale)) {
i *= 10;
i += *buf - '0';
buf++;
@@ -557,14 +563,15 @@
char *
-strptime(const char * __restrict buf, const char * __restrict fmt,
- struct tm * __restrict tm)
+strptime_l(const char * __restrict buf, const char * __restrict fmt,
+ struct tm * __restrict tm, locale_t loc)
{
char *ret;
int gmt;
+ FIX_LOCALE(loc);
gmt = 0;
- ret = _strptime(buf, fmt, tm, &gmt);
+ ret = _strptime(buf, fmt, tm, &gmt, loc);
if (ret && gmt) {
time_t t = timegm(tm);
localtime_r(&t, tm);
@@ -572,3 +579,9 @@
return (ret);
}
+char *
+strptime(const char * __restrict buf, const char * __restrict fmt,
+ struct tm * __restrict tm)
+{
+ return strptime_l(buf, fmt, tm, __get_locale());
+}
Index: lib/libc/stdtime/timelocal.c
===================================================================
--- lib/libc/stdtime/timelocal.c (revision 225653)
+++ lib/libc/stdtime/timelocal.c (working copy)
@@ -3,6 +3,11 @@
* Copyright (c) 1997 FreeBSD Inc.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,10 +38,14 @@
#include "ldpart.h"
#include "timelocal.h"
-static struct lc_time_T _time_locale;
-static int _time_using_locale;
-static char *time_locale_buf;
+struct xlocale_time {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_time_T locale;
+};
+struct xlocale_time __xlocale_global_time;
+
#define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
static const struct lc_time_T _C_time_locale = {
@@ -99,19 +108,47 @@
"%I:%M:%S %p"
};
+static void destruct_time(void *v)
+{
+ struct xlocale_time *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+#include <stdio.h>
struct lc_time_T *
-__get_current_time_locale(void)
+__get_current_time_locale(locale_t loc)
{
- return (_time_using_locale
- ? &_time_locale
+ return (loc->using_time_locale
+ ? &((struct xlocale_time *)loc->components[XLC_TIME])->locale
: (struct lc_time_T *)&_C_time_locale);
}
+static int
+time_load_locale(struct xlocale_time *l, int *using_locale, const char *name)
+{
+ struct lc_time_T *time_locale = &l->locale;
+ return (__part_load_locale(name, using_locale,
+ &l->buffer, "LC_TIME",
+ LCTIME_SIZE, LCTIME_SIZE,
+ (const char **)time_locale));
+}
int
__time_load_locale(const char *name)
{
- return (__part_load_locale(name, &_time_using_locale,
- &time_locale_buf, "LC_TIME",
- LCTIME_SIZE, LCTIME_SIZE,
- (const char **)&_time_locale));
+ return time_load_locale(&__xlocale_global_time,
+ &__xlocale_global_locale.using_time_locale, name);
}
+extern void* __time_load(const char* name, locale_t loc)
+{
+ struct xlocale_time *new = calloc(sizeof(struct xlocale_time), 1);
+ new->header.header.destructor = destruct_time;
+ if (time_load_locale(new, &loc->using_time_locale, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
Index: lib/libc/stdtime/strftime.c
===================================================================
--- lib/libc/stdtime/strftime.c (revision 225653)
+++ lib/libc/stdtime/strftime.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
@@ -43,7 +48,7 @@
static char * _add(const char *, char *, const char *);
static char * _conv(int, const char *, char *, const char *);
static char * _fmt(const char *, const struct tm *, char *, const char *,
- int *);
+ int *, locale_t);
static char * _yconv(int, int, int, int, char *, const char *);
extern char * tzname[];
@@ -82,29 +87,30 @@
};
size_t
-strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
- const struct tm * __restrict t)
+strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,
+ const struct tm * __restrict t, locale_t loc)
{
char * p;
int warn;
+ FIX_LOCALE(loc);
tzset();
warn = IN_NONE;
- p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);
#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
- (void) fprintf(stderr, "\n");
+ (void) fprintf_l(stderr, loc, "\n");
if (format == NULL)
- (void) fprintf(stderr, "NULL strftime format ");
- else (void) fprintf(stderr, "strftime format \"%s\" ",
+ (void) fprintf_l(stderr, loc, "NULL strftime format ");
+ else (void) fprintf_l(stderr, loc, "strftime format \"%s\" ",
format);
- (void) fprintf(stderr, "yields only two digits of years in ");
+ (void) fprintf_l(stderr, loc, "yields only two digits of years in ");
if (warn == IN_SOME)
- (void) fprintf(stderr, "some locales");
+ (void) fprintf_l(stderr, loc, "some locales");
else if (warn == IN_THIS)
- (void) fprintf(stderr, "the current locale");
- else (void) fprintf(stderr, "all locales");
- (void) fprintf(stderr, "\n");
+ (void) fprintf_l(stderr, loc, "the current locale");
+ else (void) fprintf_l(stderr, loc, "all locales");
+ (void) fprintf_l(stderr, loc, "\n");
}
#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
@@ -113,16 +119,24 @@
return p - s;
}
+size_t
+strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
+ const struct tm * __restrict t)
+{
+ return strftime_l(s, maxsize, format, t, __get_locale());
+}
+
static char *
-_fmt(format, t, pt, ptlim, warnp)
+_fmt(format, t, pt, ptlim, warnp, loc)
const char * format;
const struct tm * const t;
char * pt;
const char * const ptlim;
int * warnp;
+locale_t loc;
{
int Ealternative, Oalternative, PadIndex;
- struct lc_time_T *tptr = __get_current_time_locale();
+ struct lc_time_T *tptr = __get_current_time_locale(loc);
for ( ; *format; ++format) {
if (*format == '%') {
@@ -175,7 +189,7 @@
{
int warn2 = IN_SOME;
- pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2);
+ pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
@@ -183,7 +197,7 @@
}
continue;
case 'D':
- pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc);
continue;
case 'd':
pt = _conv(t->tm_mday, fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
@@ -216,7 +230,7 @@
fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex], pt, ptlim);
continue;
case 'F':
- pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc);
continue;
case 'H':
pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
@@ -285,11 +299,11 @@
pt, ptlim);
continue;
case 'R':
- pt = _fmt("%H:%M", t, pt, ptlim, warnp);
+ pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);
continue;
case 'r':
pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
- warnp);
+ warnp, loc);
continue;
case 'S':
pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
@@ -313,7 +327,7 @@
}
continue;
case 'T':
- pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc);
continue;
case 't':
pt = _add("\t", pt, ptlim);
@@ -428,7 +442,7 @@
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
- pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
+ pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -441,13 +455,13 @@
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
- pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp);
+ pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc);
continue;
case 'x':
{
int warn2 = IN_SOME;
- pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2);
+ pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
@@ -534,7 +548,7 @@
continue;
case '+':
pt = _fmt(tptr->date_fmt, t, pt, ptlim,
- warnp);
+ warnp, loc);
continue;
case '-':
if (PadIndex != PAD_DEFAULT)
Index: lib/libc/gen/glob.c
===================================================================
--- lib/libc/gen/glob.c (revision 225653)
+++ lib/libc/gen/glob.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -751,6 +756,8 @@
{
int ok, negate_range;
Char c, k;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
while (pat < patend) {
c = *pat++;
@@ -775,10 +782,10 @@
++pat;
while (((c = *pat++) & M_MASK) != M_END)
if ((*pat & M_MASK) == M_RNG) {
- if (__collate_load_error ?
+ if (table->__collate_load_error ?
CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
- __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
- && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
+ __collate_range_cmp(table, CHAR(c), CHAR(k)) <= 0
+ && __collate_range_cmp(table, CHAR(k), CHAR(pat[1])) <= 0
)
ok = 1;
pat += 2;
Index: lib/libc/gen/fnmatch.c
===================================================================
--- lib/libc/gen/fnmatch.c (revision 225653)
+++ lib/libc/gen/fnmatch.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -222,6 +227,8 @@
wchar_t c, c2;
size_t pclen;
const char *origpat;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
/*
* A bracket expression starting with an unquoted circumflex
@@ -276,10 +283,10 @@
if (flags & FNM_CASEFOLD)
c2 = towlower(c2);
- if (__collate_load_error ?
+ if (table->__collate_load_error ?
c <= test && test <= c2 :
- __collate_range_cmp(c, test) <= 0
- && __collate_range_cmp(test, c2) <= 0
+ __collate_range_cmp(table, c, test) <= 0
+ && __collate_range_cmp(table, test, c2) <= 0
)
ok = 1;
} else if (c == test)
Index: lib/libc/regex/regcomp.c
===================================================================
--- lib/libc/regex/regcomp.c (revision 225653)
+++ lib/libc/regex/regcomp.c (working copy)
@@ -3,9 +3,19 @@
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -730,6 +740,8 @@
char c;
wint_t start, finish;
wint_t i;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
/* classify what we've got */
switch ((MORE()) ? PEEK() : '\0') {
@@ -778,14 +790,14 @@
if (start == finish)
CHadd(p, cs, start);
else {
- if (__collate_load_error) {
+ if (table->__collate_load_error) {
(void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE);
CHaddrange(p, cs, start, finish);
} else {
- (void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE);
+ (void)REQUIRE(__collate_range_cmp(table, start, finish) <= 0, REG_ERANGE);
for (i = 0; i <= UCHAR_MAX; i++) {
- if ( __collate_range_cmp(start, i) <= 0
- && __collate_range_cmp(i, finish) <= 0
+ if ( __collate_range_cmp(table, start, i) <= 0
+ && __collate_range_cmp(table, i, finish) <= 0
)
CHadd(p, cs, i);
}
Index: lib/libc/Makefile
===================================================================
--- lib/libc/Makefile (revision 225653)
+++ lib/libc/Makefile (working copy)
@@ -3,6 +3,9 @@
SHLIBDIR?= /lib
+DEBUG_CFLAGS+=-g
+CFLAGS+=-g
+
.include <bsd.own.mk>
# Pick the current architecture directory for libc. In general, this is
@@ -36,6 +39,7 @@
CFLAGS+=${CANCELPOINTS_CFLAGS}
.endif
+
#
# Only link with static libgcc.a (no libgcc_eh.a).
#
Index: lib/libc/gdtoa/machdep_ldisd.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisd.c (revision 225653)
+++ lib/libc/gdtoa/machdep_ldisd.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,10 +39,10 @@
__FBSDID("$FreeBSD$");
#include "gdtoaimp.h"
+#undef strtold_l
long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
-
- return strtod(s, sp);
+ return __strtod_l(s, sp, locale);
}
Index: lib/libc/gdtoa/machdep_ldisx.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisx.c (revision 225653)
+++ lib/libc/gdtoa/machdep_ldisx.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,11 @@
#include "gdtoaimp.h"
long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
long double result;
+ FIX_LOCALE(locale);
- strtorx(s, sp, FLT_ROUNDS, &result);
+ strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
return result;
}
Index: lib/libc/gdtoa/machdep_ldisQ.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisQ.c (revision 225653)
+++ lib/libc/gdtoa/machdep_ldisQ.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,10 @@
#include "gdtoaimp.h"
long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
long double result;
- strtorQ(s, sp, FLT_ROUNDS, &result);
+ strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
return result;
}
Index: lib/libc/string/strcasecmp.c
===================================================================
--- lib/libc/string/strcasecmp.c (revision 225653)
+++ lib/libc/string/strcasecmp.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,36 +40,50 @@
#include <strings.h>
#include <ctype.h>
+#include "xlocale_private.h"
typedef unsigned char u_char;
int
-strcasecmp(const char *s1, const char *s2)
+strcasecmp_l(const char *s1, const char *s2, locale_t locale)
{
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
+ FIX_LOCALE(locale);
- while (tolower(*us1) == tolower(*us2++))
+ while (tolower_l(*us1, locale) == tolower_l(*us2++, locale))
if (*us1++ == '\0')
return (0);
- return (tolower(*us1) - tolower(*--us2));
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
}
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ return strcasecmp_l(s1, s2, __get_locale());
+}
int
-strncasecmp(const char *s1, const char *s2, size_t n)
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
{
+ FIX_LOCALE(locale);
if (n != 0) {
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
do {
- if (tolower(*us1) != tolower(*us2++))
- return (tolower(*us1) - tolower(*--us2));
+ if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return (0);
}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ return strncasecmp_l(s1, s2, n, __get_locale());
+}
Index: lib/libc/string/wcscoll.c
===================================================================
--- lib/libc/string/wcscoll.c (revision 225653)
+++ lib/libc/string/wcscoll.c (working copy)
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,12 +46,15 @@
* with extended character sets.
*/
int
-wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale)
{
char *mbs1, *mbs2;
int diff, sverrno;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
- if (__collate_load_error || MB_CUR_MAX > 1)
+ if (table->__collate_load_error || MB_CUR_MAX > 1)
/*
* Locale has no special collating order, could not be
* loaded, or has an extended character set; do a fast binary
@@ -67,7 +75,7 @@
return (wcscmp(ws1, ws2));
}
- diff = strcoll(mbs1, mbs2);
+ diff = strcoll_l(mbs1, mbs2, locale);
sverrno = errno;
free(mbs1);
free(mbs2);
@@ -76,6 +84,12 @@
return (diff);
}
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+ return wcscoll_l(ws1, ws2, __get_locale());
+}
+
static char *
__mbsdup(const wchar_t *ws)
{
Index: lib/libc/string/wcswidth.c
===================================================================
--- lib/libc/string/wcswidth.c (revision 225653)
+++ lib/libc/string/wcswidth.c (working copy)
@@ -10,6 +10,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,19 +44,26 @@
__FBSDID("$FreeBSD$");
#include <wchar.h>
+#include "xlocale_private.h"
int
-wcswidth(const wchar_t *pwcs, size_t n)
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale)
{
wchar_t wc;
int len, l;
+ FIX_LOCALE(locale);
len = 0;
while (n-- > 0 && (wc = *pwcs++) != L'\0') {
- if ((l = wcwidth(wc)) < 0)
+ if ((l = wcwidth_l(wc, locale)) < 0)
return (-1);
len += l;
}
return (len);
}
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+ return wcswidth_l(pwcs, n, __get_locale());
+}
Index: lib/libc/string/Symbol.map
===================================================================
--- lib/libc/string/Symbol.map (revision 225653)
+++ lib/libc/string/Symbol.map (working copy)
@@ -75,6 +75,11 @@
wmemcpy;
wmemmove;
wmemset;
+ strcasecmp_l;
+ strcasestr_l;
+ strncasecmp_l;
+ wcswidth_l;
+ wcwidth_l;
};
FBSD_1.1 {
Index: lib/libc/string/strcoll.c
===================================================================
--- lib/libc/string/strcoll.c (revision 225653)
+++ lib/libc/string/strcoll.c (working copy)
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,21 +37,26 @@
#include <string.h>
#include "collate.h"
+#include <stdio.h>
+
int
-strcoll(const char *s, const char *s2)
+strcoll_l(const char *s, const char *s2, locale_t locale)
{
int len, len2, prim, prim2, sec, sec2, ret, ret2;
const char *t, *t2;
char *tt, *tt2;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
- if (__collate_load_error)
+ if (table->__collate_load_error)
return strcmp(s, s2);
len = len2 = 1;
ret = ret2 = 0;
- if (__collate_substitute_nontrivial) {
- t = tt = __collate_substitute(s);
- t2 = tt2 = __collate_substitute(s2);
+ if (table->__collate_substitute_nontrivial) {
+ t = tt = __collate_substitute(table, s);
+ t2 = tt2 = __collate_substitute(table, s2);
} else {
tt = tt2 = NULL;
t = s;
@@ -55,11 +65,11 @@
while(*t && *t2) {
prim = prim2 = 0;
while(*t && !prim) {
- __collate_lookup(t, &len, &prim, &sec);
+ __collate_lookup(table, t, &len, &prim, &sec);
t += len;
}
while(*t2 && !prim2) {
- __collate_lookup(t2, &len2, &prim2, &sec2);
+ __collate_lookup(table, t2, &len2, &prim2, &sec2);
t2 += len2;
}
if(!prim || !prim2)
@@ -83,3 +93,10 @@
return ret;
}
+
+int
+strcoll(const char *s, const char *s2)
+{
+ return strcoll_l(s, s2, __get_locale());
+}
+
Index: lib/libc/string/wcsxfrm.c
===================================================================
--- lib/libc/string/wcsxfrm.c (revision 225653)
+++ lib/libc/string/wcsxfrm.c (working copy)
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -43,11 +48,14 @@
* the logic used.
*/
size_t
-wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len, locale_t locale)
{
int prim, sec, l;
size_t slen;
char *mbsrc, *s, *ss;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
if (*src == L'\0') {
if (len != 0)
@@ -55,7 +63,7 @@
return (0);
}
- if (__collate_load_error || MB_CUR_MAX > 1) {
+ if (table->__collate_load_error || MB_CUR_MAX > 1) {
slen = wcslen(src);
if (len > 0) {
if (slen < len)
@@ -71,10 +79,10 @@
mbsrc = __mbsdup(src);
slen = 0;
prim = sec = 0;
- ss = s = __collate_substitute(mbsrc);
+ ss = s = __collate_substitute(table, mbsrc);
while (*s != '\0') {
while (*s != '\0' && prim == 0) {
- __collate_lookup(s, &l, &prim, &sec);
+ __collate_lookup(table, s, &l, &prim, &sec);
s += l;
}
if (prim != 0) {
@@ -93,6 +101,11 @@
return (slen);
}
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+{
+ return wcsxfrm_l(dest, src, len, __get_locale());
+}
static char *
__mbsdup(const wchar_t *ws)
Index: lib/libc/string/strcasestr.c
===================================================================
--- lib/libc/string/strcasestr.c (revision 225653)
+++ lib/libc/string/strcasestr.c (working copy)
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,26 +40,33 @@
#include <ctype.h>
#include <string.h>
+#include "xlocale_private.h"
/*
* Find the first occurrence of find in s, ignore case.
*/
char *
-strcasestr(const char *s, const char *find)
+strcasestr_l(const char *s, const char *find, locale_t locale)
{
char c, sc;
size_t len;
+ FIX_LOCALE(locale);
if ((c = *find++) != 0) {
- c = tolower((unsigned char)c);
+ c = tolower_l((unsigned char)c, locale);
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
- } while ((char)tolower((unsigned char)sc) != c);
- } while (strncasecmp(s, find, len) != 0);
+ } while ((char)tolower_l((unsigned char)sc, locale) != c);
+ } while (strncasecmp_l(s, find, len, locale) != 0);
s--;
}
return ((char *)s);
}
+char *
+strcasestr(const char *s, const char *find)
+{
+ return strcasestr_l(s, find, __get_locale());
+}
Index: lib/libc/string/strxfrm.c
===================================================================
--- lib/libc/string/strxfrm.c (revision 225653)
+++ lib/libc/string/strxfrm.c (working copy)
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,11 +38,22 @@
#include "collate.h"
size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t loc);
+size_t
strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
{
+ return strxfrm_l(dest, src, len, __get_locale());
+}
+
+size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t locale)
+{
int prim, sec, l;
size_t slen;
char *s, *ss;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
if (!*src) {
if (len > 0)
@@ -45,15 +61,15 @@
return 0;
}
- if (__collate_load_error)
+ if (table->__collate_load_error)
return strlcpy(dest, src, len);
slen = 0;
prim = sec = 0;
- ss = s = __collate_substitute(src);
+ ss = s = __collate_substitute(table, src);
while (*s) {
while (*s && !prim) {
- __collate_lookup(s, &l, &prim, &sec);
+ __collate_lookup(table, s, &l, &prim, &sec);
s += l;
}
if (prim) {
Index: sys/amd64/include/_stdint.h
===================================================================
--- sys/amd64/include/_stdint.h (revision 225653)
+++ sys/amd64/include/_stdint.h (working copy)
@@ -150,8 +150,8 @@
#define PTRDIFF_MAX INT64_MAX
/* Limits of sig_atomic_t. */
-#define SIG_ATOMIC_MIN INT32_MIN
-#define SIG_ATOMIC_MAX INT32_MAX
+#define SIG_ATOMIC_MIN LONG_MIN
+#define SIG_ATOMIC_MAX LONG_MAX
/* Limit of size_t. */
#define SIZE_MAX UINT64_MAX
Index: sys/sys/cdefs.h
===================================================================
--- sys/sys/cdefs.h (revision 225653)
+++ sys/sys/cdefs.h (working copy)
@@ -253,6 +253,17 @@
#define __LONG_LONG_SUPPORTED
#endif
+/* C++11 exposes a load of C99 stuff */
+#if __cplusplus >= 201103L
+# define __LONG_LONG_SUPPORTED
+# ifndef __STDC_LIMIT_MACROS
+# define __STDC_LIMIT_MACROS
+# endif
+# ifndef __STDC_CONSTANT_MACROS
+# define __STDC_CONSTANT_MACROS
+# endif
+#endif
+
/*
* GCC 2.95 provides `__restrict' as an extension to C90 to support the
* C99-specific `restrict' type qualifier. We happen to use `__restrict' as
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?C57AA994-0CB1-4875-8DB4-7D728B3E62AB>
