aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Chisnall <theraven@FreeBSD.org>2011-11-20 14:45:42 +0000
committerDavid Chisnall <theraven@FreeBSD.org>2011-11-20 14:45:42 +0000
commit3c87aa1d3dc1d8dad3efad322852a8e1e76dee55 (patch)
tree909189922493cddbeeac84af2e316dc897661311
parent9e134d91bf553c39d4590a9e373837326c465758 (diff)
downloadsrc-3c87aa1d3dc1d8dad3efad322852a8e1e76dee55.tar.gz
src-3c87aa1d3dc1d8dad3efad322852a8e1e76dee55.zip
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)
Notes
Notes: svn path=/head/; revision=227753
-rw-r--r--contrib/gdtoa/gdtoaimp.h16
-rw-r--r--contrib/gdtoa/strtod.c21
-rw-r--r--contrib/gdtoa/strtodg.c12
-rw-r--r--contrib/gdtoa/strtof.c16
-rw-r--r--contrib/gdtoa/strtorQ.c7
-rw-r--r--contrib/gdtoa/strtord.c8
-rw-r--r--contrib/gdtoa/strtorx.c7
-rw-r--r--include/Makefile2
-rw-r--r--include/_xlocale_ctype.h162
-rw-r--r--include/locale.h48
-rw-r--r--include/runetype.h10
-rw-r--r--include/stdlib.h5
-rw-r--r--include/xlocale.h258
-rw-r--r--lib/libc/gdtoa/machdep_ldisQ.c9
-rw-r--r--lib/libc/gdtoa/machdep_ldisd.c10
-rw-r--r--lib/libc/gdtoa/machdep_ldisx.c10
-rw-r--r--lib/libc/gen/fnmatch.c13
-rw-r--r--lib/libc/gen/glob.c13
-rw-r--r--lib/libc/locale/DESIGN.xlocale159
-rw-r--r--lib/libc/locale/Makefile.inc9
-rw-r--r--lib/libc/locale/Symbol.map95
-rw-r--r--lib/libc/locale/ascii.c23
-rw-r--r--lib/libc/locale/big5.c19
-rw-r--r--lib/libc/locale/btowc.c15
-rw-r--r--lib/libc/locale/collate.c92
-rw-r--r--lib/libc/locale/collate.h28
-rw-r--r--lib/libc/locale/collcmp.c12
-rw-r--r--lib/libc/locale/ctype.c33
-rw-r--r--lib/libc/locale/duplocale.378
-rw-r--r--lib/libc/locale/euc.c19
-rw-r--r--lib/libc/locale/freelocale.361
-rw-r--r--lib/libc/locale/gb18030.c21
-rw-r--r--lib/libc/locale/gb2312.c21
-rw-r--r--lib/libc/locale/gbk.c19
-rw-r--r--lib/libc/locale/lmessages.c65
-rw-r--r--lib/libc/locale/lmessages.h9
-rw-r--r--lib/libc/locale/lmonetary.c73
-rw-r--r--lib/libc/locale/lmonetary.h13
-rw-r--r--lib/libc/locale/lnumeric.c68
-rw-r--r--lib/libc/locale/lnumeric.h13
-rw-r--r--lib/libc/locale/localeconv.315
-rw-r--r--lib/libc/locale/localeconv.c37
-rw-r--r--lib/libc/locale/mblen.c19
-rw-r--r--lib/libc/locale/mblocal.h57
-rw-r--r--lib/libc/locale/mbrlen.c20
-rw-r--r--lib/libc/locale/mbrtowc.c21
-rw-r--r--lib/libc/locale/mbsinit.c14
-rw-r--r--lib/libc/locale/mbsnrtowcs.c25
-rw-r--r--lib/libc/locale/mbsrtowcs.c20
-rw-r--r--lib/libc/locale/mbstowcs.c15
-rw-r--r--lib/libc/locale/mbtowc.c18
-rw-r--r--lib/libc/locale/mskanji.c19
-rw-r--r--lib/libc/locale/newlocale.3109
-rw-r--r--lib/libc/locale/nextwctype.c19
-rw-r--r--lib/libc/locale/nl_langinfo.c72
-rw-r--r--lib/libc/locale/none.c46
-rw-r--r--lib/libc/locale/querylocale.357
-rw-r--r--lib/libc/locale/runetype.c27
-rw-r--r--lib/libc/locale/setlocale.c5
-rw-r--r--lib/libc/locale/setrunelocale.c155
-rw-r--r--lib/libc/locale/table.c18
-rw-r--r--lib/libc/locale/tolower.c19
-rw-r--r--lib/libc/locale/toupper.c21
-rw-r--r--lib/libc/locale/uselocale.359
-rw-r--r--lib/libc/locale/utf8.c23
-rw-r--r--lib/libc/locale/wcrtomb.c21
-rw-r--r--lib/libc/locale/wcsftime.c26
-rw-r--r--lib/libc/locale/wcsnrtombs.c28
-rw-r--r--lib/libc/locale/wcsrtombs.c21
-rw-r--r--lib/libc/locale/wcstod.c37
-rw-r--r--lib/libc/locale/wcstof.c23
-rw-r--r--lib/libc/locale/wcstoimax.c23
-rw-r--r--lib/libc/locale/wcstol.c21
-rw-r--r--lib/libc/locale/wcstold.c36
-rw-r--r--lib/libc/locale/wcstoll.c21
-rw-r--r--lib/libc/locale/wcstombs.c17
-rw-r--r--lib/libc/locale/wcstoul.c21
-rw-r--r--lib/libc/locale/wcstoull.c23
-rw-r--r--lib/libc/locale/wcstoumax.c23
-rw-r--r--lib/libc/locale/wctob.c15
-rw-r--r--lib/libc/locale/wctomb.c18
-rw-r--r--lib/libc/locale/wctrans.c31
-rw-r--r--lib/libc/locale/wctype.c24
-rw-r--r--lib/libc/locale/wcwidth.c13
-rw-r--r--lib/libc/locale/xlocale.3270
-rw-r--r--lib/libc/locale/xlocale.c334
-rw-r--r--lib/libc/locale/xlocale_private.h198
-rw-r--r--lib/libc/regex/regcomp.c20
-rw-r--r--lib/libc/stdio/Symbol.map40
-rw-r--r--lib/libc/stdio/asprintf.c18
-rw-r--r--lib/libc/stdio/fgetwc.c21
-rw-r--r--lib/libc/stdio/fgetwln.c16
-rw-r--r--lib/libc/stdio/fgetws.c18
-rw-r--r--lib/libc/stdio/fprintf.c20
-rw-r--r--lib/libc/stdio/fputwc.c20
-rw-r--r--lib/libc/stdio/fputws.c17
-rw-r--r--lib/libc/stdio/fscanf.c22
-rw-r--r--lib/libc/stdio/fwprintf.c18
-rw-r--r--lib/libc/stdio/fwscanf.c18
-rw-r--r--lib/libc/stdio/getwc.c12
-rw-r--r--lib/libc/stdio/getwchar.c12
-rw-r--r--lib/libc/stdio/local.h20
-rw-r--r--lib/libc/stdio/printf.c17
-rw-r--r--lib/libc/stdio/printfcommon.h24
-rw-r--r--lib/libc/stdio/putwc.c15
-rw-r--r--lib/libc/stdio/putwchar.c15
-rw-r--r--lib/libc/stdio/scanf.c22
-rw-r--r--lib/libc/stdio/snprintf.c33
-rw-r--r--lib/libc/stdio/sprintf.c19
-rw-r--r--lib/libc/stdio/sscanf.c18
-rw-r--r--lib/libc/stdio/swprintf.c19
-rw-r--r--lib/libc/stdio/swscanf.c19
-rw-r--r--lib/libc/stdio/ungetwc.c21
-rw-r--r--lib/libc/stdio/vasprintf.c16
-rw-r--r--lib/libc/stdio/vdprintf.c8
-rw-r--r--lib/libc/stdio/vfprintf.c62
-rw-r--r--lib/libc/stdio/vfscanf.c51
-rw-r--r--lib/libc/stdio/vfwprintf.c80
-rw-r--r--lib/libc/stdio/vfwscanf.c88
-rw-r--r--lib/libc/stdio/vprintf.c12
-rw-r--r--lib/libc/stdio/vscanf.c19
-rw-r--r--lib/libc/stdio/vsnprintf.c19
-rw-r--r--lib/libc/stdio/vsprintf.c17
-rw-r--r--lib/libc/stdio/vsscanf.c19
-rw-r--r--lib/libc/stdio/vswprintf.c21
-rw-r--r--lib/libc/stdio/vswscanf.c21
-rw-r--r--lib/libc/stdio/vwprintf.c12
-rw-r--r--lib/libc/stdio/vwscanf.c12
-rw-r--r--lib/libc/stdio/wprintf.c18
-rw-r--r--lib/libc/stdio/wscanf.c18
-rw-r--r--lib/libc/stdlib/Symbol.map18
-rw-r--r--lib/libc/stdlib/atof.c14
-rw-r--r--lib/libc/stdlib/atoi.c14
-rw-r--r--lib/libc/stdlib/atol.c14
-rw-r--r--lib/libc/stdlib/atoll.c14
-rw-r--r--lib/libc/stdlib/strfmon.c43
-rw-r--r--lib/libc/stdlib/strtoimax.c17
-rw-r--r--lib/libc/stdlib/strtol.c22
-rw-r--r--lib/libc/stdlib/strtoll.c17
-rw-r--r--lib/libc/stdlib/strtoul.c16
-rw-r--r--lib/libc/stdlib/strtoull.c17
-rw-r--r--lib/libc/stdlib/strtoumax.c17
-rw-r--r--lib/libc/stdtime/strftime.c62
-rw-r--r--lib/libc/stdtime/strptime.c170
-rw-r--r--lib/libc/stdtime/timelocal.c57
-rw-r--r--lib/libc/stdtime/timelocal.h8
-rw-r--r--lib/libc/string/Symbol.map8
-rw-r--r--lib/libc/string/strcasecmp.c31
-rw-r--r--lib/libc/string/strcasestr.c20
-rw-r--r--lib/libc/string/strcoll.c31
-rw-r--r--lib/libc/string/strxfrm.c22
-rw-r--r--lib/libc/string/wcscoll.c20
-rw-r--r--lib/libc/string/wcswidth.c16
-rw-r--r--lib/libc/string/wcsxfrm.c21
154 files changed, 4587 insertions, 835 deletions
diff --git a/contrib/gdtoa/gdtoaimp.h b/contrib/gdtoa/gdtoaimp.h
index 75cdc4ef347a..285f8a182845 100644
--- a/contrib/gdtoa/gdtoaimp.h
+++ b/contrib/gdtoa/gdtoaimp.h
@@ -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*, const void*, size_t));
#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*, const void*, size_t));
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*, const void*, size_t));
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*));
diff --git a/contrib/gdtoa/strtod.c b/contrib/gdtoa/strtod.c
index fe8cde8418f2..236daa728f6c 100644
--- a/contrib/gdtoa/strtod.c
+++ b/contrib/gdtoa/strtod.c
@@ -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());
+}
+
diff --git a/contrib/gdtoa/strtodg.c b/contrib/gdtoa/strtodg.c
index 5059869ecf5f..37832b4ac31a 100644
--- a/contrib/gdtoa/strtodg.c
+++ b/contrib/gdtoa/strtodg.c
@@ -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;
diff --git a/contrib/gdtoa/strtof.c b/contrib/gdtoa/strtof.c
index 84bfe24bdd0d..26ab60f737fe 100644
--- a/contrib/gdtoa/strtof.c
+++ b/contrib/gdtoa/strtof.c
@@ -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());
+}
+
diff --git a/contrib/gdtoa/strtorQ.c b/contrib/gdtoa/strtorQ.c
index bd183bc2ac69..68f4ba43fba5 100644
--- a/contrib/gdtoa/strtorQ.c
+++ b/contrib/gdtoa/strtorQ.c
@@ -103,9 +103,10 @@ ULtoQ(ULong *L, ULong *bits, Long exp, int k)
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 rounding, void *L)
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;
}
diff --git a/contrib/gdtoa/strtord.c b/contrib/gdtoa/strtord.c
index 709af4c713f5..490f3e160926 100644
--- a/contrib/gdtoa/strtord.c
+++ b/contrib/gdtoa/strtord.c
@@ -70,9 +70,10 @@ ULtod(ULong *L, ULong *bits, Long exp, int k)
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 rounding, double *d)
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;
}
+
diff --git a/contrib/gdtoa/strtorx.c b/contrib/gdtoa/strtorx.c
index cd938f17b067..640ba6109b93 100644
--- a/contrib/gdtoa/strtorx.c
+++ b/contrib/gdtoa/strtorx.c
@@ -106,9 +106,10 @@ ULtox(UShort *L, ULong *bits, Long exp, int k)
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 rounding, void *L)
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;
}
diff --git a/include/Makefile b/include/Makefile
index 3e6705c5e3f2..c6fb5263254b 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -24,7 +24,7 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h _ctype.h ctype.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
diff --git a/include/_xlocale_ctype.h b/include/_xlocale_ctype.h
new file mode 100644
index 000000000000..1b2e21b0f1fe
--- /dev/null
+++ b/include/_xlocale_ctype.h
@@ -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
diff --git a/include/locale.h b/include/locale.h
index 83620f86d381..8df0a6a8882b 100644
--- a/include/locale.h
+++ b/include/locale.h
@@ -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_ */
diff --git a/include/runetype.h b/include/runetype.h
index a63d909ea3ca..c33ea2b6904f 100644
--- a/include/runetype.h
+++ b/include/runetype.h
@@ -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_ */
diff --git a/include/stdlib.h b/include/stdlib.h
index 3c48f1746f8e..3c26dfb0fcfb 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -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));
diff --git a/include/xlocale.h b/include/xlocale.h
new file mode 100644
index 000000000000..30fe87e66e68
--- /dev/null
+++ b/include/xlocale.h
@@ -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
diff --git a/lib/libc/gdtoa/machdep_ldisQ.c b/lib/libc/gdtoa/machdep_ldisQ.c
index ebcb37e8a6cc..7b5c7afbc108 100644
--- a/lib/libc/gdtoa/machdep_ldisQ.c
+++ b/lib/libc/gdtoa/machdep_ldisQ.c
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,10 @@ __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;
}
diff --git a/lib/libc/gdtoa/machdep_ldisd.c b/lib/libc/gdtoa/machdep_ldisd.c
index e2dbb609c359..d5c732998023 100644
--- a/lib/libc/gdtoa/machdep_ldisd.c
+++ b/lib/libc/gdtoa/machdep_ldisd.c
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,10 +39,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);
}
diff --git a/lib/libc/gdtoa/machdep_ldisx.c b/lib/libc/gdtoa/machdep_ldisx.c
index c08c85e5716f..b8e2a05790cc 100644
--- a/lib/libc/gdtoa/machdep_ldisx.c
+++ b/lib/libc/gdtoa/machdep_ldisx.c
@@ -2,6 +2,11 @@
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,11 @@ __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;
}
diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c
index 3acbc3b16473..c38aafc8b0b5 100644
--- a/lib/libc/gen/fnmatch.c
+++ b/lib/libc/gen/fnmatch.c
@@ -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, patmbs)
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, patmbs)
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)
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index c3d9f08ddc2c..59663d987540 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -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 *patend)
{
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 *patend)
++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;
diff --git a/lib/libc/locale/DESIGN.xlocale b/lib/libc/locale/DESIGN.xlocale
new file mode 100644
index 000000000000..5d998d32314d
--- /dev/null
+++ b/lib/libc/locale/DESIGN.xlocale
@@ -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
+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.
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
index 8fff0589a8dc..55800d02799f 100644
--- a/lib/libc/locale/Makefile.inc
+++ b/lib/libc/locale/Makefile.inc
@@ -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 @@ SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
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
@@ -37,7 +38,9 @@ MAN+= btowc.3 \
wcsftime.3 \
wcrtomb.3 \
wcsrtombs.3 wcstod.3 wcstol.3 wcstombs.3 wctomb.3 \
- wctrans.3 wctype.3 wcwidth.3
+ wctrans.3 wctype.3 wcwidth.3 \
+ duplocale.3 freelocale.3 newlocale.3 querylocale.3 uselocale.3 xlocale.3
+
MAN+= big5.5 euc.5 gb18030.5 gb2312.5 gbk.5 mskanji.5 utf8.5
MLINKS+=btowc.3 wctob.3
diff --git a/lib/libc/locale/Symbol.map b/lib/libc/locale/Symbol.map
index 20d092bb1076..01242b694f7a 100644
--- a/lib/libc/locale/Symbol.map
+++ b/lib/libc/locale/Symbol.map
@@ -101,6 +101,101 @@ FBSD_1.0 {
wcwidth;
};
+FBSD_1.3 {
+ 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 {
_PathLocale;
__detect_path_locale;
diff --git a/lib/libc/locale/ascii.c b/lib/libc/locale/ascii.c
index 493bf42f395d..784814d2664d 100644
--- a/lib/libc/locale/ascii.c
+++ b/lib/libc/locale/ascii.c
@@ -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 @@ static size_t _ascii_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
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);
}
diff --git a/lib/libc/locale/big5.c b/lib/libc/locale/big5.c
index 19977d035dc5..4b37265ad159 100644
--- a/lib/libc/locale/big5.c
+++ b/lib/libc/locale/big5.c
@@ -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 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/btowc.c b/lib/libc/locale/btowc.c
index 2c4d493b89a1..72507bc857e1 100644
--- a/lib/libc/locale/btowc.c
+++ b/lib/libc/locale/btowc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ btowc(int c)
* 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());
+}
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
index 683359800d61..e87b6dc7e1be 100644
--- a/lib/libc/locale/collate.c
+++ b/lib/libc/locale/collate.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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
+};
+
+ struct xlocale_collate __xlocale_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 &__xlocale_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 @@ __collate_load_tables(const char *encoding)
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 @@ __collate_load_tables(const char *encoding)
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 @@ __collate_load_tables(const char *encoding)
}
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 @@ __collate_substitute(const u_char *s)
}
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;
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
index 2f5f5d40eff0..ad034d4ba71e 100644
--- a/lib/libc/locale/collate.h
+++ b/lib/libc/locale/collate.h
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,6 +38,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
+#include "xlocale_private.h"
#define STR_LEN 10
#define TABLE_SIZE 100
@@ -47,20 +53,26 @@ struct __collate_st_chain_pri {
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
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
index 313e04384f2e..aa17afdbc3c0 100644
--- a/lib/libc/locale/collcmp.c
+++ b/lib/libc/locale/collcmp.c
@@ -2,6 +2,11 @@
* Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,17 +33,20 @@
__FBSDID("$FreeBSD$");
#include <string.h>
+#include <xlocale.h>
#include "collate.h"
/*
* Compare two characters using collate
*/
-int __collate_range_cmp(int c1, int c2)
+int __collate_range_cmp(struct xlocale_collate *table, int c1, int c2)
{
static char s1[2], s2[2];
s1[0] = c1;
s2[0] = c2;
- return (strcoll(s1, s2));
+ struct _xlocale l = {{0}};
+ l.components[XLC_COLLATE] = (struct xlocale_component *)table;
+ return (strcoll_l(s1, s2, &l));
}
diff --git a/lib/libc/locale/ctype.c b/lib/libc/locale/ctype.c
new file mode 100644
index 000000000000..f0ec3f6d8b0f
--- /dev/null
+++ b/lib/libc/locale/ctype.c
@@ -0,0 +1,33 @@
+/*-
+ * 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$
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
diff --git a/lib/libc/locale/duplocale.3 b/lib/libc/locale/duplocale.3
new file mode 100644
index 000000000000..19d2569c0499
--- /dev/null
+++ b/lib/libc/locale/duplocale.3
@@ -0,0 +1,78 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.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
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
index 188073e49e38..26ad413156cd 100644
--- a/lib/libc/locale/euc.c
+++ b/lib/libc/locale/euc.c
@@ -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 @@ typedef struct {
} _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 @@ _EUC_init(_RuneLocale *rl)
}
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);
}
diff --git a/lib/libc/locale/freelocale.3 b/lib/libc/locale/freelocale.3
new file mode 100644
index 000000000000..cf7174d12fa5
--- /dev/null
+++ b/lib/libc/locale/freelocale.3
@@ -0,0 +1,61 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.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 .
diff --git a/lib/libc/locale/gb18030.c b/lib/libc/locale/gb18030.c
index 1457d3e7540c..92143852dd76 100644
--- a/lib/libc/locale/gb18030.c
+++ b/lib/libc/locale/gb18030.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB18030_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB18030_mbsinit(const mbstate_t *);
@@ -53,15 +56,15 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/gb2312.c b/lib/libc/locale/gb2312.c
index 74a7bdc3be79..5fbc07dada01 100644
--- a/lib/libc/locale/gb2312.c
+++ b/lib/libc/locale/gb2312.c
@@ -3,6 +3,11 @@
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,8 +40,6 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB2312_mbsinit(const mbstate_t *);
@@ -49,15 +52,15 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/gbk.c b/lib/libc/locale/gbk.c
index 802f78e7c177..43269c7ae8e7 100644
--- a/lib/libc/locale/gbk.c
+++ b/lib/libc/locale/gbk.c
@@ -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 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c
index 3498be2a6e8e..a0664d074ecd 100644
--- a/lib/libc/locale/lmessages.c
+++ b/lib/libc/locale/lmessages.c
@@ -2,6 +2,11 @@
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,6 +41,14 @@ __FBSDID("$FreeBSD$");
#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 @@ static const struct lc_messages_T _C_messages_locale = {
"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);
}
diff --git a/lib/libc/locale/lmessages.h b/lib/libc/locale/lmessages.h
index 41dcfa98ca6b..ea9c57e28943 100644
--- a/lib/libc/locale/lmessages.h
+++ b/lib/libc/locale/lmessages.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -29,6 +34,8 @@
#ifndef _LMESSAGES_H_
#define _LMESSAGES_H_
+#include "xlocale_private.h"
+
struct lc_messages_T {
const char *yesexpr;
const char *noexpr;
@@ -36,7 +43,7 @@ struct lc_messages_T {
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_ */
diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c
index 8d55ab2c6e5d..a9d67d3708b8 100644
--- a/lib/libc/locale/lmonetary.c
+++ b/lib/libc/locale/lmonetary.c
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,7 +39,6 @@ __FBSDID("$FreeBSD$");
#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 @@ static const struct lc_monetary_T _C_monetary_locale = {
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 @@ cnv(const char *str)
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 @@ __monetary_load_locale(const char *name)
*/
#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 @@ __monetary_load_locale(const char *name)
}
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);
}
diff --git a/lib/libc/locale/lmonetary.h b/lib/libc/locale/lmonetary.h
index 45ec3235b578..b606862f54af 100644
--- a/lib/libc/locale/lmonetary.h
+++ b/lib/libc/locale/lmonetary.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,6 +33,7 @@
#ifndef _LMONETARY_H_
#define _LMONETARY_H_
+#include "xlocale_private.h"
struct lc_monetary_T {
const char *int_curr_symbol;
@@ -52,8 +58,13 @@ struct lc_monetary_T {
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_ */
diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c
index d4ed04f65945..a2468f4e28b5 100644
--- a/lib/libc/locale/lnumeric.c
+++ b/lib/libc/locale/lnumeric.c
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,7 +37,6 @@ __FBSDID("$FreeBSD$");
#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 @@ static const struct lc_numeric_T _C_numeric_locale = {
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);
+}
+
+struct xlocale_numeric __xlocale_global_numeric;
-int
-__numeric_load_locale(const char *name)
+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);
}
diff --git a/lib/libc/locale/lnumeric.h b/lib/libc/locale/lnumeric.h
index cc6965b62cc7..5088dd444b5f 100644
--- a/lib/libc/locale/lnumeric.h
+++ b/lib/libc/locale/lnumeric.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,14 +33,20 @@
#ifndef _LNUMERIC_H_
#define _LNUMERIC_H_
+#include "xlocale_private.h"
struct lc_numeric_T {
const char *decimal_point;
const char *thousands_sep;
const char *grouping;
};
+struct xlocale_numeric {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_numeric_T locale;
+};
-struct lc_numeric_T *__get_current_numeric_locale(void);
+struct lc_numeric_T *__get_current_numeric_locale(locale_t loc);
int __numeric_load_locale(const char *);
#endif /* !_LNUMERIC_H_ */
diff --git a/lib/libc/locale/localeconv.3 b/lib/libc/locale/localeconv.3
index c4b5746a8f92..6ebb8781814f 100644
--- a/lib/libc/locale/localeconv.3
+++ b/lib/libc/locale/localeconv.3
@@ -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 value that is not in the current locale.
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 @@ which may be altered by later calls to
.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
diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c
index fed8d3587901..4b19160c35dd 100644
--- a/lib/libc/locale/localeconv.c
+++ b/lib/libc/locale/localeconv.c
@@ -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 @@ __FBSDID("$FreeBSD$");
* 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 @@ localeconv()
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());
}
diff --git a/lib/libc/locale/mblen.c b/lib/libc/locale/mblen.c
index 4a2cc5cbcde8..1bacf3eb837b 100644
--- a/lib/libc/locale/mblen.c
+++ b/lib/libc/locale/mblen.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
+}
diff --git a/lib/libc/locale/mblocal.h b/lib/libc/locale/mblocal.h
index 0faebe502c6f..d172764e79de 100644
--- a/lib/libc/locale/mblocal.h
+++ b/lib/libc/locale/mblocal.h
@@ -2,6 +2,11 @@
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,35 +35,45 @@
#define _MBLOCAL_H_
#include <runetype.h>
+#include "xlocale_private.h"
+
/*
- * Rune initialization function prototypes.
+ * Conversion function pointers for current encoding.
*/
-int _none_init(_RuneLocale *);
-int _ascii_init(_RuneLocale *);
-int _UTF8_init(_RuneLocale *);
-int _EUC_init(_RuneLocale *);
-int _GB18030_init(_RuneLocale *);
-int _GB2312_init(_RuneLocale *);
-int _GBK_init(_RuneLocale *);
-int _BIG5_init(_RuneLocale *);
-int _MSKanji_init(_RuneLocale *);
+struct xlocale_ctype {
+ struct xlocale_component header;
+ _RuneLocale *runes;
+ size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+ int (*__mbsinit)(const mbstate_t *);
+ size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
+ size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ int __mb_cur_max;
+ int __mb_sb_limit;
+};
+#define XLOCALE_CTYPE(x) ((struct xlocale_ctype*)(x)->components[XLC_CTYPE])
+extern struct xlocale_ctype __xlocale_global_ctype;
/*
- * Conversion function pointers for current encoding.
+ * Rune initialization function prototypes.
*/
-extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
- size_t, mbstate_t * __restrict);
-extern int (*__mbsinit)(const mbstate_t *);
-extern size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
-extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
-extern size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+int _none_init(struct xlocale_ctype *, _RuneLocale *);
+int _ascii_init(struct xlocale_ctype *, _RuneLocale *);
+int _UTF8_init(struct xlocale_ctype *, _RuneLocale *);
+int _EUC_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB18030_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB2312_init(struct xlocale_ctype *, _RuneLocale *);
+int _GBK_init(struct xlocale_ctype *, _RuneLocale *);
+int _BIG5_init(struct xlocale_ctype *, _RuneLocale *);
+int _MSKanji_init(struct xlocale_ctype *, _RuneLocale *);
extern size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
#endif /* _MBLOCAL_H_ */
diff --git a/lib/libc/locale/mbrlen.c b/lib/libc/locale/mbrlen.c
index b4c3a04694d4..9ce0bc067642 100644
--- a/lib/libc/locale/mbrlen.c
+++ b/lib/libc/locale/mbrlen.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c
index 42d5f7a178d6..8f1aebd5762a 100644
--- a/lib/libc/locale/mbrtowc.c
+++ b/lib/libc/locale/mbrtowc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/mbsinit.c b/lib/libc/locale/mbsinit.c
index 24408c7f573e..be44fe5e31c0 100644
--- a/lib/libc/locale/mbsinit.c
+++ b/lib/libc/locale/mbsinit.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c
index 5284087fb4c1..15b48dd72d12 100644
--- a/lib/libc/locale/mbsnrtowcs.c
+++ b/lib/libc/locale/mbsnrtowcs.c
@@ -1,5 +1,10 @@
/*-
* 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
@@ -34,14 +39,19 @@ __FBSDID("$FreeBSD$");
#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 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
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 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
}
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) {
diff --git a/lib/libc/locale/mbsrtowcs.c b/lib/libc/locale/mbsrtowcs.c
index 1239c82c337f..9032b94fffba 100644
--- a/lib/libc/locale/mbsrtowcs.c
+++ b/lib/libc/locale/mbsrtowcs.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/mbstowcs.c b/lib/libc/locale/mbstowcs.c
index 194ec2e03534..6905d2e6604e 100644
--- a/lib/libc/locale/mbstowcs.c
+++ b/lib/libc/locale/mbstowcs.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/mbtowc.c b/lib/libc/locale/mbtowc.c
index ad5b73525635..70fc19ea3500 100644
--- a/lib/libc/locale/mbtowc.c
+++ b/lib/libc/locale/mbtowc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
+}
diff --git a/lib/libc/locale/mskanji.c b/lib/libc/locale/mskanji.c
index 9ee91de28c15..9fdd0803f735 100644
--- a/lib/libc/locale/mskanji.c
+++ b/lib/libc/locale/mskanji.c
@@ -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 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/newlocale.3 b/lib/libc/locale/newlocale.3
new file mode 100644
index 000000000000..b351f99e6b0a
--- /dev/null
+++ b/lib/libc/locale/newlocale.3
@@ -0,0 +1,109 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.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
diff --git a/lib/libc/locale/nextwctype.c b/lib/libc/locale/nextwctype.c
index 9363b0a700cc..9fc8ce05ecee 100644
--- a/lib/libc/locale/nextwctype.c
+++ b/lib/libc/locale/nextwctype.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <runetype.h>
#include <wchar.h>
#include <wctype.h>
+#include "mblocal.h"
wint_t
-nextwctype(wint_t wc, wctype_t wct)
+nextwctype_l(wint_t wc, wctype_t wct, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneLocale *runes = XLOCALE_CTYPE(locale)->runes;
+ _RuneRange *rr = &runes->__runetype_ext;
_RuneEntry *base, *re;
int noinc;
@@ -43,7 +51,7 @@ nextwctype(wint_t wc, wctype_t wct)
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 @@ found:
}
return (-1);
}
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+ return nextwctype_l(wc, wct, __get_locale());
+}
diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c
index 26ca02544982..3e8fe7cc6d3d 100644
--- a/lib/libc/locale/nl_langinfo.c
+++ b/lib/libc/locale/nl_langinfo.c
@@ -2,6 +2,11 @@
* Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,15 +46,16 @@ __FBSDID("$FreeBSD$");
#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 @@ nl_langinfo(nl_item item)
}
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 @@ nl_langinfo(nl_item item)
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 @@ nl_langinfo(nl_item item)
* 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());
+}
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
index 22fcd203937b..75adffaa96df 100644
--- a/lib/libc/locale/none.c
+++ b/lib/libc/locale/none.c
@@ -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_cur_max = 1;
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,26 @@ 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) = _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 */
+};
+
+const struct xlocale_ctype __xlocale_C_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3
new file mode 100644
index 000000000000..ceb4da053c9f
--- /dev/null
+++ b/lib/libc/locale/querylocale.3
@@ -0,0 +1,57 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.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
diff --git a/lib/libc/locale/runetype.c b/lib/libc/locale/runetype.c
index 5765b855073a..a0da47b5de98 100644
--- a/lib/libc/locale/runetype.c
+++ b/lib/libc/locale/runetype.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
unsigned long
-___runetype(__ct_rune_t c)
+___runetype_l(__ct_rune_t c, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext);
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -64,3 +72,18 @@ ___runetype(__ct_rune_t c)
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;
+}
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
index d6db1813d2a0..8cf8fd4fec91 100644
--- a/lib/libc/locale/setlocale.c
+++ b/lib/libc/locale/setlocale.c
@@ -95,7 +95,7 @@ static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
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 @@ loadlocale(category)
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;
{
diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c
index 36d28946e3b4..61ce5d9f925c 100644
--- a/lib/libc/locale/setrunelocale.c
+++ b/lib/libc/locale/setrunelocale.c
@@ -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 int __mb_sb_limit;
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 @@ __setrunelocale(const char *encoding)
}
(void)fclose(fp);
- old__mbrtowc = __mbrtowc;
- old__mbsinit = __mbsinit;
- old__mbsnrtowcs = __mbsnrtowcs;
- old__wcrtomb = __wcrtomb;
- old__wcsnrtombs = __wcsnrtombs;
-
- __mbrtowc = NULL;
- __mbsinit = NULL;
- __mbsnrtowcs = __mbsnrtowcs_std;
- __wcrtomb = NULL;
- __wcsnrtombs = __wcsnrtombs_std;
+ l->__mbrtowc = NULL;
+ l->__mbsinit = NULL;
+ l->__mbsnrtowcs = __mbsnrtowcs_std;
+ l->__wcrtomb = NULL;
+ l->__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 @@ __setrunelocale(const char *encoding)
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;
+}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
index e1f49d189a62..8c876e95a124 100644
--- a/lib/libc/locale/table.c
+++ b/lib/libc/locale/table.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-_RuneLocale _DefaultRuneLocale = {
+const _RuneLocale _DefaultRuneLocale = {
_RUNE_MAGIC_1,
"NONE",
NULL,
@@ -245,5 +250,14 @@ _RuneLocale _DefaultRuneLocale = {
},
};
-_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;
+}
diff --git a/lib/libc/locale/tolower.c b/lib/libc/locale/tolower.c
index 82a78cfdc9b9..f2eb48313c63 100644
--- a/lib/libc/locale/tolower.c
+++ b/lib/libc/locale/tolower.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___tolower(c)
+___tolower_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__maplower_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -62,3 +71,9 @@ ___tolower(c)
return(c);
}
+__ct_rune_t
+___tolower(c)
+ __ct_rune_t c;
+{
+ return ___tolower_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/toupper.c b/lib/libc/locale/toupper.c
index 4870e8e12cbb..d3a4fa3e7e07 100644
--- a/lib/libc/locale/toupper.c
+++ b/lib/libc/locale/toupper.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___toupper(c)
+___toupper_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__mapupper_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -53,7 +62,9 @@ ___toupper(c)
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 @@ ___toupper(c)
return(c);
}
+__ct_rune_t
+___toupper(c)
+ __ct_rune_t c;
+{
+ return ___toupper_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/uselocale.3 b/lib/libc/locale/uselocale.3
new file mode 100644
index 000000000000..a7068b434345
--- /dev/null
+++ b/lib/libc/locale/uselocale.3
@@ -0,0 +1,59 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.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
diff --git a/lib/libc/locale/utf8.c b/lib/libc/locale/utf8.c
index 0ccadd3e8d3b..40f0e1701bd5 100644
--- a/lib/libc/locale/utf8.c
+++ b/lib/libc/locale/utf8.c
@@ -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 @@ typedef struct {
} _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);
}
diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c
index ef75b78f3760..32d4df2af64c 100644
--- a/lib/libc/locale/wcrtomb.c
+++ b/lib/libc/locale/wcrtomb.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/wcsftime.c b/lib/libc/locale/wcsftime.c
index a546dc646a60..c4f6b2ee4e5f 100644
--- a/lib/libc/locale/wcsftime.c
+++ b/lib/libc/locale/wcsftime.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <time.h>
#include <wchar.h>
+#include "xlocale_private.h"
/*
* Convert date and time to a wide-character string.
@@ -47,8 +53,9 @@ __FBSDID("$FreeBSD$");
* 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 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
const wchar_t *formatp;
size_t n, sflen;
int sverrno;
+ FIX_LOCALE(locale);
sformat = dst = NULL;
@@ -66,13 +74,13 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
*/
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 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
}
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 @@ error:
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());
+}
diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c
index e89969820957..2f3bf1e8d245 100644
--- a/lib/libc/locale/wcsnrtombs.c
+++ b/lib/libc/locale/wcsnrtombs.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
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 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
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 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
* 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);
}
diff --git a/lib/libc/locale/wcsrtombs.c b/lib/libc/locale/wcsrtombs.c
index f3b38b71c4d8..f6d1ca07f523 100644
--- a/lib/libc/locale/wcsrtombs.c
+++ b/lib/libc/locale/wcsrtombs.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
diff --git a/lib/libc/locale/wcstod.c b/lib/libc/locale/wcstod.c
index 68df1eddfedd..8bc46a7c3ad4 100644
--- a/lib/libc/locale/wcstod.c
+++ b/lib/libc/locale/wcstod.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a double-precision number.
@@ -41,17 +47,22 @@ __FBSDID("$FreeBSD$");
* 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 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
* 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 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
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 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
* 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());
+}
diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c
index ba238d459031..93a5af838187 100644
--- a/lib/libc/locale/wcstof.c
+++ b/lib/libc/locale/wcstof.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
float
-wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -43,13 +50,14 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
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 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
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 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
return (val);
}
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstof_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c
index 66e692ad71a8..ce066a53462b 100644
--- a/lib/libc/locale/wcstoimax.c
+++ b/lib/libc/locale/wcstoimax.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an intmax_t integer.
*/
intmax_t
-wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -88,8 +95,8 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c
index 294b6e0a4989..2b21d126c700 100644
--- a/lib/libc/locale/wcstol.c
+++ b/lib/libc/locale/wcstol.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a long integer.
*/
long
-wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
+ base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -81,8 +89,8 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c
index cf9d87464c5d..fcfd48f12d01 100644
--- a/lib/libc/locale/wcstold.c
+++ b/lib/libc/locale/wcstold.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
long double
-wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
long double val;
char *buf, *end;
- const wchar_t *wcp;
+ const wchar_t *wcp = nptr;
size_t len;
+ size_t spaces = 0;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
- nptr++;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -57,14 +68,23 @@ wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
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());
+}
diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c
index 19b285fb8317..f246502bb2fa 100644
--- a/lib/libc/locale/wcstoll.c
+++ b/lib/libc/locale/wcstoll.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a long long integer.
*/
long long
-wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoll for comments as to the logic used.
@@ -60,7 +68,7 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -87,8 +95,8 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wcstombs.c b/lib/libc/locale/wcstombs.c
index 250d2b9b1047..8d4ae1c0b4e1 100644
--- a/lib/libc/locale/wcstombs.c
+++ b/lib/libc/locale/wcstombs.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
}
+
diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c
index f50e7a74d818..54e6b4fb9111 100644
--- a/lib/libc/locale/wcstoul.c
+++ b/lib/libc/locale/wcstoul.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long integer.
*/
unsigned long
-wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -79,8 +87,8 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c
index d84042458b12..c56ee770f032 100644
--- a/lib/libc/locale/wcstoull.c
+++ b/lib/libc/locale/wcstoull.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long long integer.
*/
unsigned long long
-wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoull for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c
index d643b0b24884..397c1e37410f 100644
--- a/lib/libc/locale/wcstoumax.c
+++ b/lib/libc/locale/wcstoumax.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a uintmax_t integer.
*/
uintmax_t
-wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c
index cb39adc45141..96e8b730a903 100644
--- a/lib/libc/locale/wctob.c
+++ b/lib/libc/locale/wctob.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
+}
diff --git a/lib/libc/locale/wctomb.c b/lib/libc/locale/wctomb.c
index 77b9043d61e1..da3d2635a967 100644
--- a/lib/libc/locale/wctomb.c
+++ b/lib/libc/locale/wctomb.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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());
+}
diff --git a/lib/libc/locale/wctrans.c b/lib/libc/locale/wctrans.c
index 6813e3304629..0831146b0103 100644
--- a/lib/libc/locale/wctrans.c
+++ b/lib/libc/locale/wctrans.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <string.h>
#include <wctype.h>
+#include "xlocale_private.h"
enum {
_WCT_ERROR = 0,
@@ -38,15 +44,14 @@ enum {
};
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 @@ towctrans(wint_t wc, wctrans_t desc)
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 @@ wctrans(const char *charclass)
errno = EINVAL;
return (ccls[i].trans);
}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ return wctrans_l(charclass, 0);
+}
+
diff --git a/lib/libc/locale/wctype.c b/lib/libc/locale/wctype.c
index f94a735d4e9c..5ffbb7905f1e 100644
--- a/lib/libc/locale/wctype.c
+++ b/lib/libc/locale/wctype.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <string.h>
#include <wctype.h>
+#include <xlocale.h>
#undef iswctype
int
iswctype(wint_t wc, wctype_t charclass)
{
-
return (__istype(wc, charclass));
}
+int
+iswctype_l(wint_t wc, wctype_t charclass, locale_t locale)
+{
+ return __istype_l(wc, charclass, locale);
+}
+/*
+ * IMPORTANT: The 0 in the call to this function in wctype() must be changed to
+ * __get_locale() if wctype_l() is 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 @@ wctype(const char *property)
return (props[i].mask);
}
+
+wctype_t wctype(const char *property)
+{
+ return wctype_l(property, 0);
+}
diff --git a/lib/libc/locale/wcwidth.c b/lib/libc/locale/wcwidth.c
index 7a5d2eda2bfd..9e74217f6d8e 100644
--- a/lib/libc/locale/wcwidth.c
+++ b/lib/libc/locale/wcwidth.c
@@ -10,6 +10,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,12 +44,18 @@
__FBSDID("$FreeBSD$");
#include <wchar.h>
+#include <wctype.h>
+#include <xlocale.h>
#undef wcwidth
int
wcwidth(wchar_t wc)
{
-
return (__wcwidth(wc));
}
+int
+wcwidth_l(wchar_t wc, locale_t locale)
+{
+ return (__wcwidth_l(wc, locale));
+}
diff --git a/lib/libc/locale/xlocale.3 b/lib/libc/locale/xlocale.3
new file mode 100644
index 000000000000..ecfbb4c1ff1a
--- /dev/null
+++ b/lib/libc/locale/xlocale.3
@@ -0,0 +1,270 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.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 opaque 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. Each of these functions
+accepts either NULL or LC_GLOBAL_LOCALE. In these functions, NULL refers to
+the C locale, rather than the thread's current locale. If you wish to use the
+thread's current locale, then use the unsuffixed version of the function.
+.Pp
+These functions are exposed by including
+.In xlocale.h
+.Em after
+including the relevant headers for the standard variant. For example, the
+.Xr strtol_l 3
+function is exposed by including
+.In xlocale.h
+after
+.In stdlib.h ,
+which defines
+.Xr strtol 3 .
+.Pp
+For reference, a complete list of the locale-aware functions that are available
+in this form, along with the headers that expose them, is provided here:
+.Pp
+.Bl -tag -width "<monetary.h> "
+.It In wctype.h
+.Xr iswalnum_l 3 ,
+.Xr iswalpha_l 3 ,
+.Xr iswcntrl_l 3 ,
+.Xr iswctype_l 3 ,
+.Xr iswdigit_l 3 ,
+.Xr iswgraph_l 3 ,
+.Xr iswlower_l 3 ,
+.Xr iswprint_l 3 ,
+.Xr iswpunct_l 3 ,
+.Xr iswspace_l 3 ,
+.Xr iswupper_l 3 ,
+.Xr iswxdigit_l 3 ,
+.Xr towlower_l 3 ,
+.Xr towupper_l 3 ,
+.Xr wctype_l 3 ,
+.It In ctype.h
+.Xr digittoint_l 3 ,
+.Xr isalnum_l 3 ,
+.Xr isalpha_l 3 ,
+.Xr isblank_l 3 ,
+.Xr iscntrl_l 3 ,
+.Xr isdigit_l 3 ,
+.Xr isgraph_l 3 ,
+.Xr ishexnumber_l 3 ,
+.Xr isideogram_l 3 ,
+.Xr islower_l 3 ,
+.Xr isnumber_l 3 ,
+.Xr isphonogram_l 3 ,
+.Xr isprint_l 3 ,
+.Xr ispunct_l 3 ,
+.Xr isrune_l 3 ,
+.Xr isspace_l 3 ,
+.Xr isspecial_l 3 ,
+.Xr isupper_l 3 ,
+.Xr isxdigit_l 3 ,
+.Xr tolower_l 3 ,
+.Xr toupper_l 3
+.It In inttypes.h
+.Xr strtoimax_l 3 ,
+.Xr strtoumax_l 3 ,
+.Xr wcstoimax_l 3 ,
+.Xr wcstoumax_l 3
+.It In langinfo.h
+.Xr nl_langinfo_l 3
+.It In monetary.h
+.Xr strfmon_l 3
+.It In stdio.h
+.Xr asprintf_l 3 ,
+.Xr fprintf_l 3 ,
+.Xr fscanf_l 3 ,
+.Xr printf_l 3 ,
+.Xr scanf_l 3 ,
+.Xr snprintf_l 3 ,
+.Xr sprintf_l 3 ,
+.Xr sscanf_l 3 ,
+.Xr vasprintf_l 3 ,
+.Xr vfprintf_l 3 ,
+.Xr vfscanf_l 3 ,
+.Xr vprintf_l 3 ,
+.Xr vscanf_l 3 ,
+.Xr vsnprintf_l 3 ,
+.Xr vsprintf_l 3 ,
+.Xr vsscanf_l 3
+.It In stdlib.h
+.Xr atof_l 3 ,
+.Xr atoi_l 3 ,
+.Xr atol_l 3 ,
+.Xr atoll_l 3 ,
+.Xr mblen_l 3 ,
+.Xr mbstowcs_l 3 ,
+.Xr mbtowc_l 3 ,
+.Xr strtod_l 3 ,
+.Xr strtof_l 3 ,
+.Xr strtol_l 3 ,
+.Xr strtold_l 3 ,
+.Xr strtoll_l 3 ,
+.Xr strtoq_l 3 ,
+.Xr strtoul_l 3 ,
+.Xr strtoull_l 3 ,
+.Xr strtouq_l 3 ,
+.Xr wcstombs_l 3 ,
+.Xr wctomb_l 3
+.It In string.h
+.Xr strcoll_l 3 ,
+.Xr strxfrm_l 3 ,
+.Xr strcasecmp_l 3 ,
+.Xr strcasestr_l 3 ,
+.Xr strncasecmp_l 3
+.It In time.h
+.Xr strftime_l 3
+.Xr strptime_l 3
+.It In wchar.h
+.Xr btowc_l 3 ,
+.Xr fgetwc_l 3 ,
+.Xr fgetws_l 3 ,
+.Xr fputwc_l 3 ,
+.Xr fputws_l 3 ,
+.Xr fwprintf_l 3 ,
+.Xr fwscanf_l 3 ,
+.Xr getwc_l 3 ,
+.Xr getwchar_l 3 ,
+.Xr mbrlen_l 3 ,
+.Xr mbrtowc_l 3 ,
+.Xr mbsinit_l 3 ,
+.Xr mbsnrtowcs_l 3 ,
+.Xr mbsrtowcs_l 3 ,
+.Xr putwc_l 3 ,
+.Xr putwchar_l 3 ,
+.Xr swprintf_l 3 ,
+.Xr swscanf_l 3 ,
+.Xr ungetwc_l 3 ,
+.Xr vfwprintf_l 3 ,
+.Xr vfwscanf_l 3 ,
+.Xr vswprintf_l 3 ,
+.Xr vswscanf_l 3 ,
+.Xr vwprintf_l 3 ,
+.Xr vwscanf_l 3 ,
+.Xr wcrtomb_l 3 ,
+.Xr wcscoll_l 3 ,
+.Xr wcsftime_l 3 ,
+.Xr wcsnrtombs_l 3 ,
+.Xr wcsrtombs_l 3 ,
+.Xr wcstod_l 3 ,
+.Xr wcstof_l 3 ,
+.Xr wcstol_l 3 ,
+.Xr wcstold_l 3 ,
+.Xr wcstoll_l 3 ,
+.Xr wcstoul_l 3 ,
+.Xr wcstoull_l 3 ,
+.Xr wcswidth_l 3 ,
+.Xr wcsxfrm_l 3 ,
+.Xr wctob_l 3 ,
+.Xr wcwidth_l 3 ,
+.Xr wprintf_l 3 ,
+.Xr wscanf_l 3
+.It In wctype.h
+.Xr iswblank_l 3 ,
+.Xr iswhexnumber_l 3 ,
+.Xr iswideogram_l 3 ,
+.Xr iswnumber_l 3 ,
+.Xr iswphonogram_l 3 ,
+.Xr iswrune_l 3 ,
+.Xr iswspecial_l 3 ,
+.Xr nextwctype_l 3 ,
+.Xr towctrans_l 3 ,
+.Xr wctrans_l 3
+.It In xlocale.h
+.Xr localeconv_l 3
+.El
+.Sh STANDARDS
+The functions
+conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The xlocale APIs first appeared in Darwin 8.0. This implementation was
+written by David Chisnall, under sponsorship from the FreeBSD Foundation and
+first appeared in
+.Fx 9.1 .
diff --git a/lib/libc/locale/xlocale.c b/lib/libc/locale/xlocale.c
new file mode 100644
index 000000000000..f14f9528465c
--- /dev/null
+++ b/lib/libc/locale/xlocale.c
@@ -0,0 +1,334 @@
+/*-
+ * 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$
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "libc_private.h"
+#include "xlocale_private.h"
+
+/**
+ * Each locale loader declares a global component. This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+/*
+ * And another version for the statically-allocated C locale. We only have
+ * components for the parts that are expected to be sensible.
+ */
+extern struct xlocale_component __xlocale_C_collate;
+extern struct xlocale_component __xlocale_C_ctype;
+/*
+ * 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
+};
+
+struct _xlocale __xlocale_C_locale = {
+ {0},
+ {
+ &__xlocale_C_collate,
+ &__xlocale_C_ctype,
+ 0, 0, 0, 0
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+ __collate_load,
+ __ctype_load,
+ __monetary_load,
+ __numeric_load,
+ __time_load,
+ __messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void init_key(void)
+{
+ pthread_key_create(&locale_info_key, xlocale_release);
+ pthread_setspecific(locale_info_key, (void*)42);
+ if (pthread_getspecific(locale_info_key) == (void*)42) {
+ pthread_setspecific(locale_info_key, 0);
+ } else {
+ fake_tls = 1;
+ }
+ __detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+ _once(&once_control, init_key);
+
+ return (fake_tls ? thread_local_locale :
+ pthread_getspecific(locale_info_key));
+}
+
+locale_t
+__get_locale(void)
+{
+ locale_t l = get_thread_locale();
+ return (l ? l : &__xlocale_global_locale);
+
+}
+
+static void
+set_thread_locale(locale_t loc)
+{
+ pthread_once(&once_control, init_key);
+
+ if (NULL != loc) {
+ xlocale_retain((struct xlocale_refcounted*)loc);
+ }
+ locale_t old = pthread_getspecific(locale_info_key);
+ if ((NULL != old) && (loc != old)) {
+ xlocale_release((struct xlocale_refcounted*)old);
+ }
+ if (fake_tls) {
+ thread_local_locale = loc;
+ } else {
+ pthread_setspecific(locale_info_key, loc);
+ }
+}
+
+/**
+ * Clean up a locale, once its reference count reaches zero. This function is
+ * called by xlocale_release(), it should not be called directly.
+ */
+static void
+destruct_locale(void *l)
+{
+ locale_t loc = l;
+ for (int type=0 ; type<XLC_LAST ; type++) {
+ if (loc->components[type]) {
+ xlocale_release(loc->components[type]);
+ }
+ }
+ if (loc->csym) {
+ free(loc->csym);
+ }
+ free(l);
+}
+
+/**
+ * Allocates a new, uninitialised, locale.
+ */
+static locale_t
+alloc_locale(void)
+{
+ locale_t new = calloc(sizeof(struct _xlocale), 1);
+ new->header.destructor = destruct_locale;
+ new->monetary_locale_changed = 1;
+ new->numeric_locale_changed = 1;
+ return (new);
+}
+static void
+copyflags(locale_t new, locale_t old)
+{
+ new->using_monetary_locale = old->using_monetary_locale;
+ new->using_numeric_locale = old->using_numeric_locale;
+ new->using_time_locale = old->using_time_locale;
+ new->using_messages_locale = old->using_messages_locale;
+}
+
+static int dupcomponent(int type, locale_t base, locale_t new)
+{
+ /* Always copy from the global locale, since it has mutable components. */
+ struct xlocale_component *src = base->components[type];
+ if (&__xlocale_global_locale == base) {
+ new->components[type] = constructors[type](src->locale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, src->locale, ENCODING_LEN);
+ }
+ } else {
+ new->components[type] = xlocale_retain(base->components[type]);
+ }
+ return (0 != new->components[type]);
+}
+
+/*
+ * Public interfaces. These are the five public functions described by the
+ * xlocale interface.
+ */
+
+locale_t newlocale(int mask, const char *locale, locale_t base)
+{
+ int type;
+ const char *realLocale = locale;
+ int useenv = 0;
+ int success = 1;
+
+ _once(&once_control, init_key);
+
+ locale_t new = alloc_locale();
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ if (NULL == locale) {
+ realLocale = "C";
+ } else if ('\0' == locale[0]) {
+ useenv = 1;
+ }
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ if (mask & 1) {
+ if (useenv) {
+ realLocale = __get_locale_env(type);
+ }
+ new->components[type] = constructors[type](realLocale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, realLocale, ENCODING_LEN);
+ } else {
+ success = 0;
+ break;
+ }
+ } else {
+ if (!dupcomponent(type, base, new)) {
+ success = 0;
+ break;
+ }
+ }
+ mask >>= 1;
+ }
+ if (0 == success) {
+ xlocale_release(new);
+ new = NULL;
+ }
+
+ return (new);
+}
+
+locale_t duplocale(locale_t base)
+{
+ locale_t new = alloc_locale();
+ int type;
+
+ _once(&once_control, init_key);
+
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ dupcomponent(type, base, new);
+ }
+
+ return (new);
+}
+
+/*
+ * Free a locale_t. This is quite a poorly named function. It actually
+ * disclaims a reference to a locale_t, rather than freeing it.
+ */
+int
+freelocale(locale_t loc)
+{
+ /* Fail if we're passed something that isn't a locale. */
+ if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) {
+ return (-1);
+ }
+ /* If we're passed the global locale, pretend that we freed it but don't
+ * actually do anything. */
+ if (&__xlocale_global_locale == loc) {
+ return (0);
+ }
+ xlocale_release(loc);
+ return (0);
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc)
+{
+ int type = ffs(mask) - 1;
+ FIX_LOCALE(loc);
+ if (type >= XLC_LAST)
+ return (NULL);
+ if (loc->components[type])
+ return (loc->components[type]->locale);
+ return "C";
+}
+
+/*
+ * 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);
+}
+
diff --git a/lib/libc/locale/xlocale_private.h b/lib/libc/locale/xlocale_private.h
new file mode 100644
index 000000000000..272d15ec8c83
--- /dev/null
+++ b/lib/libc/locale/xlocale_private.h
@@ -0,0 +1,198 @@
+/*-
+ * 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_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include "setlocale.h"
+
+enum {
+ XLC_COLLATE = 0,
+ XLC_CTYPE,
+ XLC_MONETARY,
+ XLC_NUMERIC,
+ XLC_TIME,
+ XLC_MESSAGES,
+ XLC_LAST
+};
+
+
+/**
+ * Header used for objects that are reference counted. Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure. Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0. When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+ /** Number of references to this component. */
+ long retain_count;
+ /** Function used to destroy this component, if one is required*/
+ void(*destructor)(void*);
+};
+/**
+ * Header for a locale component. All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+ struct xlocale_refcounted header;
+ /** Name of the locale used for this component. */
+ char locale[ENCODING_LEN+1];
+};
+
+/**
+ * xlocale structure, stores per-thread locale information.
+ */
+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;
+ atomic_add_long(&(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 = atomic_fetchadd_long(&(obj->retain_count), -1) - 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;
+extern struct _xlocale __xlocale_C_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_C_locale);
+ case -1: return (&__xlocale_global_locale);
+ default: return (locale);
+ }
+}
+
+/**
+ * Replace a placeholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
index 2e9adeb67391..c24b3826416d 100644
--- a/lib/libc/regex/regcomp.c
+++ b/lib/libc/regex/regcomp.c
@@ -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 @@ p_b_term(struct parse *p, cset *cs)
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 @@ p_b_term(struct parse *p, cset *cs)
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);
}
diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map
index df66ab3c2399..cafb0c64df7c 100644
--- a/lib/libc/stdio/Symbol.map
+++ b/lib/libc/stdio/Symbol.map
@@ -117,6 +117,46 @@ FBSD_1.1 {
vdprintf;
};
+FBSD_1.3 {
+ 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;
+};
+
FBSDprivate_1.0 {
_flockfile;
_flockfile_debug_stub;
diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c
index 90c62bcea2b0..cd475cd2117e 100644
--- a/lib/libc/stdio/asprintf.c
+++ b/lib/libc/stdio/asprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdarg.h>
+#include <xlocale.h>
int
asprintf(char ** __restrict s, char const * __restrict fmt, ...)
@@ -47,3 +53,15 @@ asprintf(char ** __restrict s, char const * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c
index 3a5b09b9ae7b..0e877532423e 100644
--- a/lib/libc/stdio/fgetwc.c
+++ b/lib/libc/stdio/fgetwc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ __fgetwc(FILE *fp)
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)
diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c
index 1a1ad2ddeaa0..6d9087b09c8f 100644
--- a/lib/libc/stdio/fgetwln.c
+++ b/lib/libc/stdio/fgetwln.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ error:
*lenp = 0;
return (NULL);
}
+wchar_t *
+fgetwln(FILE * __restrict fp, size_t *lenp)
+{
+ return fgetwln_l(fp, lenp, __get_locale());
+}
diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c
index 550843dff676..f7a63fe1d564 100644
--- a/lib/libc/stdio/fgetws.c
+++ b/lib/libc/stdio/fgetws.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
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 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
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 @@ error:
FUNLOCKFILE(fp);
return (NULL);
}
+wchar_t *
+fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+{
+ return fgetws_l(ws, n, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c
index bebc182d97ad..169532d1cd1b 100644
--- a/lib/libc/stdio/fprintf.c
+++ b/lib/libc/stdio/fprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdarg.h>
+#include "xlocale_private.h"
int
fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
@@ -46,7 +52,19 @@ fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
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);
}
diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c
index ae92f662822c..7b05d4a876db 100644
--- a/lib/libc/stdio/fputwc.c
+++ b/lib/libc/stdio/fputwc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
* 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 @@ __fputwc(wchar_t wc, FILE *fp)
*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 @@ __fputwc(wchar_t wc, FILE *fp)
* 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());
+}
diff --git a/lib/libc/stdio/fputws.c b/lib/libc/stdio/fputws.c
index b4462b744197..a318e2d8acdf 100644
--- a/lib/libc/stdio/fputws.c
+++ b/lib/libc/stdio/fputws.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
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 @@ error:
FUNLOCKFILE(fp);
return (-1);
}
+
+int
+fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+{
+ return fputws_l(ws, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c
index ce3001a103df..c5fa85f5629d 100644
--- a/lib/libc/stdio/fscanf.c
+++ b/lib/libc/stdio/fscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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,7 +57,21 @@ fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
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);
diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c
index a22edaeb55f0..f4342ab6c4e3 100644
--- a/lib/libc/stdio/fwprintf.c
+++ b/lib/libc/stdio/fwprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@ fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c
index f779c538518a..175607747d65 100644
--- a/lib/libc/stdio/fwscanf.c
+++ b/lib/libc/stdio/fwscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@ fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/getwc.c
index ba5ab6011bfd..666350bba923 100644
--- a/lib/libc/stdio/getwc.c
+++ b/lib/libc/stdio/getwc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
@@ -46,3 +52,9 @@ getwc(FILE *fp)
return (fgetwc(fp));
}
+wint_t
+getwc_l(FILE *fp, locale_t locale)
+{
+
+ return (fgetwc_l(fp, locale));
+}
diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c
index 79dd7bc4b33b..bc3b8a64c662 100644
--- a/lib/libc/stdio/getwchar.c
+++ b/lib/libc/stdio/getwchar.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
@@ -42,6 +48,10 @@ __FBSDID("$FreeBSD$");
wint_t
getwchar(void)
{
-
return (fgetwc(stdin));
}
+wint_t
+getwchar_l(locale_t locale)
+{
+ return (fgetwc_l(stdin, locale));
+}
diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h
index 6380b83af20e..8b37f0d01000 100644
--- a/lib/libc/stdio/local.h
+++ b/lib/libc/stdio/local.h
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,6 +42,7 @@
#include <pthread.h>
#include <string.h>
#include <wchar.h>
+#include <locale.h>
/*
* Information local to this implementation of stdio,
@@ -50,8 +56,8 @@ extern int _ftello(FILE *, fpos_t *);
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 _cleanup(void);
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);
diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c
index df290fa13451..f623f2f94c25 100644
--- a/lib/libc/stdio/printf.c
+++ b/lib/libc/stdio/printf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdarg.h>
+#include <xlocale.h>
int
printf(char const * __restrict fmt, ...)
@@ -50,3 +56,14 @@ printf(char const * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h
index 39b00030ab8a..97acc5398ac3 100644
--- a/lib/libc/stdio/printfcommon.h
+++ b/lib/libc/stdio/printfcommon.h
@@ -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 @@ io_init(struct io_state *iop, FILE *fp)
* 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 @@ static const CHAR zeroes[PADSIZE] =
* 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 @@ io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
*/
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 @@ io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
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));
}
/*
diff --git a/lib/libc/stdio/putwc.c b/lib/libc/stdio/putwc.c
index 8fe065bdfe32..56acf5081c1c 100644
--- a/lib/libc/stdio/putwc.c
+++ b/lib/libc/stdio/putwc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#undef putwc
@@ -41,8 +47,13 @@ __FBSDID("$FreeBSD$");
* 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());
}
diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c
index 55030713c752..8673bd5065fa 100644
--- a/lib/libc/stdio/putwchar.c
+++ b/lib/libc/stdio/putwchar.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#undef putwchar
@@ -40,8 +46,13 @@ __FBSDID("$FreeBSD$");
* 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());
}
diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c
index 4ae88da973fc..ba33caae7988 100644
--- a/lib/libc/stdio/scanf.c
+++ b/lib/libc/stdio/scanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
int
scanf(char const * __restrict fmt, ...)
@@ -51,7 +57,21 @@ scanf(char const * __restrict fmt, ...)
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);
diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c
index e6d7115fb37f..74af42de23a7 100644
--- a/lib/libc/stdio/snprintf.c
+++ b/lib/libc/stdio/snprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
+#include "xlocale_private.h"
#include "local.h"
@@ -59,7 +65,32 @@ snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...)
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);
diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c
index b55bd6cfa2cb..6e20e04651e0 100644
--- a/lib/libc/stdio/sprintf.c
+++ b/lib/libc/stdio/sprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <limits.h>
#include "local.h"
+#include "xlocale_private.h"
int
sprintf(char * __restrict str, char const * __restrict fmt, ...)
@@ -52,3 +58,16 @@ sprintf(char * __restrict str, char const * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c
index c793b86699cc..1c339eb5069b 100644
--- a/lib/libc/stdio/sscanf.c
+++ b/lib/libc/stdio/sscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <xlocale.h>
#include "local.h"
int
@@ -52,3 +58,15 @@ sscanf(const char * __restrict str, char const * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c
index d66531820d30..1f6ecc65a8ad 100644
--- a/lib/libc/stdio/swprintf.c
+++ b/lib/libc/stdio/swprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@ swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c
index 728a3d6957c5..c305ac15d943 100644
--- a/lib/libc/stdio/swscanf.c
+++ b/lib/libc/stdio/swscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@ swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c
index 10dbbbf89a5a..78bc38d954a0 100644
--- a/lib/libc/stdio/ungetwc.c
+++ b/lib/libc/stdio/ungetwc.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ __ungetwc(wint_t wc, FILE *fp)
* 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());
+}
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
index a1b600a4ea24..8feb23da758e 100644
--- a/lib/libc/stdio/vasprintf.c
+++ b/lib/libc/stdio/vasprintf.c
@@ -4,6 +4,11 @@
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,15 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
+#include "xlocale_private.h"
#include "local.h"
int
-vasprintf(char **str, const char *fmt, __va_list ap)
+vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
{
FILE f = FAKE_FILE;
int ret;
+ FIX_LOCALE(locale);
f._flags = __SWR | __SSTR | __SALC;
f._bf._base = f._p = malloc(128);
@@ -49,7 +56,7 @@ vasprintf(char **str, const char *fmt, __va_list ap)
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 @@ vasprintf(char **str, const char *fmt, __va_list ap)
*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);
+}
diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c
index 3ad273ea9600..454b0f9fdba7 100644
--- a/lib/libc/stdio/vdprintf.c
+++ b/lib/libc/stdio/vdprintf.c
@@ -2,6 +2,11 @@
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,6 +40,7 @@ __FBSDID("$FreeBSD$");
#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 @@ vdprintf(int fd, const char * __restrict fmt, va_list ap)
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);
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 17ad8244feba..bfbdc1331d49 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <printf.h>
#include <stdarg.h>
+#include "xlocale_private.h"
#include "un-namespace.h"
#include "libc_private.h"
@@ -64,8 +70,8 @@ __FBSDID("$FreeBSD$");
#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 @@ struct grouping_state {
* 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 @@ grouping_init(struct grouping_state *gs, int ndigits)
*/
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 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
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 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
* 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 @@ __sprint(FILE *fp, struct __suio *uio)
* 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 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
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 @@ __wcsconv(wchar_t *wcsarg, int prec)
* 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 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
* 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 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
/* 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 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
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 @@ fp_common:
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 @@ number: if ((dprec = prec) >= 0)
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 @@ number: if ((dprec = prec) >= 0)
/* 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 @@ number: if ((dprec = prec) >= 0)
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
- cp, dtoaend);
+ cp, dtoaend, locale);
if (n < 0)
goto error;
cp += n;
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
index bce4481dfe69..0e7894917416 100644
--- a/lib/libc/stdio/vfscanf.c
+++ b/lib/libc/stdio/vfscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include "collate.h"
#include "libc_private.h"
#include "local.h"
+#include "xlocale_private.h"
#ifndef NO_FLOATING_POINT
#include <locale.h>
@@ -95,7 +101,7 @@ __FBSDID("$FreeBSD$");
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);
@@ -109,7 +115,18 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap)
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);
}
@@ -118,7 +135,7 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap)
* __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 */
@@ -733,9 +750,9 @@ literal:
*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 +783,17 @@ literal:
/* 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 +822,8 @@ __sccl(tab, fmt)
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 +877,8 @@ doswitch:
*/
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 +886,14 @@ doswitch:
}
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 +927,7 @@ doswitch:
#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 +936,7 @@ parsefloat(FILE *fp, char *buf, char *end)
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;
/*
diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c
index d34f559a8f3b..73e37c914c5c 100644
--- a/lib/libc/stdio/vfwprintf.c
+++ b/lib/libc/stdio/vfwprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ struct grouping_state {
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 @@ get_thousep(void)
* 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 @@ grouping_init(struct grouping_state *gs, int ndigits)
*/
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 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
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 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
* 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 @@ __sprint(FILE *fp, struct __suio *uio)
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 @@ __sprint(FILE *fp, struct __suio *uio)
* 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 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
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 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
* 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 @@ __xfputwc(wchar_t wc, FILE *fp)
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 @@ __mbsconv(char *mbsarg, int prec)
* 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 @@ vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
* 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 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
/* 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 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
io_init(&io, fp);
ret = 0;
#ifndef NO_FLOATING_POINT
- decimal_point = get_decpt();
+ decimal_point = get_decpt(locale);
#endif
/*
@@ -816,7 +828,7 @@ fp_common:
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 @@ number: if ((dprec = prec) >= 0)
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 @@ number: if ((dprec = prec) >= 0)
/* 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 @@ number: if ((dprec = prec) >= 0)
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
- cp, convbuf + ndig);
+ cp, convbuf + ndig, locale);
if (n < 0)
goto error;
cp += n;
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
index 60c7c71053ad..22b08270897c 100644
--- a/lib/libc/stdio/vfwscanf.c
+++ b/lib/libc/stdio/vfwscanf.c
@@ -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,10 +58,7 @@ __FBSDID("$FreeBSD$");
#include "libc_private.h"
#include "local.h"
-
-#ifndef NO_FLOATING_POINT
-#include <locale.h>
-#endif
+#include "xlocale_private.h"
#define BUF 513 /* Maximum length of numeric string. */
@@ -96,7 +98,7 @@ __FBSDID("$FreeBSD$");
#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 @@ static const mbstate_t initial_mbs;
* 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 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
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 @@ again: c = *fmt++;
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 @@ literal:
* 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 @@ literal:
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 @@ literal:
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 @@ literal:
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 @@ literal:
/* 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 @@ literal:
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 @@ literal:
n++;
}
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
if (!(flags & SUPPRESS)) {
*mbp = 0;
nassigned++;
@@ -481,29 +491,29 @@ literal:
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 @@ literal:
nread++;
}
if (wi != WEOF)
- __ungetwc(wi, fp);
+ __ungetwc(wi, fp, locale);
if (!(flags & SUPPRESS)) {
*mbp = 0;
nassigned++;
@@ -544,7 +554,7 @@ literal:
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 @@ literal:
* for a number. Stop accumulating digits.
*/
if (c != WEOF)
- __ungetwc(c, fp);
+ __ungetwc(c, fp, locale);
break;
ok:
/*
@@ -644,13 +654,13 @@ literal:
*/
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 @@ literal:
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 @@ match_failure:
#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 @@ parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
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 @@ reswitch:
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);
}
diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c
index a610b7dc2b13..c15ef4d6cc77 100644
--- a/lib/libc/stdio/vprintf.c
+++ b/lib/libc/stdio/vprintf.c
@@ -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 @@ static char sccsid[] = "@(#)vprintf.c 8.1 (Berkeley) 6/4/93";
__FBSDID("$FreeBSD$");
#include <stdio.h>
+#include <xlocale.h>
int
vprintf(const char * __restrict fmt, __va_list ap)
{
-
return (vfprintf(stdout, fmt, ap));
}
+int
+vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
+{
+ return (vfprintf_l(stdout, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c
index 25bce72c1cec..d56bb3b51639 100644
--- a/lib/libc/stdio/vscanf.c
+++ b/lib/libc/stdio/vscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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);
+}
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
index 70e4c530fe3c..d2bad0f09aa7 100644
--- a/lib/libc/stdio/vsnprintf.c
+++ b/lib/libc/stdio/vsnprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdio.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
- __va_list ap)
+vsnprintf_l(char * __restrict str, size_t n, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
{
size_t on;
int ret;
char dummy[2];
FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
on = n;
if (n != 0)
@@ -64,8 +71,14 @@ vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
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);
+}
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
index 3890af70d87c..04f2df3cca17 100644
--- a/lib/libc/stdio/vsprintf.c
+++ b/lib/libc/stdio/vsprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <limits.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+vsprintf_l(char * __restrict str, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
{
int ret;
FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = INT_MAX;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
*f._p = 0;
return (ret);
}
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+ return vsprintf_l(str, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c
index 82429c6e3eed..5668ab5b9825 100644
--- a/lib/libc/stdio/vsscanf.c
+++ b/lib/libc/stdio/vsscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
#include "local.h"
+#include "xlocale_private.h"
static int
eofread(void *, char *, int);
@@ -52,14 +58,21 @@ eofread(void *cookie, char *buf, int len)
}
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);
}
diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c
index 2cfe7242ef74..023c53750f2d 100644
--- a/lib/libc/stdio/vswprintf.c
+++ b/lib/libc/stdio/vswprintf.c
@@ -4,6 +4,11 @@
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,10 +43,11 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include "local.h"
+#include "xlocale_private.h"
int
-vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
- __va_list ap)
+vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+ const wchar_t * __restrict fmt, __va_list ap)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -49,6 +55,7 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
char *mbp;
int ret, sverrno;
size_t nwc;
+ FIX_LOCALE(locale);
if (n == 0) {
errno = EINVAL;
@@ -62,7 +69,7 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
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 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
* 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 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
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);
+}
diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c
index f06fc02bbf2d..f646e852c781 100644
--- a/lib/libc/stdio/vswscanf.c
+++ b/lib/libc/stdio/vswscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <wchar.h>
#include "local.h"
+#include "xlocale_private.h"
static int eofread(void *, char *, int);
@@ -57,8 +63,8 @@ eofread(void *cookie, char *buf, int len)
}
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 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
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 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
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 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
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);
+}
diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c
index 91212a8bf3d0..e09a30eccca5 100644
--- a/lib/libc/stdio/vwprintf.c
+++ b/lib/libc/stdio/vwprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
vwprintf(const wchar_t * __restrict fmt, va_list ap)
{
-
return (vfwprintf(stdout, fmt, ap));
}
+int
+vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwprintf_l(stdout, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c
index 4a21af2d8356..730beeef7f20 100644
--- a/lib/libc/stdio/vwscanf.c
+++ b/lib/libc/stdio/vwscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
vwscanf(const wchar_t * __restrict fmt, va_list ap)
{
-
return (vfwscanf(stdin, fmt, ap));
}
+int
+vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwscanf_l(stdin, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c
index 92426f6c207b..fdffa8614634 100644
--- a/lib/libc/stdio/wprintf.c
+++ b/lib/libc/stdio/wprintf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
wprintf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@ wprintf(const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c
index 5e27b401fa84..22ce9bd1f89b 100644
--- a/lib/libc/stdio/wscanf.c
+++ b/lib/libc/stdio/wscanf.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
+#include <xlocale.h>
int
wscanf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@ wscanf(const wchar_t * __restrict fmt, ...)
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);
+}
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index d159beddd4ee..c268ab9139fc 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -92,6 +92,24 @@ FBSD_1.0 {
twalk;
};
+FBSD_1.3 {
+ 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 {
_malloc_thread_cleanup;
_malloc_prefork;
diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c
index 51e482e7dac3..746ceac385f2 100644
--- a/lib/libc/stdlib/atof.c
+++ b/lib/libc/stdlib/atof.c
@@ -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 @@ static char sccsid[] = "@(#)atof.c 8.1 (Berkeley) 6/4/93";
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
double
atof(ascii)
@@ -41,3 +47,11 @@ atof(ascii)
{
return strtod(ascii, (char **)NULL);
}
+
+double
+atof_l(ascii, locale)
+ const char *ascii;
+ locale_t locale;
+{
+ return strtod_l(ascii, (char **)NULL, locale);
+}
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
index 0ffcd037394e..31a8676b98b9 100644
--- a/lib/libc/stdlib/atoi.c
+++ b/lib/libc/stdlib/atoi.c
@@ -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 @@ static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93";
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
int
atoi(str)
@@ -41,3 +47,11 @@ atoi(str)
{
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);
+}
diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c
index c9cf2e85b00b..7ebbe01ec9e2 100644
--- a/lib/libc/stdlib/atol.c
+++ b/lib/libc/stdlib/atol.c
@@ -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 @@ static char sccsid[] = "@(#)atol.c 8.1 (Berkeley) 6/4/93";
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
long
atol(str)
@@ -41,3 +47,11 @@ atol(str)
{
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);
+}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
index 203c17425ae4..cbb5459cb12a 100644
--- a/lib/libc/stdlib/atoll.c
+++ b/lib/libc/stdlib/atoll.c
@@ -2,6 +2,11 @@
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,6 +36,7 @@
__FBSDID("$FreeBSD$");
#include <stdlib.h>
+#include <xlocale.h>
long long
atoll(str)
@@ -38,3 +44,11 @@ atoll(str)
{
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);
+}
diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c
index 6c28254472e7..b82797dc6d1e 100644
--- a/lib/libc/stdlib/strfmon.c
+++ b/lib/libc/stdlib/strfmon.c
@@ -2,6 +2,11 @@
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -38,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "xlocale_private.h"
/* internal flags */
#define NEED_GROUPING 0x01 /* print digits grouped (default) */
@@ -92,11 +98,10 @@ static void __setup_vars(int, char *, char *, char *, char **);
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 @@ strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
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 @@ strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
}
PRINT('\0');
- va_end(ap);
free(asciivalue);
free(currency_symbol);
return (dst - s - 1); /* return size of put data except trailing '\0' */
@@ -399,9 +403,32 @@ end_error:
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;
+ 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,
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
index 4f0063ca318a..9be773b00254 100644
--- a/lib/libc/stdlib/strtoimax.c
+++ b/lib/libc/stdlib/strtoimax.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
+#include "xlocale_private.h"
/*
* Convert a string to an intmax_t integer.
@@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c
index 0d6f73684c0d..f80ecb440f83 100644
--- a/lib/libc/stdlib/strtol.c
+++ b/lib/libc/stdlib/strtol.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
@@ -46,13 +52,15 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
index 2e5547dc87e7..67833275e3ae 100644
--- a/lib/libc/stdlib/strtoll.c
+++ b/lib/libc/stdlib/strtoll.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
* Convert a string to a long long integer.
@@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c
index e8d1e114a0a4..0ae0661c2c08 100644
--- a/lib/libc/stdlib/strtoul.c
+++ b/lib/libc/stdlib/strtoul.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
* Convert a string to an unsigned long integer.
@@ -45,13 +51,14 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
index f11910c3a9ff..4b7f1c9082d7 100644
--- a/lib/libc/stdlib/strtoull.c
+++ b/lib/libc/stdlib/strtoull.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
+#include "xlocale_private.h"
/*
* Convert a string to an unsigned long long integer.
@@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
index 23050c2c61aa..d4362bb333c4 100644
--- a/lib/libc/stdlib/strtoumax.c
+++ b/lib/libc/stdlib/strtoumax.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
+#include "xlocale_private.h"
/*
* Convert a string to a uintmax_t integer.
@@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$");
* 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 @@ strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
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 @@ noconv:
*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());
+}
diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c
index dac910bb724f..d3571ad3621a 100644
--- a/lib/libc/stdtime/strftime.c
+++ b/lib/libc/stdtime/strftime.c
@@ -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 @@ __FBSDID("$FreeBSD$");
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 @@ static const char* fmt_padding[][4] = {
};
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 @@ strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
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 @@ label:
{
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 @@ label:
}
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 @@ label:
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 @@ label:
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 @@ label:
}
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 @@ label:
** "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 @@ label:
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 @@ label:
continue;
case '+':
pt = _fmt(tptr->date_fmt, t, pt, ptlim,
- warnp);
+ warnp, loc);
continue;
case '-':
if (PadIndex != PAD_DEFAULT)
diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c
index 401350ee3d76..fb94dcd0df43 100644
--- a/lib/libc/stdtime/strptime.c
+++ b/lib/libc/stdtime/strptime.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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,9 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
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 +121,19 @@ label:
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 +145,13 @@ label:
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 +169,48 @@ label:
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 +223,16 @@ label:
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 +248,10 @@ label:
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 +267,12 @@ label:
* 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 +285,10 @@ label:
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 +298,7 @@ label:
* 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 +308,7 @@ label:
}
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 +323,12 @@ label:
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 +346,12 @@ label:
* 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 +359,15 @@ label:
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 +376,10 @@ label:
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 +393,12 @@ label:
* 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 +408,10 @@ label:
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 +422,15 @@ label:
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 +441,8 @@ label:
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 +454,12 @@ label:
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 +469,10 @@ label:
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 +485,7 @@ label:
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 +499,16 @@ label:
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 +522,10 @@ label:
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 +534,9 @@ label:
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 +570,7 @@ label:
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 +590,15 @@ label:
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 +606,9 @@ strptime(const char * __restrict buf, const char * __restrict fmt,
return (ret);
}
+char *
+strptime(const char * __restrict buf, const char * __restrict fmt,
+ struct tm * __restrict tm)
+{
+ return strptime_l(buf, fmt, tm, __get_locale());
+}
diff --git a/lib/libc/stdtime/timelocal.c b/lib/libc/stdtime/timelocal.c
index 6917e6b6ccee..3d9d096c7492 100644
--- a/lib/libc/stdtime/timelocal.c
+++ b/lib/libc/stdtime/timelocal.c
@@ -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,9 +38,13 @@ __FBSDID("$FreeBSD$");
#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 *))
@@ -99,19 +108,47 @@ static const struct lc_time_T _C_time_locale = {
"%I:%M:%S %p"
};
+static void destruct_time(void *v)
+{
+ struct xlocale_time *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+#include <stdio.h>
struct lc_time_T *
-__get_current_time_locale(void)
+__get_current_time_locale(locale_t loc)
{
- return (_time_using_locale
- ? &_time_locale
+ return (loc->using_time_locale
+ ? &((struct xlocale_time *)loc->components[XLC_TIME])->locale
: (struct lc_time_T *)&_C_time_locale);
}
+static int
+time_load_locale(struct xlocale_time *l, int *using_locale, const char *name)
+{
+ struct lc_time_T *time_locale = &l->locale;
+ return (__part_load_locale(name, using_locale,
+ &l->buffer, "LC_TIME",
+ LCTIME_SIZE, LCTIME_SIZE,
+ (const char **)time_locale));
+}
int
__time_load_locale(const char *name)
{
- return (__part_load_locale(name, &_time_using_locale,
- &time_locale_buf, "LC_TIME",
- LCTIME_SIZE, LCTIME_SIZE,
- (const char **)&_time_locale));
+ return time_load_locale(&__xlocale_global_time,
+ &__xlocale_global_locale.using_time_locale, name);
}
+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;
+}
+
diff --git a/lib/libc/stdtime/timelocal.h b/lib/libc/stdtime/timelocal.h
index 5d26bf938d97..2e44415b9940 100644
--- a/lib/libc/stdtime/timelocal.h
+++ b/lib/libc/stdtime/timelocal.h
@@ -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 @@ struct lc_time_T {
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_ */
diff --git a/lib/libc/string/Symbol.map b/lib/libc/string/Symbol.map
index 19f33824b9dd..ef23465e182d 100644
--- a/lib/libc/string/Symbol.map
+++ b/lib/libc/string/Symbol.map
@@ -91,6 +91,14 @@ FBSD_1.1 {
wcsnlen;
};
+FBSD_1.3 {
+ strcasecmp_l;
+ strcasestr_l;
+ strncasecmp_l;
+ wcswidth_l;
+ wcwidth_l;
+};
+
FBSDprivate_1.0 {
__strtok_r;
};
diff --git a/lib/libc/string/strcasecmp.c b/lib/libc/string/strcasecmp.c
index 4a474fee24a7..e173f6d04e4e 100644
--- a/lib/libc/string/strcasecmp.c
+++ b/lib/libc/string/strcasecmp.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <strings.h>
#include <ctype.h>
+#include "xlocale_private.h"
typedef unsigned char u_char;
int
-strcasecmp(const char *s1, const char *s2)
+strcasecmp_l(const char *s1, const char *s2, locale_t locale)
{
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
+ FIX_LOCALE(locale);
- while (tolower(*us1) == tolower(*us2++))
+ while (tolower_l(*us1, locale) == tolower_l(*us2++, locale))
if (*us1++ == '\0')
return (0);
- return (tolower(*us1) - tolower(*--us2));
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
+}
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ return strcasecmp_l(s1, s2, __get_locale());
}
int
-strncasecmp(const char *s1, const char *s2, size_t n)
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
{
+ FIX_LOCALE(locale);
if (n != 0) {
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
do {
- if (tolower(*us1) != tolower(*us2++))
- return (tolower(*us1) - tolower(*--us2));
+ if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return (0);
}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ return strncasecmp_l(s1, s2, n, __get_locale());
+}
diff --git a/lib/libc/string/strcasestr.c b/lib/libc/string/strcasestr.c
index 9b28bf569a4d..5f39648a69bd 100644
--- a/lib/libc/string/strcasestr.c
+++ b/lib/libc/string/strcasestr.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <string.h>
+#include "xlocale_private.h"
/*
* Find the first occurrence of find in s, ignore case.
*/
char *
-strcasestr(const char *s, const char *find)
+strcasestr_l(const char *s, const char *find, locale_t locale)
{
char c, sc;
size_t len;
+ FIX_LOCALE(locale);
if ((c = *find++) != 0) {
- c = tolower((unsigned char)c);
+ c = tolower_l((unsigned char)c, locale);
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
- } while ((char)tolower((unsigned char)sc) != c);
- } while (strncasecmp(s, find, len) != 0);
+ } while ((char)tolower_l((unsigned char)sc, locale) != c);
+ } while (strncasecmp_l(s, find, len, locale) != 0);
s--;
}
return ((char *)s);
}
+char *
+strcasestr(const char *s, const char *find)
+{
+ return strcasestr_l(s, find, __get_locale());
+}
diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c
index 0da5c5730fc8..a918fcabfab6 100644
--- a/lib/libc/string/strcoll.c
+++ b/lib/libc/string/strcoll.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include "collate.h"
+#include <stdio.h>
+
int
-strcoll(const char *s, const char *s2)
+strcoll_l(const char *s, const char *s2, locale_t locale)
{
int len, len2, prim, prim2, sec, sec2, ret, ret2;
const char *t, *t2;
char *tt, *tt2;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
- if (__collate_load_error)
+ if (table->__collate_load_error)
return strcmp(s, s2);
len = len2 = 1;
ret = ret2 = 0;
- if (__collate_substitute_nontrivial) {
- t = tt = __collate_substitute(s);
- t2 = tt2 = __collate_substitute(s2);
+ if (table->__collate_substitute_nontrivial) {
+ t = tt = __collate_substitute(table, s);
+ t2 = tt2 = __collate_substitute(table, s2);
} else {
tt = tt2 = NULL;
t = s;
@@ -55,11 +65,11 @@ strcoll(const char *s, const char *s2)
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 @@ strcoll(const char *s, const char *s2)
return ret;
}
+
+int
+strcoll(const char *s, const char *s2)
+{
+ return strcoll_l(s, s2, __get_locale());
+}
+
diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c
index a4c8019468d6..b758b0c4a383 100644
--- a/lib/libc/string/strxfrm.c
+++ b/lib/libc/string/strxfrm.c
@@ -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 @@ __FBSDID("$FreeBSD$");
#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 @@ strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
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) {
diff --git a/lib/libc/string/wcscoll.c b/lib/libc/string/wcscoll.c
index dbfbcfa919a7..3c51015807c2 100644
--- a/lib/libc/string/wcscoll.c
+++ b/lib/libc/string/wcscoll.c
@@ -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 @@ static char *__mbsdup(const wchar_t *);
* 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 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
return (wcscmp(ws1, ws2));
}
- diff = strcoll(mbs1, mbs2);
+ diff = strcoll_l(mbs1, mbs2, locale);
sverrno = errno;
free(mbs1);
free(mbs2);
@@ -76,6 +84,12 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2)
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)
{
diff --git a/lib/libc/string/wcswidth.c b/lib/libc/string/wcswidth.c
index b142074f1708..4095c8d8cb17 100644
--- a/lib/libc/string/wcswidth.c
+++ b/lib/libc/string/wcswidth.c
@@ -10,6 +10,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,19 +44,26 @@
__FBSDID("$FreeBSD$");
#include <wchar.h>
+#include "xlocale_private.h"
int
-wcswidth(const wchar_t *pwcs, size_t n)
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale)
{
wchar_t wc;
int len, l;
+ FIX_LOCALE(locale);
len = 0;
while (n-- > 0 && (wc = *pwcs++) != L'\0') {
- if ((l = wcwidth(wc)) < 0)
+ if ((l = wcwidth_l(wc, locale)) < 0)
return (-1);
len += l;
}
return (len);
}
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+ return wcswidth_l(pwcs, n, __get_locale());
+}
diff --git a/lib/libc/string/wcsxfrm.c b/lib/libc/string/wcsxfrm.c
index 5e47ad946ee6..cea667e54815 100644
--- a/lib/libc/string/wcsxfrm.c
+++ b/lib/libc/string/wcsxfrm.c
@@ -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 @@ static char *__mbsdup(const wchar_t *);
* 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 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
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 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
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 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
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)