From owner-freebsd-hackers@FreeBSD.ORG Wed Sep 21 19:29:08 2011 Return-Path: Delivered-To: hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 56EA9106566C for ; Wed, 21 Sep 2011 19:29:08 +0000 (UTC) (envelope-from theraven@theravensnest.org) Received: from theravensnest.org (theravensnest.org [109.169.23.128]) by mx1.freebsd.org (Postfix) with ESMTP id C742A8FC15 for ; Wed, 21 Sep 2011 19:29:06 +0000 (UTC) Received: from [192.168.0.128] (cpc1-cwma5-0-0-cust192.7-3.cable.virginmedia.com [80.4.12.193]) (authenticated bits=0) by theravensnest.org (8.14.4/8.14.4) with ESMTP id p8LKPq1R064998 (version=TLSv1/SSLv3 cipher=DHE-DSS-AES128-SHA bits=128 verify=NO) for ; Wed, 21 Sep 2011 21:25:52 +0100 (BST) (envelope-from theraven@theravensnest.org) From: David Chisnall Mime-Version: 1.0 (Apple Message framework v1244.3) Content-Type: multipart/mixed; boundary="Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD" Date: Wed, 21 Sep 2011 20:28:54 +0100 In-Reply-To: <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org> To: hackers@freebsd.org References: <20110919172214.GJ33993@hoeg.nl> <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org> Message-Id: X-Mailer: Apple Mail (2.1244.3) X-Mailman-Approved-At: Wed, 21 Sep 2011 19:37:37 +0000 Cc: Subject: Re: xlocale patch X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Sep 2011 19:29:08 -0000 --Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii 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. =20 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=3D"-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=3Dc++0x -stdlib=3Dlibc++ -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=3Dc++0x -stdlib=3Dlibc++ =20 ---------------------------------------------------- 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 --Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD Content-Disposition: attachment; filename=xlocale.diff Content-Type: application/octet-stream; x-unix-mode=0644; name="xlocale.diff" Content-Transfer-Encoding: 7bit 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 + +__BEGIN_DECLS + +/* + * Extended locale versions of the locale-aware functions from string.h. + * + * Include before 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 before 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 before 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 before 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 before 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 , 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 #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 + +#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 +#include 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 * 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 #include #include +#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 +#include 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 #include #include +#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 +#include 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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#include /* * 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 #include #include +#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 +#include 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 #include +#include 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 #include +#include #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 #include +#include #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 #include #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 * 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 #include #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 #include #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 #include #include +#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 #include #include +#include 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 #include #include +#include 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 #include +#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 #include #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 +#include 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 #include #include +#include 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 * 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 #include +#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 #include #include +#include /* * 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 #include #include +#include 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 #include #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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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 #include #include +#include #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 @@ -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 * 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 #include #include +#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 -#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 #include +#include 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 #include #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 +#include +#include +#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 ; typecomponents[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 ; typecomponents[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 ; typecomponents[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 #include #include +#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 #include #include +#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 #include #include +#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 * 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 #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 +#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 +#include #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 #include #include +#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 +#include +#include #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 #include #include +#include +#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 * 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 * 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 #include #include +#include #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 * 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 #include #include +#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 * 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 #include #include +#include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #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 * 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 #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 #include #include +#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 #include #include +#include +#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 #include #include +#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 * 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 #include #include +#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 #include #include +#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 * 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 #include #include +#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 +#include +#include +#include +#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 " " +.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 +#include +#include 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 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 # 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 * 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 * 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 * 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 #include +#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 +#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 #include "collate.h" +#include + 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 #include +#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 --Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD--