svn commit: r227753 - in head: contrib/gdtoa include lib/libc/gdtoa lib/libc/gen lib/libc/locale lib/libc/regex lib/libc/stdio lib/libc/stdlib lib/libc/stdtime lib/libc/string

David Chisnall theraven at FreeBSD.org
Sun Nov 20 14:45:42 UTC 2011


Author: theraven
Date: Sun Nov 20 14:45:42 2011
New Revision: 227753
URL: http://svn.freebsd.org/changeset/base/227753

Log:
  Implement xlocale APIs from Darwin, mainly for use by libc++.  This adds a
  load of _l suffixed versions of various standard library functions that use
  the global locale, making them take an explicit locale parameter.  Also
  adds support for per-thread locales.  This work was funded by the FreeBSD
  Foundation.
  
  Please test any code you have that uses the C standard locale functions!
  
  Reviewed by:    das (gdtoa changes)
  Approved by:    dim (mentor)

Added:
  head/include/_xlocale_ctype.h   (contents, props changed)
  head/include/xlocale.h   (contents, props changed)
  head/lib/libc/locale/DESIGN.xlocale   (contents, props changed)
  head/lib/libc/locale/ctype.c   (contents, props changed)
  head/lib/libc/locale/duplocale.3   (contents, props changed)
  head/lib/libc/locale/freelocale.3   (contents, props changed)
  head/lib/libc/locale/newlocale.3   (contents, props changed)
  head/lib/libc/locale/querylocale.3   (contents, props changed)
  head/lib/libc/locale/uselocale.3   (contents, props changed)
  head/lib/libc/locale/xlocale.3   (contents, props changed)
  head/lib/libc/locale/xlocale.c   (contents, props changed)
  head/lib/libc/locale/xlocale_private.h   (contents, props changed)
Modified:
  head/contrib/gdtoa/gdtoaimp.h
  head/contrib/gdtoa/strtod.c
  head/contrib/gdtoa/strtodg.c
  head/contrib/gdtoa/strtof.c
  head/contrib/gdtoa/strtorQ.c
  head/contrib/gdtoa/strtord.c
  head/contrib/gdtoa/strtorx.c
  head/include/Makefile
  head/include/locale.h
  head/include/runetype.h
  head/include/stdlib.h
  head/lib/libc/gdtoa/machdep_ldisQ.c
  head/lib/libc/gdtoa/machdep_ldisd.c
  head/lib/libc/gdtoa/machdep_ldisx.c
  head/lib/libc/gen/fnmatch.c
  head/lib/libc/gen/glob.c
  head/lib/libc/locale/Makefile.inc
  head/lib/libc/locale/Symbol.map
  head/lib/libc/locale/ascii.c
  head/lib/libc/locale/big5.c
  head/lib/libc/locale/btowc.c
  head/lib/libc/locale/collate.c
  head/lib/libc/locale/collate.h
  head/lib/libc/locale/collcmp.c
  head/lib/libc/locale/euc.c
  head/lib/libc/locale/gb18030.c
  head/lib/libc/locale/gb2312.c
  head/lib/libc/locale/gbk.c
  head/lib/libc/locale/lmessages.c
  head/lib/libc/locale/lmessages.h
  head/lib/libc/locale/lmonetary.c
  head/lib/libc/locale/lmonetary.h
  head/lib/libc/locale/lnumeric.c
  head/lib/libc/locale/lnumeric.h
  head/lib/libc/locale/localeconv.3
  head/lib/libc/locale/localeconv.c
  head/lib/libc/locale/mblen.c
  head/lib/libc/locale/mblocal.h
  head/lib/libc/locale/mbrlen.c
  head/lib/libc/locale/mbrtowc.c
  head/lib/libc/locale/mbsinit.c
  head/lib/libc/locale/mbsnrtowcs.c
  head/lib/libc/locale/mbsrtowcs.c
  head/lib/libc/locale/mbstowcs.c
  head/lib/libc/locale/mbtowc.c
  head/lib/libc/locale/mskanji.c
  head/lib/libc/locale/nextwctype.c
  head/lib/libc/locale/nl_langinfo.c
  head/lib/libc/locale/none.c
  head/lib/libc/locale/runetype.c
  head/lib/libc/locale/setlocale.c
  head/lib/libc/locale/setrunelocale.c
  head/lib/libc/locale/table.c
  head/lib/libc/locale/tolower.c
  head/lib/libc/locale/toupper.c
  head/lib/libc/locale/utf8.c
  head/lib/libc/locale/wcrtomb.c
  head/lib/libc/locale/wcsftime.c
  head/lib/libc/locale/wcsnrtombs.c
  head/lib/libc/locale/wcsrtombs.c
  head/lib/libc/locale/wcstod.c
  head/lib/libc/locale/wcstof.c
  head/lib/libc/locale/wcstoimax.c
  head/lib/libc/locale/wcstol.c
  head/lib/libc/locale/wcstold.c
  head/lib/libc/locale/wcstoll.c
  head/lib/libc/locale/wcstombs.c
  head/lib/libc/locale/wcstoul.c
  head/lib/libc/locale/wcstoull.c
  head/lib/libc/locale/wcstoumax.c
  head/lib/libc/locale/wctob.c
  head/lib/libc/locale/wctomb.c
  head/lib/libc/locale/wctrans.c
  head/lib/libc/locale/wctype.c
  head/lib/libc/locale/wcwidth.c
  head/lib/libc/regex/regcomp.c
  head/lib/libc/stdio/Symbol.map
  head/lib/libc/stdio/asprintf.c
  head/lib/libc/stdio/fgetwc.c
  head/lib/libc/stdio/fgetwln.c
  head/lib/libc/stdio/fgetws.c
  head/lib/libc/stdio/fprintf.c
  head/lib/libc/stdio/fputwc.c
  head/lib/libc/stdio/fputws.c
  head/lib/libc/stdio/fscanf.c
  head/lib/libc/stdio/fwprintf.c
  head/lib/libc/stdio/fwscanf.c
  head/lib/libc/stdio/getwc.c
  head/lib/libc/stdio/getwchar.c
  head/lib/libc/stdio/local.h
  head/lib/libc/stdio/printf.c
  head/lib/libc/stdio/printfcommon.h
  head/lib/libc/stdio/putwc.c
  head/lib/libc/stdio/putwchar.c
  head/lib/libc/stdio/scanf.c
  head/lib/libc/stdio/snprintf.c
  head/lib/libc/stdio/sprintf.c
  head/lib/libc/stdio/sscanf.c
  head/lib/libc/stdio/swprintf.c
  head/lib/libc/stdio/swscanf.c
  head/lib/libc/stdio/ungetwc.c
  head/lib/libc/stdio/vasprintf.c
  head/lib/libc/stdio/vdprintf.c
  head/lib/libc/stdio/vfprintf.c
  head/lib/libc/stdio/vfscanf.c
  head/lib/libc/stdio/vfwprintf.c
  head/lib/libc/stdio/vfwscanf.c
  head/lib/libc/stdio/vprintf.c
  head/lib/libc/stdio/vscanf.c
  head/lib/libc/stdio/vsnprintf.c
  head/lib/libc/stdio/vsprintf.c
  head/lib/libc/stdio/vsscanf.c
  head/lib/libc/stdio/vswprintf.c
  head/lib/libc/stdio/vswscanf.c
  head/lib/libc/stdio/vwprintf.c
  head/lib/libc/stdio/vwscanf.c
  head/lib/libc/stdio/wprintf.c
  head/lib/libc/stdio/wscanf.c
  head/lib/libc/stdlib/Symbol.map
  head/lib/libc/stdlib/atof.c
  head/lib/libc/stdlib/atoi.c
  head/lib/libc/stdlib/atol.c
  head/lib/libc/stdlib/atoll.c
  head/lib/libc/stdlib/strfmon.c
  head/lib/libc/stdlib/strtoimax.c
  head/lib/libc/stdlib/strtol.c
  head/lib/libc/stdlib/strtoll.c
  head/lib/libc/stdlib/strtoul.c
  head/lib/libc/stdlib/strtoull.c
  head/lib/libc/stdlib/strtoumax.c
  head/lib/libc/stdtime/strftime.c
  head/lib/libc/stdtime/strptime.c
  head/lib/libc/stdtime/timelocal.c
  head/lib/libc/stdtime/timelocal.h
  head/lib/libc/string/Symbol.map
  head/lib/libc/string/strcasecmp.c
  head/lib/libc/string/strcasestr.c
  head/lib/libc/string/strcoll.c
  head/lib/libc/string/strxfrm.c
  head/lib/libc/string/wcscoll.c
  head/lib/libc/string/wcswidth.c
  head/lib/libc/string/wcsxfrm.c

Modified: head/contrib/gdtoa/gdtoaimp.h
==============================================================================
--- head/contrib/gdtoa/gdtoaimp.h	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/gdtoaimp.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -201,6 +201,7 @@ THIS SOFTWARE.
 #include "namespace.h"
 #include <pthread.h>
 #include "un-namespace.h"
+#include "xlocale_private.h"
 
 #ifdef KR_headers
 #define Char char
@@ -525,11 +526,11 @@ extern void memcpy_D2A ANSI((void*, cons
 #define	strtoIQ		__strtoIQ
 #define	strtoIx		__strtoIx
 #define	strtoIxL	__strtoIxL
-#define	strtord		__strtord
+#define	strtord_l		__strtord_l
 #define	strtordd	__strtordd
 #define	strtorf		__strtorf
-#define	strtorQ		__strtorQ
-#define	strtorx		__strtorx
+#define	strtorQ_l		__strtorQ_l
+#define	strtorx_l		__strtorx_l
 #define	strtorxL	__strtorxL
 #define	strtodI		__strtodI
 #define	strtopd		__strtopd
@@ -634,7 +635,7 @@ extern void memcpy_D2A ANSI((void*, cons
  extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int));
  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,17 +645,18 @@ extern void memcpy_D2A ANSI((void*, cons
  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 *));
  extern int strtopdd ANSI((CONST char *, char **, double *));
  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 strtorx ANSI((CONST char *, char **, int, void *));
+ extern int strtorQ_l ANSI((CONST char *, char **, int, void *, locale_t));
+ 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*));

Modified: head/contrib/gdtoa/strtod.c
==============================================================================
--- head/contrib/gdtoa/strtod.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtod.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -82,11 +82,11 @@ sulp
 #endif /*}*/
 
  double
-strtod
+strtod_l
 #ifdef KR_headers
-	(s00, se) CONST char *s00; char **se;
+	(s00, se, loc) CONST char *s00; char **se; locale_t loc
 #else
-	(CONST char *s00, char **se)
+	(CONST char *s00, char **se, locale_t loc)
 #endif
 {
 #ifdef Avoid_Underflow
@@ -108,14 +108,14 @@ strtod
 #endif
 #ifdef USE_LOCALE /*{{*/
 #ifdef NO_LOCALE_CACHE
-	char *decimalpoint = localeconv()->decimal_point;
+	char *decimalpoint = localeconv_l(loc)->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(loc)->decimal_point;
 		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
 			strcpy(decimalpoint_cache, s0);
 			s0 = decimalpoint_cache;
@@ -1074,3 +1074,14 @@ strtod
 	return sign ? -dval(&rv) : dval(&rv);
 	}
 
+ double
+strtod
+#ifdef KR_headers
+	(s00, se, loc) CONST char *s00; char **se; locale_t
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+	return strtod_l(s00, se, __get_locale());
+}
+

Modified: head/contrib/gdtoa/strtodg.c
==============================================================================
--- head/contrib/gdtoa/strtodg.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtodg.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -313,12 +313,12 @@ mantbits(U *d)
 	}
 
  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, loc)
+	CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; locale_t loc;
 #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 loc)
 #endif
 {
 	int abe, abits, asub;
@@ -334,14 +334,14 @@ strtodg
 	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(loc)->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(loc)->decimal_point;
 		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
 			strcpy(decimalpoint_cache, s0);
 			s0 = decimalpoint_cache;

Modified: head/contrib/gdtoa/strtof.c
==============================================================================
--- head/contrib/gdtoa/strtof.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtof.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -35,9 +35,9 @@ THIS SOFTWARE.
 
  float
 #ifdef KR_headers
-strtof(s, sp) CONST char *s; char **sp;
+strtof_l(s, sp, loc) CONST char *s; char **sp; locale_t loc;
 #else
-strtof(CONST char *s, char **sp)
+strtof_l(CONST char *s, char **sp, locale_t loc)
 #endif
 {
 	static FPI fpi0 = { 24, 1-127-24+1,  254-127-24+1, 1, SI };
@@ -51,7 +51,7 @@ strtof(CONST char *s, char **sp)
 #define fpi &fpi0
 #endif
 
-	k = strtodg(s, sp, fpi, &exp, bits);
+	k = strtodg_l(s, sp, fpi, &exp, bits, loc);
 	switch(k & STRTOG_Retmask) {
 	  case STRTOG_NoNumber:
 	  case STRTOG_Zero:
@@ -82,3 +82,13 @@ strtof(CONST char *s, char **sp)
 		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());
+}
+

Modified: head/contrib/gdtoa/strtorQ.c
==============================================================================
--- head/contrib/gdtoa/strtorQ.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtorQ.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -103,9 +103,10 @@ ULtoQ(ULong *L, ULong *bits, Long exp, i
 
  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,7 @@ strtorQ(CONST char *s, char **sp, int ro
 		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;
 	}

Modified: head/contrib/gdtoa/strtord.c
==============================================================================
--- head/contrib/gdtoa/strtord.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtord.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -70,9 +70,10 @@ ULtod(ULong *L, ULong *bits, Long exp, i
 
  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,8 @@ strtord(CONST char *s, char **sp, int ro
 		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;
 	}
+

Modified: head/contrib/gdtoa/strtorx.c
==============================================================================
--- head/contrib/gdtoa/strtorx.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/contrib/gdtoa/strtorx.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -106,9 +106,10 @@ ULtox(UShort *L, ULong *bits, Long exp, 
 
  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,7 @@ strtorx(CONST char *s, char **sp, int ro
 		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;
 	}

Modified: head/include/Makefile
==============================================================================
--- head/include/Makefile	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/include/Makefile	Sun Nov 20 14:45:42 2011	(r227753)
@@ -24,7 +24,7 @@ INCS=	a.out.h ar.h assert.h bitstring.h 
 	strings.h sysexits.h tar.h termios.h tgmath.h \
 	time.h timeconv.h timers.h ttyent.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
 

Added: head/include/_xlocale_ctype.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/include/_xlocale_ctype.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -0,0 +1,162 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _XLOCALE_H_
+#error This header should only be included by <xlocale.h>, never directly.
+#endif
+
+#ifndef _XLOCALE_CTYPE_H_
+__BEGIN_DECLS
+unsigned long	___runetype_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t	___tolower_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t	___toupper_l(__ct_rune_t, locale_t) __pure;
+_RuneLocale	*__runes_for_locale(locale_t, int*);
+__END_DECLS
+#endif
+
+#ifndef _XLOCALE_INLINE
+#if __GNUC__ && !__GNUC_STDC_INLINE__
+#define _XLOCALE_INLINE extern inline
+#else
+#define _XLOCALE_INLINE inline
+#endif
+#endif
+
+#ifdef XLOCALE_WCTYPES
+static __inline int
+__maskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (_c < 0 || _c >= _CACHED_RUNES) ? ___runetype_l(_c, locale) :
+	       runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__istype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	return (!!__maskrune_l(_c, _f, locale));
+}
+
+#define XLOCALE_ISCTYPE(fname, cat) \
+		_XLOCALE_INLINE int isw##fname##_l(int c, locale_t l)\
+		{ return __istype_l(c, cat, l); }
+#else
+static __inline int
+__sbmaskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (_c < 0 || _c >= mb_sb_limit) ? 0 :
+	       runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__sbistype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	return (!!__sbmaskrune_l(_c, _f, locale));
+}
+
+#define XLOCALE_ISCTYPE(fname, cat) \
+		_XLOCALE_INLINE int is##fname##_l(int c, locale_t l)\
+		{ return __sbistype_l(c, cat, l); }
+#endif
+
+XLOCALE_ISCTYPE(alnum, _CTYPE_A|_CTYPE_D)
+XLOCALE_ISCTYPE(alpha, _CTYPE_A)
+XLOCALE_ISCTYPE(blank, _CTYPE_B)
+XLOCALE_ISCTYPE(cntrl, _CTYPE_C)
+XLOCALE_ISCTYPE(digit, _CTYPE_D)
+XLOCALE_ISCTYPE(graph, _CTYPE_G)
+XLOCALE_ISCTYPE(hexnumber, _CTYPE_X)
+XLOCALE_ISCTYPE(ideogram, _CTYPE_I)
+XLOCALE_ISCTYPE(lower, _CTYPE_L)
+XLOCALE_ISCTYPE(number, _CTYPE_D)
+XLOCALE_ISCTYPE(phonogram, _CTYPE_Q)
+XLOCALE_ISCTYPE(print, _CTYPE_R)
+XLOCALE_ISCTYPE(punct, _CTYPE_P)
+XLOCALE_ISCTYPE(rune, 0xFFFFFF00L)
+XLOCALE_ISCTYPE(space, _CTYPE_S)
+XLOCALE_ISCTYPE(special, _CTYPE_T)
+XLOCALE_ISCTYPE(upper, _CTYPE_U)
+XLOCALE_ISCTYPE(xdigit, _CTYPE_X)
+#undef XLOCALE_ISCTYPE
+
+#ifdef XLOCALE_WCTYPES
+_XLOCALE_INLINE int towlower_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= _CACHED_RUNES) ? ___tolower_l(c, locale) :
+	       runes->__maplower[c];
+}
+_XLOCALE_INLINE int towupper_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= _CACHED_RUNES) ? ___toupper_l(c, locale) :
+	       runes->__mapupper[c];
+}
+_XLOCALE_INLINE int
+__wcwidth_l(__ct_rune_t _c, locale_t locale)
+{
+	unsigned int _x;
+
+	if (_c == 0)
+		return (0);
+	_x = (unsigned int)__maskrune_l(_c, _CTYPE_SWM|_CTYPE_R, locale);
+	if ((_x & _CTYPE_SWM) != 0)
+		return ((_x & _CTYPE_SWM) >> _CTYPE_SWS);
+	return ((_x & _CTYPE_R) != 0 ? 1 : -1);
+}
+int iswctype_l(wint_t wc, wctype_t charclass, locale_t locale);
+wctype_t wctype_l(const char *property, locale_t locale);
+wint_t towctrans_l(wint_t wc, wctrans_t desc, locale_t locale);
+wint_t nextwctype_l(wint_t wc, wctype_t wct, locale_t locale);
+wctrans_t wctrans_l(const char *charclass, locale_t locale);
+#undef XLOCALE_WCTYPES
+#else
+_XLOCALE_INLINE int digittoint_l(int c, locale_t locale)
+{ return __sbmaskrune_l((c), 0xFF, locale); }
+
+_XLOCALE_INLINE int tolower_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= mb_sb_limit) ? c :
+	       runes->__maplower[c];
+}
+_XLOCALE_INLINE int toupper_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= mb_sb_limit) ? c :
+	       runes->__mapupper[c];
+}
+#endif

Modified: head/include/locale.h
==============================================================================
--- head/include/locale.h	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/include/locale.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -79,4 +79,52 @@ struct lconv	*localeconv(void);
 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);
+
+/**
+ * Returns an identical duplicate of the passed locale.  The returned locale
+ * must be freed with freelocale().  The returned locale will share components
+ * with the original.
+ */
+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_ */

Modified: head/include/runetype.h
==============================================================================
--- head/include/runetype.h	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/include/runetype.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -83,8 +83,14 @@ typedef struct {
 } _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_ */

Modified: head/include/stdlib.h
==============================================================================
--- head/include/stdlib.h	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/include/stdlib.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -71,10 +71,11 @@ typedef struct {
 
 #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));

Added: head/include/xlocale.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/include/xlocale.h	Sun Nov 20 14:45:42 2011	(r227753)
@@ -0,0 +1,258 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _XLOCALE_H_
+#define _XLOCALE_H_
+
+#include <locale.h>
+
+__BEGIN_DECLS
+
+/*
+ * Extended locale versions of the locale-aware functions from string.h.
+ *
+ * Include <string.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STRING_H_
+int	 strcoll_l(const char *, const char *, locale_t);
+size_t	 strxfrm_l(char *, const char *, size_t, locale_t);
+int	 strcasecmp_l(const char *, const char *, locale_t);
+char	*strcasestr_l(const char *, const char *, locale_t);
+int	 strncasecmp_l(const char *, const char *, size_t, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from inttypes.h.
+ *
+ * Include <inttypes.h> before <xlocale.h> to expose these.
+ */
+#ifdef _INTTYPES_H_
+intmax_t 
+strtoimax_l(const char * __restrict, char ** __restrict, int, locale_t);
+uintmax_t
+strtoumax_l(const char * __restrict, char ** __restrict, int, locale_t);
+intmax_t 
+wcstoimax_l(const wchar_t * __restrict, wchar_t ** __restrict, int , locale_t);
+uintmax_t
+wcstoumax_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from monetary.h.
+ *
+ * Include <monetary.h> before <xlocale.h> to expose these.
+ */
+#ifdef _MONETARY_H_
+ssize_t strfmon_l(char *, size_t, locale_t, const char *, ...)
+#	if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+	__attribute__((__format__ (__strfmon__, 4, 5)))
+#	endif
+	;
+#endif
+
+/*
+ * Extended locale versions of the locale-aware functions from stdlib.h.
+ *
+ * Include <stdlib.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STDLIB_H_
+double	 atof_l(const char *, locale_t);
+int	 atoi_l(const char *, locale_t);
+long	 atol_l(const char *, locale_t);
+long long	 atoll_l(const char *, locale_t);
+int	 mblen_l(const char *, size_t, locale_t);
+size_t
+mbstowcs_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+int
+mbtowc_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+double	 strtod_l(const char *, char **, locale_t);
+float	 strtof_l(const char *, char **, locale_t);
+long	 strtol_l(const char *, char **, int, locale_t);
+long	 double strtold_l(const char *, char **, locale_t);
+long long	 strtoll_l(const char *, char **, int, locale_t);
+unsigned long	 strtoul_l(const char *, char **, int, locale_t);
+unsigned long long	 strtoull_l(const char *, char **, int, locale_t);
+size_t
+wcstombs_l(char * __restrict, const wchar_t * __restrict, size_t, locale_t);
+int	 wctomb_l(char *, wchar_t, locale_t);
+
+int	 ___mb_cur_max_l(locale_t);
+#define MB_CUR_MAX_L(x) (___mb_cur_max_l(x))
+
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from time.h.
+ *
+ * Include <time.h> before <xlocale.h> to expose these.
+ */
+#ifdef _TIME_H_
+size_t
+strftime_l(char * __restrict, size_t, const char * __restrict, const
+           struct tm * __restrict, locale_t)
+#	if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+	__attribute__((__format__ (__strftime__, 3, 0)))
+#	endif
+	;
+char *
+strptime_l(const char * __restrict, const char * __restrict,
+           struct tm * __restrict, locale_t);
+#endif
+#ifdef _LANGINFO_H_
+char	*nl_langinfo_l(nl_item, locale_t);
+#endif
+#ifdef _CTYPE_H_
+#include <_xlocale_ctype.h>
+#endif
+#ifdef _WCTYPE_H_
+#define XLOCALE_WCTYPES 1
+#include <_xlocale_ctype.h>
+#endif
+
+#ifdef _STDIO_H_
+int	 fprintf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+		__printflike(3, 4);
+int	 fscanf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+		__scanflike(3, 4);
+int	 printf_l(locale_t, const char * __restrict, ...) __printflike(2, 3);
+int	 scanf_l(locale_t, const char * __restrict, ...) __scanflike(2, 3);
+int	 sprintf_l(char * __restrict, locale_t, const char * __restrict, ...)
+		__printflike(3, 4);
+int	 sscanf_l(const char * __restrict, locale_t, const char * __restrict, ...)
+		__scanflike(3, 4);
+int	 vfprintf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+int	 vprintf_l(locale_t, const char * __restrict, __va_list) __printflike(2, 0);
+int	 vsprintf_l(char * __restrict, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+
+int	 snprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+		...) __printflike(4, 5);
+int	 vfscanf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+		__scanflike(3, 0);
+int	 vscanf_l(locale_t, const char * __restrict, __va_list) __scanflike(2, 0);
+int	 vsnprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+		va_list) __printflike(4, 0);
+int	 vsscanf_l(const char * __restrict, locale_t, const char * __restrict,
+		va_list) __scanflike(3, 0);
+int	 dprintf_l(int, locale_t, const char * __restrict, ...) __printflike(3, 4);
+int	 vdprintf_l(int, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+int	 asprintf_l(char **, locale_t, const char *, ...) __printflike(3, 4);
+int	 vasprintf_l(char **, locale_t, const char *, __va_list) __printflike(3, 0);
+#endif
+#ifdef _WCHAR_H_
+wint_t	 btowc_l(int, locale_t);
+wint_t	 fgetwc_l(FILE *, locale_t);
+wchar_t *
+fgetws_l(wchar_t * __restrict, int, FILE * __restrict, locale_t);
+wint_t	 fputwc_l(wchar_t, FILE *, locale_t);
+int
+fputws_l(const wchar_t * __restrict, FILE * __restrict, locale_t);
+int
+fwprintf_l(FILE * __restrict, locale_t, const wchar_t * __restrict,
+		...);
+int
+fwscanf_l(FILE * __restrict, locale_t, const wchar_t * __restrict, ...);
+wint_t	 getwc_l(FILE *, 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, FILE *, 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, FILE *, locale_t);
+int
+vfwprintf_l(FILE * __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(FILE * __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, 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);
+__END_DECLS
+
+#endif

Modified: head/lib/libc/gdtoa/machdep_ldisQ.c
==============================================================================
--- head/lib/libc/gdtoa/machdep_ldisQ.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/lib/libc/gdtoa/machdep_ldisQ.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das at FreeBSD.ORG>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -38,10 +43,10 @@ __FBSDID("$FreeBSD$");
 #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;
 }

Modified: head/lib/libc/gdtoa/machdep_ldisd.c
==============================================================================
--- head/lib/libc/gdtoa/machdep_ldisd.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/lib/libc/gdtoa/machdep_ldisd.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das at FreeBSD.ORG>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -34,10 +39,11 @@
 __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);
 }

Modified: head/lib/libc/gdtoa/machdep_ldisx.c
==============================================================================
--- head/lib/libc/gdtoa/machdep_ldisx.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/lib/libc/gdtoa/machdep_ldisx.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das at FreeBSD.ORG>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -38,10 +43,11 @@ __FBSDID("$FreeBSD$");
 #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;
 }

Modified: head/lib/libc/gen/fnmatch.c
==============================================================================
--- head/lib/libc/gen/fnmatch.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/lib/libc/gen/fnmatch.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -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 @@ rangematch(pattern, test, flags, newp, p
 	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 @@ rangematch(pattern, test, flags, newp, p
 			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)

Modified: head/lib/libc/gen/glob.c
==============================================================================
--- head/lib/libc/gen/glob.c	Sun Nov 20 13:11:29 2011	(r227752)
+++ head/lib/libc/gen/glob.c	Sun Nov 20 14:45:42 2011	(r227753)
@@ -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 @@ match(Char *name, Char *pat, Char *paten
 {
 	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 @@ match(Char *name, Char *pat, Char *paten
 				++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;

Added: head/lib/libc/locale/DESIGN.xlocale
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/locale/DESIGN.xlocale	Sun Nov 20 14:45:42 2011	(r227753)
@@ -0,0 +1,159 @@
+$FreeBSD$
+
+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

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list