partial xlocale(3) port from FreeBSD

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

partial xlocale(3) port from FreeBSD

Martin Pelikan
Hi!

my laptop now has libcxx working (most of the tests pass, but I haven't
checked what is missing from the C++ runtime).  The steps required are:

- port xlocale(3) from FreeBSD -- this is what this patch does
- use ld(1) from binutils-2.17 to avoid linker errors (for some reason it
  links symbols between first two object files and discards them for the
  rest of the command line)
- patch binutils to support DW_FORM_flag_present (not defined by DWARF 2,
  but emitted by clang++)  -- this is trivially taken from FreeBSD
- recompile libc, compile libcxxrt and libcxx and use them :-)
  -- some "defined(__OpenBSD__)" have to be added there, very technical.

Obviously, our locale support still sucks, this patch is mostly providing the
API for filling the blanks later.  Specifically, after we have proper TLS, the
locale_t is specified per-thread, the GNU "printf-like" security checks are
erased (where do I put them?) and we only support one locale -- "C".

I did the patch in two parts, separating include/ and lib/libc/, because my
connection is quite poor and "cvs diff" takes quite a long time.  It is by no
means complete, but hopefully small enough to be reviewed and used.

Tested on both architectures (country AND western!).
WARNING:  Touching this code may cause swear words.  Back your libc.so up!
--
Martin Pelikan


Index: Makefile
===================================================================
RCS file: /cvs/src/lib/libc/Makefile,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile
--- Makefile 1 Jun 2013 21:26:17 -0000 1.32
+++ Makefile 15 Oct 2013 12:42:21 -0000
@@ -12,6 +12,7 @@
 LIB=c
 CLEANFILES+=tags
 #CFLAGS+=-Werror
+CFLAGS+=-D__NO_TLS
 LDADD=-nodefaultlibs -lgcc
 
 LIBCSRCDIR=${.CURDIR}
Index: arch/amd64/gdtoa/strtold.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/amd64/gdtoa/strtold.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtold.c
--- arch/amd64/gdtoa/strtold.c 7 Sep 2008 20:36:07 -0000 1.1
+++ arch/amd64/gdtoa/strtold.c 15 Oct 2013 12:42:21 -0000
@@ -36,10 +36,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
  long double result;
 
- strtorx(s, sp, FLT_ROUNDS, &result);
+ strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
  return result;
 }
Index: arch/i386/gdtoa/strtold.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/i386/gdtoa/strtold.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtold.c
--- arch/i386/gdtoa/strtold.c 7 Sep 2008 20:36:07 -0000 1.1
+++ arch/i386/gdtoa/strtold.c 15 Oct 2013 12:42:21 -0000
@@ -36,10 +36,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
  long double result;
 
- strtorx(s, sp, FLT_ROUNDS, &result);
+ strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
  return result;
 }
Index: arch/m68k/gdtoa/strtold.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/m68k/gdtoa/strtold.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtold.c
--- arch/m68k/gdtoa/strtold.c 7 Sep 2008 20:36:07 -0000 1.1
+++ arch/m68k/gdtoa/strtold.c 15 Oct 2013 12:42:21 -0000
@@ -36,10 +36,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
  long double result;
 
- strtorx(s, sp, FLT_ROUNDS, &result);
+ strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
  return result;
 }
Index: arch/mips64/gdtoa/strtold.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/mips64/gdtoa/strtold.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtold.c
--- arch/mips64/gdtoa/strtold.c 7 Sep 2008 20:36:07 -0000 1.1
+++ arch/mips64/gdtoa/strtold.c 15 Oct 2013 12:42:21 -0000
@@ -36,10 +36,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
  long double result;
 
- strtorQ(s, sp, FLT_ROUNDS, &result);
+ strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
  return result;
 }
Index: arch/sparc64/gdtoa/strtold.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/sparc64/gdtoa/strtold.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtold.c
--- arch/sparc64/gdtoa/strtold.c 7 Sep 2008 20:36:08 -0000 1.1
+++ arch/sparc64/gdtoa/strtold.c 15 Oct 2013 12:42:21 -0000
@@ -36,10 +36,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
  long double result;
 
- strtorQ(s, sp, FLT_ROUNDS, &result);
+ strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
  return result;
 }
Index: arch/vax/gdtoa/strtof.c
===================================================================
RCS file: /cvs/src/lib/libc/arch/vax/gdtoa/strtof.c,v
retrieving revision 1.4
diff -u -p -r1.4 strtof.c
--- arch/vax/gdtoa/strtof.c 8 Jun 2011 22:14:17 -0000 1.4
+++ arch/vax/gdtoa/strtof.c 15 Oct 2013 12:42:21 -0000
@@ -33,9 +33,9 @@ THIS SOFTWARE.
 
  float
 #ifdef KR_headers
-strtof(s, sp) CONST char *s; char **sp;
+strtof_l(s, sp, locale) CONST char *s; char **sp; locale_t locale;
 #else
-strtof(CONST char *s, char **sp)
+strtof_l(CONST char *s, char **sp, locale_t locale)
 #endif
 {
  static FPI fpi0 = { 24, 1-128-1-24+1,  255-128-1-24+1, 1, SI };
@@ -49,7 +49,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, locale);
  switch(k & STRTOG_Retmask) {
   case STRTOG_NoNumber:
   case STRTOG_Zero:
Index: citrus/citrus_none.c
===================================================================
RCS file: /cvs/src/lib/libc/citrus/citrus_none.c,v
retrieving revision 1.5
diff -u -p -r1.5 citrus_none.c
--- citrus/citrus_none.c 7 Mar 2013 18:12:31 -0000 1.5
+++ citrus/citrus_none.c 15 Oct 2013 12:42:21 -0000
@@ -31,17 +31,34 @@
 
 #include <errno.h>
 #include <limits.h>
+#include <runetype.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <wchar.h>
+#include "../locale/mblocal.h"
+#include "../locale/rune.h"
 
 #include "citrus_ctype.h"
 #include "citrus_none.h"
 
 _CITRUS_CTYPE_DEF_OPS(none);
 
+int
+_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+ l->__mbrtowc = _citrus_none_ctype_mbrtowc;
+ l->__mbsinit = _citrus_none_ctype_mbsinit;
+ l->__mbsnrtowcs = _citrus_none_ctype_mbsnrtowcs;
+ l->__wcrtomb = _citrus_none_ctype_wcrtomb;
+ l->__wcsnrtombs = _citrus_none_ctype_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 256;
+ return (0);
+}
+
 /*
  * Convert an unsigned char value into a char value without relying on
  * signed overflow behavior.
@@ -167,3 +184,42 @@ _citrus_none_ctype_wcsnrtombs(char * __r
  *src += i;
  return (i);
 }
+
+struct xlocale_ctype __xlocale_global_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _citrus_none_ctype_mbrtowc,
+ _citrus_none_ctype_mbsinit,
+ _citrus_none_ctype_mbsnrtowcs,
+ _citrus_none_ctype_wcrtomb,
+ _citrus_none_ctype_wcsnrtombs,
+ 1, /* __mb_cur_max */
+ 256 /* __mb_sb_limit */
+};
+struct xlocale_ctype __xlocale_C_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _citrus_none_ctype_mbrtowc,
+ _citrus_none_ctype_mbsinit,
+ _citrus_none_ctype_mbsnrtowcs,
+ _citrus_none_ctype_wcrtomb,
+ _citrus_none_ctype_wcsnrtombs,
+ 1, /* __mb_cur_max */
+ 256 /* __mb_sb_limit */
+};
+
+struct xlocale_collate {
+ struct xlocale_component header;
+ int __collate_load_error;
+ int __collate_substitute_nontrivial;
+
+ u_char (*__collate_substitute_table_ptr)[UCHAR_MAX + 1][10 /* XXX */];
+};
+
+struct xlocale_collate __xlocale_global_collate = {
+ {{0}, "C"}, 1, 0
+};
+struct xlocale_collate __xlocale_C_collate = {
+ {{0}, "C"}, 1, 0
+};
+
Index: gdtoa/gdtoaimp.h
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/gdtoaimp.h,v
retrieving revision 1.3
diff -u -p -r1.3 gdtoaimp.h
--- gdtoa/gdtoaimp.h 2 Jul 2011 18:03:43 -0000 1.3
+++ gdtoa/gdtoaimp.h 15 Oct 2013 12:42:21 -0000
@@ -662,4 +662,5 @@ extern void memcpy_D2A ANSI((void*, cons
 #define SI 0
 #endif
 
+typedef struct _xlocale *locale_t;
 #endif /* GDTOAIMP_H_INCLUDED */
Index: gdtoa/strtod.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtod.c,v
retrieving revision 1.5
diff -u -p -r1.5 strtod.c
--- gdtoa/strtod.c 2 Jul 2011 18:03:43 -0000 1.5
+++ gdtoa/strtod.c 15 Oct 2013 12:42:21 -0000
@@ -37,6 +37,8 @@ THIS SOFTWARE.
 #ifdef USE_LOCALE
 #include "locale.h"
 #endif
+#include <xlocale.h>
+#include "../locale/xlocale_private.h"
 
 #ifdef IEEE_Arith
 #ifndef NO_IEEE_Scale
@@ -80,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
@@ -106,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))) {
  strlcpy(decimalpoint_cache, s0, strlen(s0) + 1);
  s0 = decimalpoint_cache;
@@ -1102,4 +1104,10 @@ strtod
  *se = (char *)s;
  return sign ? -dval(&rv) : dval(&rv);
  }
+
+double
+strtod(const char *s00, char **se)
+{
+ return strtod_l(s00, se, __get_locale());
+}
 
Index: gdtoa/strtodg.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtodg.c,v
retrieving revision 1.5
diff -u -p -r1.5 strtodg.c
--- gdtoa/strtodg.c 2 Jul 2011 18:03:43 -0000 1.5
+++ gdtoa/strtodg.c 15 Oct 2013 12:42:21 -0000
@@ -34,6 +34,7 @@ THIS SOFTWARE.
 #ifdef USE_LOCALE
 #include "locale.h"
 #endif
+#include <xlocale.h>
 
  static CONST int
 fivesbits[] = { 0,  3,  5,  7, 10, 12, 14, 17, 19, 21,
@@ -334,12 +335,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;
@@ -355,14 +356,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))) {
  strlcpy(decimalpoint_cache, s0, strlen(s0) + 1);
  s0 = decimalpoint_cache;
Index: gdtoa/strtof.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtof.c,v
retrieving revision 1.4
diff -u -p -r1.4 strtof.c
--- gdtoa/strtof.c 2 Jul 2011 18:03:43 -0000 1.4
+++ gdtoa/strtof.c 15 Oct 2013 12:42:21 -0000
@@ -29,13 +29,14 @@ THIS SOFTWARE.
 /* Please send bug reports to David M. Gay (dmg at acm dot org,
  * with " at " changed at "@" and " dot " changed to "."). */
 
+#include "../locale/xlocale_private.h"
 #include "gdtoaimp.h"
 
  float
 #ifdef KR_headers
-strtof(s, sp) CONST char *s; char **sp;
+strtof_l(s, sp, locale) CONST char *s; char **sp; locale_t locale;
 #else
-strtof(CONST char *s, char **sp)
+strtof_l(CONST char *s, char **sp, locale_t locale)
 #endif
 {
  static FPI fpi0 = { 24, 1-127-24+1,  254-127-24+1, 1, SI };
@@ -49,7 +50,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, locale);
  switch(k & STRTOG_Retmask) {
   case STRTOG_NoNumber:
   case STRTOG_Zero:
@@ -79,3 +80,10 @@ strtof(CONST char *s, char **sp)
  u.L[0] |= 0x80000000L;
  return u.f;
  }
+
+float
+strtof(const char *s, char **sp)
+{
+ return strtof_l(s, sp, __get_locale());
+}
+
Index: gdtoa/strtorQ.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtorQ.c,v
retrieving revision 1.2
diff -u -p -r1.2 strtorQ.c
--- gdtoa/strtorQ.c 16 Oct 2009 12:15:03 -0000 1.2
+++ gdtoa/strtorQ.c 15 Oct 2013 12:42:21 -0000
@@ -97,9 +97,10 @@ ULtoQ(ULong *L, ULong *bits, Long exp, i
 
  int
 #ifdef KR_headers
-strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorQ_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
 #else
-strtorQ(CONST char *s, char **sp, int rounding, void *L)
+strtorQ_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
 #endif
 {
  static FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI };
@@ -114,7 +115,7 @@ strtorQ(CONST char *s, char **sp, int ro
  fpi1.rounding = rounding;
  fpi = &fpi1;
  }
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits);
  ULtoQ((ULong*)L, bits, exp, k);
  return k;
  }
Index: gdtoa/strtord.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtord.c,v
retrieving revision 1.2
diff -u -p -r1.2 strtord.c
--- gdtoa/strtord.c 16 Oct 2009 12:15:03 -0000 1.2
+++ gdtoa/strtord.c 15 Oct 2013 12:42:21 -0000
@@ -73,9 +73,10 @@ ULtod(ULong *L, ULong *bits, Long exp, i
 
  int
 #ifdef KR_headers
-strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d;
+strtord_l(s, sp, rounding, d, locale) CONST char *s; char **sp; int rounding;
+double *d; locale_t locale;
 #else
-strtord(CONST char *s, char **sp, int rounding, double *d)
+strtord_l(CONST char *s, char **sp, int rounding, double *d, locale_t locale)
 #endif
 {
  static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
@@ -90,7 +91,7 @@ strtord(CONST char *s, char **sp, int ro
  fpi1.rounding = rounding;
  fpi = &fpi1;
  }
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, locale);
  ULtod((ULong*)d, bits, exp, k);
  return k;
  }
Index: gdtoa/strtorx.c
===================================================================
RCS file: /cvs/src/lib/libc/gdtoa/strtorx.c,v
retrieving revision 1.3
diff -u -p -r1.3 strtorx.c
--- gdtoa/strtorx.c 2 Jul 2011 18:03:43 -0000 1.3
+++ gdtoa/strtorx.c 15 Oct 2013 12:42:22 -0000
@@ -100,9 +100,10 @@ ULtox(UShort *L, ULong *bits, Long exp,
 
  int
 #ifdef KR_headers
-strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorx_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
 #else
-strtorx(CONST char *s, char **sp, int rounding, void *L)
+strtorx_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
 #endif
 {
  static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI };
@@ -117,7 +118,7 @@ strtorx(CONST char *s, char **sp, int ro
  fpi1.rounding = rounding;
  fpi = &fpi1;
  }
- k = strtodg(s, sp, fpi, &exp, bits);
+ k = strtodg_l(s, sp, fpi, &exp, bits, locale);
  ULtox((UShort*)L, bits, exp, k);
  return k;
  }
Index: locale/Makefile.inc
===================================================================
RCS file: /cvs/src/lib/libc/locale/Makefile.inc,v
retrieving revision 1.19
diff -u -p -r1.19 Makefile.inc
--- locale/Makefile.inc 28 Aug 2013 16:53:34 -0000 1.19
+++ locale/Makefile.inc 15 Oct 2013 12:42:22 -0000
@@ -12,13 +12,15 @@ SRCS+= btowc.c _def_messages.c _def_mone
  wcstombs.c wctob.c wctomb.c wcstof.c wcstod.c wcstold.c wcstol.c \
  wcstoul.c wcstoll.c wcstoull.c wcstoimax.c wcstoumax.c \
  setrunelocale.c runeglue.c rune.c runetable.c ___runetype_mb.c \
- _wctrans.c wcsxfrm.c
+ _wctrans.c wcsxfrm.c xlocale.c ctype.c runetype.c tolower.c toupper.c
 
 MAN+= nl_langinfo.3 setlocale.3 iswalnum.3 towlower.3 \
  btowc.3 mblen.3 mbrlen.3 mbrtowc.3 mbsinit.3 mbsrtowcs.3 \
  mbstowcs.3 mbtowc.3 wcrtomb.3 wcsrtombs.3 wcstod.3 wcstol.3 \
  wcstombs.3 wctob.3 wctomb.3 \
- wctype.3 iswctype.3 wctrans.3 towctrans.3 wcwidth.3
+ wctype.3 iswctype.3 wctrans.3 towctrans.3 wcwidth.3 \
+ duplocale.3 freelocale.3 newlocale.3 querylocale.3 uselocale.3 xlocale.3
+
 MLINKS+=setlocale.3 localeconv.3 \
  iswalnum.3 iswalpha.3 \
  iswalnum.3 iswblank.3 \
Index: locale/___runetype_mb.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/___runetype_mb.c,v
retrieving revision 1.2
diff -u -p -r1.2 ___runetype_mb.c
--- locale/___runetype_mb.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/___runetype_mb.c 15 Oct 2013 12:42:22 -0000
@@ -66,3 +66,4 @@ ___runetype_mb(wint_t c)
 
  return (0U);
 }
+
Index: locale/__mb_cur_max.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/__mb_cur_max.c,v
retrieving revision 1.2
diff -u -p -r1.2 __mb_cur_max.c
--- locale/__mb_cur_max.c 8 Aug 2005 08:05:35 -0000 1.2
+++ locale/__mb_cur_max.c 15 Oct 2013 12:42:22 -0000
@@ -29,6 +29,8 @@
 
 #include <sys/types.h>
 #include <limits.h>
+#include <wchar.h>
+#include "mblocal.h"
 
 size_t __mb_cur_max = 1;
 size_t __mb_len_max_runtime = MB_LEN_MAX;
Index: locale/btowc.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/btowc.c,v
retrieving revision 1.2
diff -u -p -r1.2 btowc.c
--- locale/btowc.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/btowc.c 15 Oct 2013 12:42:22 -0000
@@ -4,6 +4,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:
@@ -27,15 +32,17 @@
  */
 
 #include <stdio.h>
-#include <string.h>
 #include <wchar.h>
+#include "mblocal.h"
 
 wint_t
-btowc(int c)
+btowc_l(int c, locale_t l)
 {
- mbstate_t mbs;
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
  char cc;
  wchar_t wc;
+ FIX_LOCALE(l);
 
  if (c == EOF)
  return (WEOF);
@@ -44,9 +51,13 @@ btowc(int c)
  * which detects error return values as well as "impossible" byte
  * counts.
  */
- memset(&mbs, 0, sizeof(mbs));
  cc = (char)c;
- if (mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
  return (WEOF);
  return (wc);
+}
+wint_t
+btowc(int c)
+{
+ return btowc_l(c, __get_locale());
 }
Index: locale/ctype.c
===================================================================
RCS file: locale/ctype.c
diff -N locale/ctype.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/ctype.c 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,33 @@
+/* $OpenBSD$ */
+
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions * are met:
+ * 1.  Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
Index: locale/duplocale.3
===================================================================
RCS file: locale/duplocale.3
diff -N locale/duplocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/duplocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,79 @@
+.\" 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 an independent internal state.
+Various functions, such as
+.Xr mblen 3
+require a persistent 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.
+The locale returned by this call must be freed with
+.Xr freelocale 3 .
+.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 .
+.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.
Index: locale/freelocale.3
===================================================================
RCS file: locale/freelocale.3
diff -N locale/freelocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/freelocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,68 @@
+.\" 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
+The
+.Fn freelocale
+function
+differs from
+.St -p1003.1-2008
+in that its return type is
+.Vt int
+rather than
+.Vt void .
Index: locale/localeconv.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/localeconv.c,v
retrieving revision 1.5
diff -u -p -r1.5 localeconv.c
--- locale/localeconv.c 8 Aug 2005 08:05:35 -0000 1.5
+++ locale/localeconv.c 15 Oct 2013 12:42:22 -0000
@@ -1,59 +1,68 @@
 /* $OpenBSD: localeconv.c,v 1.5 2005/08/08 08:05:35 espie Exp $ */
 /*
- * Written by J.T. Conklin <[hidden email]>.
- * Public domain.
+ * Copyright (c) 2001 Alexey Zelkin <[hidden email]>
+ * 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:
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
  */
 
-#include <sys/localedef.h>
 #include <locale.h>
+#include <xlocale.h>
+#include "xlocale_private.h"
 
-/*
+/*
  * The localeconv() function constructs a struct lconv from the current
  * monetary and numeric locales.
  *
  * Because localeconv() may be called many times (especially by library
- * routines like printf() & strtod()), the approprate members of the
- * lconv structure are computed only when the monetary or numeric
+ * routines like printf() & strtod()), the approprate members of the
+ * 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(void)
+localeconv_l(locale_t loc)
 {
-    static struct lconv ret;
+ FIX_LOCALE(loc);
+    struct lconv *ret = &loc->lconv;
+ ret->decimal_point = ".";
+ /* XXX missing LC_MONETARY and LC_NUMERIC bits */
 
-    if (__mlocale_changed) {
- /* LC_MONETARY */
- ret.int_curr_symbol = _CurrentMonetaryLocale->int_curr_symbol;
- ret.currency_symbol = _CurrentMonetaryLocale->currency_symbol;
- ret.mon_decimal_point = _CurrentMonetaryLocale->mon_decimal_point;
- ret.mon_thousands_sep = _CurrentMonetaryLocale->mon_thousands_sep;
- ret.mon_grouping = _CurrentMonetaryLocale->mon_grouping;
- ret.positive_sign = _CurrentMonetaryLocale->positive_sign;
- ret.negative_sign = _CurrentMonetaryLocale->negative_sign;
- ret.int_frac_digits = _CurrentMonetaryLocale->int_frac_digits;
- ret.frac_digits = _CurrentMonetaryLocale->frac_digits;
- ret.p_cs_precedes = _CurrentMonetaryLocale->p_cs_precedes;
- ret.p_sep_by_space = _CurrentMonetaryLocale->p_sep_by_space;
- ret.n_cs_precedes = _CurrentMonetaryLocale->n_cs_precedes;
- ret.n_sep_by_space = _CurrentMonetaryLocale->n_sep_by_space;
- ret.p_sign_posn = _CurrentMonetaryLocale->p_sign_posn;
- ret.n_sign_posn = _CurrentMonetaryLocale->n_sign_posn;
- __mlocale_changed = 0;
-    }
-
-    if (__nlocale_changed) {
- /* LC_NUMERIC */
- ret.decimal_point = (char *) _CurrentNumericLocale->decimal_point;
- ret.thousands_sep = (char *) _CurrentNumericLocale->thousands_sep;
- ret.grouping = (char *) _CurrentNumericLocale->grouping;
- __nlocale_changed = 0;
-    }
-
-    return (&ret);
+    return ret;
+}
+struct lconv *
+localeconv(void)
+{
+ return localeconv_l(__get_locale());
 }
Index: locale/mblocal.h
===================================================================
RCS file: locale/mblocal.h
diff -N locale/mblocal.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/mblocal.h 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,78 @@
+/*-
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _MBLOCAL_H_
+#define _MBLOCAL_H_
+
+#include <runetype.h>
+#include "xlocale_private.h"
+
+
+/*
+ * Conversion function pointers for current encoding.
+ */
+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;
+
+/*
+ * Rune initialization function prototypes.
+ */
+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);
+extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+#endif /* _MBLOCAL_H_ */
Index: locale/mbrlen.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/mbrlen.c,v
retrieving revision 1.2
diff -u -p -r1.2 mbrlen.c
--- locale/mbrlen.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/mbrlen.c 15 Oct 2013 12:42:22 -0000
@@ -1,9 +1,12 @@
-/* $OpenBSD: mbrlen.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
-
 /*-
  * 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:
@@ -27,13 +30,19 @@
  */
 
 #include <wchar.h>
+#include "mblocal.h"
 
 size_t
-mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale)
 {
- static mbstate_t mbs;
-
+ FIX_LOCALE(locale);
  if (ps == NULL)
- ps = &mbs;
- return (mbrtowc(NULL, s, n, ps));
+ ps = &locale->mbrlen;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps));
+}
+
+size_t
+mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+{
+ return mbrlen_l(s, n, ps, __get_locale());
 }
Index: locale/mbtowc.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/mbtowc.c,v
retrieving revision 1.2
diff -u -p -r1.2 mbtowc.c
--- locale/mbtowc.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/mbtowc.c 15 Oct 2013 12:42:22 -0000
@@ -1,9 +1,13 @@
 /* $OpenBSD: mbtowc.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
-
 /*-
  * 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:
@@ -26,25 +30,29 @@
  * SUCH DAMAGE.
  */
 
-
 #include <stdlib.h>
-#include <string.h>
 #include <wchar.h>
-#include <errno.h>
+#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 mbstate_t mbs;
+ static const mbstate_t initial;
  size_t rval;
+ FIX_LOCALE(locale);
 
  if (s == NULL) {
  /* No support for state dependent encodings. */
- memset(&mbs, 0, sizeof(mbs));
+ locale->mbtowc = initial;
  return (0);
  }
- rval = mbrtowc(pwc, s, n, &mbs);
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, &locale->mbtowc);
  if (rval == (size_t)-1 || rval == (size_t)-2)
  return (-1);
  return ((int)rval);
+}
+int
+mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+{
+ return mbtowc_l(pwc, s, n, __get_locale());
 }
Index: locale/multibyte_citrus.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/multibyte_citrus.c,v
retrieving revision 1.4
diff -u -p -r1.4 multibyte_citrus.c
--- locale/multibyte_citrus.c 5 Dec 2012 23:20:00 -0000 1.4
+++ locale/multibyte_citrus.c 15 Oct 2013 12:42:22 -0000
@@ -35,6 +35,7 @@
 #include "citrus_ctype.h"
 #include "rune.h"
 #include "multibyte.h"
+#include "xlocale_private.h"
 
 int
 mbsinit(const mbstate_t *ps)
@@ -53,73 +54,124 @@ mbsinit(const mbstate_t *ps)
 }
 
 size_t
-mbrtowc(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
+mbrtowc_l(wchar_t *pwc, const char *s, size_t n,
+    mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
  struct _citrus_ctype_rec *cc;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  cc = _CurrentRuneLocale->rl_citrus_ctype;
  return (*cc->cc_ops->co_mbrtowc)(pwc, s, n, _ps_to_private(ps));
 }
+size_t
+mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+    size_t n, mbstate_t * __restrict ps)
+{
+ return mbrtowc_l(pwc, s, n, ps, __get_locale());
+}
 
 size_t
-mbsrtowcs(wchar_t *dst, const char **src, size_t len, mbstate_t *ps)
+mbsrtowcs_l(wchar_t *dst, const char **src, size_t len,
+    mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  return (mbsnrtowcs(dst, src, SIZE_MAX, len, ps));
 }
+size_t
+mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+    mbstate_t * __restrict ps)
+{
+ return mbsrtowcs_l(dst, src, len, ps, __get_locale());
+}
 
 size_t
-mbsnrtowcs(wchar_t *dst, const char **src, size_t nmc, size_t len,
-    mbstate_t *ps)
+mbsnrtowcs_l(wchar_t *dst, const char **src, size_t nmc, size_t len,
+    mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
  struct _citrus_ctype_rec *cc;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  cc = _CurrentRuneLocale->rl_citrus_ctype;
  return (*cc->cc_ops->co_mbsnrtowcs)(dst, src, nmc, len,
     _ps_to_private(ps));
 }
+size_t
+mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t nms,
+    size_t len, mbstate_t * __restrict ps)
+{
+ return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale());
+}
 
 size_t
-wcrtomb(char *s, wchar_t wc, mbstate_t *ps)
+wcrtomb_l(char *s, wchar_t wc, mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
  struct _citrus_ctype_rec *cc;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  cc = _CurrentRuneLocale->rl_citrus_ctype;
  return (*cc->cc_ops->co_wcrtomb)(s, wc, _ps_to_private(ps));
 }
+size_t
+wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ return wcrtomb_l(s, wc, ps, __get_locale());
+}
 
 size_t
-wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps)
+wcsrtombs_l(char *dst, const wchar_t **src, size_t len,
+    mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  return (wcsnrtombs(dst, src, SIZE_MAX, len, ps));
 }
+size_t
+wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+    mbstate_t * __restrict ps)
+{
+ return wcsrtombs_l(dst, src, len, ps, __get_locale());
+}
 
 size_t
-wcsnrtombs(char *dst, const wchar_t **src, size_t nwc, size_t len,
-    mbstate_t *ps)
+wcsnrtombs_l(char *dst, const wchar_t **src, size_t nwc, size_t len,
+    mbstate_t *ps, locale_t locale)
 {
  static mbstate_t mbs;
  struct _citrus_ctype_rec *cc;
 
+ /* XXX xlocale not yet implemented */
+ (void) locale;
  if (ps == NULL)
  ps = &mbs;
  cc = _CurrentRuneLocale->rl_citrus_ctype;
  return (*cc->cc_ops->co_wcsnrtombs)(dst, src, nwc, len,
     _ps_to_private(ps));
 }
+size_t
+wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+    size_t len, mbstate_t * __restrict ps)
+{
+ return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale());
+}
+
Index: locale/newlocale.3
===================================================================
RCS file: locale/newlocale.3
diff -N locale/newlocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/newlocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,112 @@
+.\" 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 locale_t
+.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 .
+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, alphabetic 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 formatting of decimal points in input and output of floating
+point numbers in functions such as
+.Xr printf 3
+and
+.Xr scanf 3 ,
+as well as values returned by
+.Xr localeconv 3 .
+.It LC_TIME_MASK
+Set a locale for formatting dates and times using the
+.Xr strftime 3
+function.
+.El
+This function uses the same rules for loading locale components as
+.Xr setlocale 3 .
+.Sh RETURN VALUES
+Returns a new, valid,
+.Fa locale_t
+or NULL if an error occurs.
+You must free the returned locale with
+.Xr freelocale 3 .
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function conforms to
+.St -p1003.1-2008 .
Index: locale/querylocale.3
===================================================================
RCS file: locale/querylocale.3
diff -N locale/querylocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/querylocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,54 @@
+.\" 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 May 3, 2013
+.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
Index: locale/rune.h
===================================================================
RCS file: /cvs/src/lib/libc/locale/rune.h,v
retrieving revision 1.2
diff -u -p -r1.2 rune.h
--- locale/rune.h 15 Mar 2011 22:27:48 -0000 1.2
+++ locale/rune.h 15 Oct 2013 12:42:22 -0000
@@ -40,7 +40,7 @@
 
 #include <stdio.h>
 #include <wchar.h>
-#include "runetype.h"
+#include <runetype.h>
 
 /*
  * map _RTYPE_x to _CTYPE_x
@@ -74,7 +74,7 @@
  * global variables
  */
 extern size_t __mb_len_max_runtime;
-extern _RuneLocale _DefaultRuneLocale;
-extern _RuneLocale *_CurrentRuneLocale;
+extern const _RuneLocale _DefaultRuneLocale;
+extern const _RuneLocale *_CurrentRuneLocale;
 
 #endif /*! _RUNE_H_ */
Index: locale/rune_local.h
===================================================================
RCS file: /cvs/src/lib/libc/locale/rune_local.h,v
retrieving revision 1.2
diff -u -p -r1.2 rune_local.h
--- locale/rune_local.h 10 Oct 2005 17:37:44 -0000 1.2
+++ locale/rune_local.h 15 Oct 2013 12:42:22 -0000
@@ -29,6 +29,7 @@
 
 #ifndef _RUNE_LOCAL_H_
 #define _RUNE_LOCAL_H_
+#include "runetype.h"
 
 /* rune.c */
 extern _RuneLocale *_Read_RuneMagi(FILE *fp);
Index: locale/runetable.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/runetable.c,v
retrieving revision 1.4
diff -u -p -r1.4 runetable.c
--- locale/runetable.c 5 Dec 2012 23:20:00 -0000 1.4
+++ locale/runetable.c 15 Oct 2013 12:42:22 -0000
@@ -30,8 +30,6 @@
  * 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: src/lib/libc/locale/table.c,v 1.13 2000/02/08 07:43:25 obrien Exp $
  */
 
 #include <stdlib.h>
@@ -44,8 +42,9 @@
 #include "citrus_ctype.h"
 #include "citrus_none.h"
 #include <stdlib.h>
+#include "mblocal.h"
 
-_RuneLocale _DefaultRuneLocale = {
+const _RuneLocale _DefaultRuneLocale = {
     _RUNE_MAGIC_1,
     "NONE",
     _DEFAULT_INVALID_RUNE,
@@ -400,4 +399,13 @@ _RuneLocale _DefaultRuneLocale = {
     NULL
 };
 
-_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+const _RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+
+_RuneLocale *
+__runes_for_locale(locale_t locale, int *mb_sb_limit)
+{
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *c = XLOCALE_CTYPE(locale);
+ *mb_sb_limit = c->__mb_sb_limit;
+ return c->runes;
+}
Index: locale/runetype.c
===================================================================
RCS file: locale/runetype.c
diff -N locale/runetype.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/runetype.c 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * 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:
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+unsigned long
+___runetype_l(__ct_rune_t c, locale_t locale)
+{
+ size_t lim;
+ FIX_LOCALE(locale);
+ _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->rl_runetype_ext);
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(0L);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->rr_rune_ranges;
+ for (lim = rr->rr_nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->re_min <= c && c <= re->re_max) {
+ if (re->re_rune_types)
+    return(re->re_rune_types[c - re->re_min]);
+ else
+    return(re->re_map);
+ } else if (c > re->re_max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(0L);
+}
+unsigned long
+___runetype(__ct_rune_t c)
+{
+ return ___runetype_l(c, __get_locale());
+}
+
+int ___mb_cur_max(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->__mb_cur_max;
+}
+int ___mb_cur_max_l(locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return XLOCALE_CTYPE(locale)->__mb_cur_max;
+}
Index: locale/runetype.h
===================================================================
RCS file: locale/runetype.h
diff -N locale/runetype.h
--- locale/runetype.h 5 Dec 2012 23:20:00 -0000 1.7
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,219 +0,0 @@
-#ifndef _NB_RUNETYPE_H_
-#define _NB_RUNETYPE_H_
-
-/* $OpenBSD: runetype.h,v 1.7 2012/12/05 23:20:00 deraadt Exp $ */
-/* $NetBSD: runetype.h,v 1.18 2003/08/07 16:43:04 agc Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Paul Borman at Krystal Technologies.
- *
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * 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.
- *
- * @(#)runetype.h 8.1 (Berkeley) 6/2/93
- */
-
-#include <sys/types.h>
-#include "ctype_private.h"
-
-typedef uint32_t rune_t;
-typedef uint64_t __runepad_t;
-
-
-#define _CACHED_RUNES (1 << 8) /* Must be a power of 2 */
-#define _RUNE_ISCACHED(c) ((c)>=0 && (c)<_CACHED_RUNES)
-
-#define _DEFAULT_INVALID_RUNE ((rune_t)-3)
-
-/*
- * The lower 8 bits of runetype[] contain the digit value of the rune.
- */
-typedef uint32_t _RuneType;
-
-#define _RUNETYPE_A 0x00000100U /* Alpha */
-#define _RUNETYPE_C 0x00000200U /* Control */
-#define _RUNETYPE_D 0x00000400U /* Digit */
-#define _RUNETYPE_G 0x00000800U /* Graph */
-#define _RUNETYPE_L 0x00001000U /* Lower */
-#define _RUNETYPE_P 0x00002000U /* Punct */
-#define _RUNETYPE_S 0x00004000U /* Space */
-#define _RUNETYPE_U 0x00008000U /* Upper */
-#define _RUNETYPE_X 0x00010000U /* X digit */
-#define _RUNETYPE_B 0x00020000U /* Blank */
-#define _RUNETYPE_R 0x00040000U /* Print */
-#define _RUNETYPE_I 0x00080000U /* Ideogram */
-#define _RUNETYPE_T 0x00100000U /* Special */
-#define _RUNETYPE_Q 0x00200000U /* Phonogram */
-#define _RUNETYPE_SWM 0xe0000000U /* Mask to get screen width data */
-#define _RUNETYPE_SWS 30 /* Bits to shift to get width */
-#define _RUNETYPE_SW0 0x20000000U /* 0 width character */
-#define _RUNETYPE_SW1 0x40000000U /* 1 width character */
-#define _RUNETYPE_SW2 0x80000000U /* 2 width character */
-#define _RUNETYPE_SW3 0xc0000000U /* 3 width character */
-
-
-/*
- * rune file format.  network endian.
- */
-typedef struct {
- int32_t fre_min; /* First rune of the range */
- int32_t fre_max; /* Last rune (inclusive) of the range */
- int32_t fre_map; /* What first maps to in maps */
-} __packed _FileRuneEntry;
-
-
-typedef struct {
- uint32_t frr_nranges; /* Number of ranges stored */
-} __packed _FileRuneRange;
-
-
-typedef struct {
- char frl_magic[8]; /* Magic saying what version we are */
- char frl_encoding[32];/* ASCII name of this encoding */
-
- int32_t frl_invalid_rune;
-
- _RuneType frl_runetype[_CACHED_RUNES];
- int32_t frl_maplower[_CACHED_RUNES];
- int32_t frl_mapupper[_CACHED_RUNES];
-
- /*
- * The following are to deal with Runes larger than _CACHED_RUNES - 1.
- * Their data is actually contiguous with this structure so as to make
- * it easier to read/write from/to disk.
- */
- _FileRuneRange frl_runetype_ext;
- _FileRuneRange frl_maplower_ext;
- _FileRuneRange frl_mapupper_ext;
-
- int32_t frl_variable_len;/* how long that data is */
-
- /* variable size data follows */
-} __packed _FileRuneLocale;
-
-
-/*
- * expanded rune locale declaration.  local to the host.  host endian.
- */
-typedef struct {
- rune_t re_min; /* First rune of the range */
- rune_t re_max; /* Last rune (inclusive) of the range */
- rune_t re_map; /* What first maps to in maps */
- _RuneType *re_rune_types; /* Array of types in range */
-} _RuneEntry;
-
-
-typedef struct {
- uint32_t rr_nranges; /* Number of ranges stored */
- _RuneEntry *rr_rune_ranges;
-} _RuneRange;
-
-
-/*
- * wctrans stuffs.
- */
-typedef struct _WCTransEntry {
- char *te_name;
- rune_t *te_cached;
- _RuneRange *te_extmap;
-} _WCTransEntry;
-
-#define _WCTRANS_INDEX_LOWER 0
-#define _WCTRANS_INDEX_UPPER 1
-#define _WCTRANS_NINDEXES 2
-
-/*
- * wctype stuffs.
- */
-typedef struct _WCTypeEntry {
- char *te_name;
- _RuneType te_mask;
-} _WCTypeEntry;
-#define _WCTYPE_INDEX_ALNUM 0
-#define _WCTYPE_INDEX_ALPHA 1
-#define _WCTYPE_INDEX_BLANK 2
-#define _WCTYPE_INDEX_CNTRL 3
-#define _WCTYPE_INDEX_DIGIT 4
-#define _WCTYPE_INDEX_GRAPH 5
-#define _WCTYPE_INDEX_LOWER 6
-#define _WCTYPE_INDEX_PRINT 7
-#define _WCTYPE_INDEX_PUNCT 8
-#define _WCTYPE_INDEX_SPACE 9
-#define _WCTYPE_INDEX_UPPER 10
-#define _WCTYPE_INDEX_XDIGIT 11
-#define _WCTYPE_NINDEXES 12
-
-/*
- * ctype stuffs
- */
-
-struct old_tabs {
- /* compatibility with `old' ctype */
- char ctype_tab[CTYPE_NUM_CHARS + 1];
- short tolower_tab[256 + 1];
- short toupper_tab[256 + 1];
-};
-
-typedef struct {
- /*
- * copied from _FileRuneLocale
- */
- char rl_magic[8]; /* Magic saying what version we are */
- char rl_encoding[32];/* ASCII name of this encoding */
- rune_t rl_invalid_rune;
- _RuneType rl_runetype[_CACHED_RUNES];
- rune_t rl_maplower[_CACHED_RUNES];
- rune_t rl_mapupper[_CACHED_RUNES];
- _RuneRange rl_runetype_ext;
- _RuneRange rl_maplower_ext;
- _RuneRange rl_mapupper_ext;
-
- void *rl_variable;
- size_t rl_variable_len;
-
- /*
- * the following portion is generated on the fly
- */
- char *rl_codeset;
- struct _citrus_ctype_rec *rl_citrus_ctype;
- _WCTransEntry rl_wctrans[_WCTRANS_NINDEXES];
- _WCTypeEntry rl_wctype[_WCTYPE_NINDEXES];
-
- struct old_tabs * rl_tabs;
-
-} _RuneLocale;
-
-/* magic number for LC_CTYPE (rune)locale declaration */
-#define _RUNE_MAGIC_1 "RuneCT10" /* Indicates version 0 of RuneLocale */
-
-/* magic string for dynamic link module - type should be like "LC_CTYPE" */
-#define _RUNE_MODULE_1(type) "RuneModule10." type
-
-/* codeset tag */
-#define _RUNE_CODESET "CODESET="
-
-#endif
Index: locale/setlocale.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/setlocale.c,v
retrieving revision 1.20
diff -u -p -r1.20 setlocale.c
--- locale/setlocale.c 28 Aug 2013 16:53:34 -0000 1.20
+++ locale/setlocale.c 15 Oct 2013 12:42:22 -0000
@@ -79,7 +79,7 @@ static char *currentlocale(void);
 static void revert_to_default(int);
 static int load_locale_sub(int, const char *, int);
 static char *loadlocale(int);
-static const char *__get_locale_env(int);
+const char *__get_locale_env(int);
 
 char *
 setlocale(int category, const char *locale)
@@ -287,7 +287,7 @@ loadlocale(int category)
  }
 }
 
-static const char *
+const char *
 __get_locale_env(int category)
 {
  const char *env;
Index: locale/setlocale.h
===================================================================
RCS file: locale/setlocale.h
diff -N locale/setlocale.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/setlocale.h 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia.
+ * All rights reserved.
+ *
+ * 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 ``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.
+ */
+
+#ifndef _SETLOCALE_H_
+#define _SETLOCALE_H_
+
+#define ENCODING_LEN 31
+#define CATEGORY_LEN 11
+
+extern char *_PathLocale;
+
+int __detect_path_locale(void);
+int __wrap_setrunelocale(const char *);
+
+#endif /* !_SETLOCALE_H_ */
Index: locale/tolower.c
===================================================================
RCS file: locale/tolower.c
diff -N locale/tolower.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/tolower.c 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * 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:
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+__ct_rune_t
+___tolower_l(c, l)
+ __ct_rune_t c;
+ locale_t l;
+{
+ size_t lim;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->rl_maplower_ext;
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(c);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->rr_rune_ranges;
+ for (lim = rr->rr_nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->re_min <= c && c <= re->re_max)
+ return (re->re_map + c - re->re_min);
+ else if (c > re->re_max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(c);
+}
+__ct_rune_t
+___tolower(c)
+ __ct_rune_t c;
+{
+ return ___tolower_l(c, __get_locale());
+}
Index: locale/toupper.c
===================================================================
RCS file: locale/toupper.c
diff -N locale/toupper.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/toupper.c 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * 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:
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+__ct_rune_t
+___toupper_l(c, l)
+ __ct_rune_t c;
+ locale_t l;
+{
+ size_t lim;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->rl_mapupper_ext;
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(c);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->rr_rune_ranges;
+ for (lim = rr->rr_nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->re_min <= c && c <= re->re_max)
+ {
+ return (re->re_map + c - re->re_min);
+ }
+ else if (c > re->re_max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(c);
+}
+__ct_rune_t
+___toupper(c)
+ __ct_rune_t c;
+{
+ return ___toupper_l(c, __get_locale());
+}
Index: locale/uselocale.3
===================================================================
RCS file: locale/uselocale.3
diff -N locale/uselocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/uselocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,60 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $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 .
Index: locale/wcscoll.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/wcscoll.c,v
retrieving revision 1.2
diff -u -p -r1.2 wcscoll.c
--- locale/wcscoll.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/wcscoll.c 15 Oct 2013 12:42:22 -0000
@@ -29,13 +29,20 @@
 
 #include <assert.h>
 #include <wchar.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Compare strings with using collating information.
  */
 int
-wcscoll(const wchar_t *s1, const wchar_t *s2)
+wcscoll_l(const wchar_t *s1, const wchar_t *s2, locale_t locale)
 {
  /* XXX: LC_COLLATE should be implemented. */
  return (wcscmp(s1, s2));
 }
+int
+wcscoll(const wchar_t *s1, const wchar_t *s2)
+{
+ return wcscoll_l(s1, s2, __get_locale());
+}
+
Index: locale/wcsxfrm.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/wcsxfrm.c,v
retrieving revision 1.2
diff -u -p -r1.2 wcsxfrm.c
--- locale/wcsxfrm.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/wcsxfrm.c 15 Oct 2013 12:42:22 -0000
@@ -32,11 +32,19 @@
  */
 
 #include <wchar.h>
+#include "../locale/xlocale_private.h"
 
 size_t
-wcsxfrm(wchar_t *dest, const wchar_t *src, size_t n)
+wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t n,
+    locale_t locale)
 {
  if (n == 0)
  return wcslen(src);
  return wcslcpy(dest, src, n);
 }
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t n)
+{
+ return wcsxfrm_l(dest, src, n, __get_locale());
+}
+
Index: locale/wctob.c
===================================================================
RCS file: /cvs/src/lib/libc/locale/wctob.c,v
retrieving revision 1.2
diff -u -p -r1.2 wctob.c
--- locale/wctob.c 5 Dec 2012 23:20:00 -0000 1.2
+++ locale/wctob.c 15 Oct 2013 12:42:22 -0000
@@ -1,8 +1,12 @@
-/* $OpenBSD: wctob.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
 /*-
  * 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:
@@ -27,17 +31,23 @@
 
 #include <limits.h>
 #include <stdio.h>
-#include <string.h>
 #include <wchar.h>
+#include "mblocal.h"
 
 int
-wctob(wint_t c)
+wctob_l(wint_t c, locale_t locale)
 {
- mbstate_t mbs;
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
  char buf[MB_LEN_MAX];
+ FIX_LOCALE(locale);
 
- memset(&mbs, 0, sizeof(mbs));
- if (c == WEOF || wcrtomb(buf, c, &mbs) != 1)
+ if (c == WEOF /* || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1 */)
  return (EOF);
  return ((unsigned char)*buf);
+}
+int
+wctob(wint_t c)
+{
+ return wctob_l(c, __get_locale());
 }
Index: locale/xlocale.3
===================================================================
RCS file: locale/xlocale.3
diff -N locale/xlocale.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/xlocale.3 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,280 @@
+.\" 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 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:
+.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 .
+.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.
Index: locale/xlocale.c
===================================================================
RCS file: locale/xlocale.c
diff -N locale/xlocale.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/xlocale.c 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,400 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "runetype.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;
+
+#ifndef __NO_TLS
+/*
+ * The locale for this thread.
+ */
+_Thread_local locale_t __thread_locale;
+#endif
+/*
+ * Flag indicating that one or more per-thread locales exist.
+ */
+int __has_thread_locale;
+/*
+ * Private functions in setlocale.c.
+ */
+const char *
+__get_locale_env(int category);
+int
+__detect_path_locale(void);
+
+struct _xlocale __xlocale_global_locale = {
+ {0},
+ {
+#if 0
+ &__xlocale_global_collate,
+ &__xlocale_global_ctype,
+ &__xlocale_global_monetary,
+ &__xlocale_global_numeric,
+ &__xlocale_global_time,
+ &__xlocale_global_messages
+#endif
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+struct _xlocale __xlocale_C_locale = {
+ {0},
+ {
+ &__xlocale_C_collate,
+ &__xlocale_C_ctype,
+ 0, 0, 0, 0
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+void *__collate_load(const char *a, locale_t b) { return NULL; }
+void *__ctype_load(const char *a, locale_t b) { return NULL; }
+void *__monetary_load(const char *a, locale_t b) { return NULL; }
+void *__numeric_load(const char *a, locale_t b) { return NULL; }
+void *__time_load(const char *a, locale_t b) { return NULL; }
+void *__messages_load(const char *a, locale_t b) { return NULL; }
+
+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)
+{
+#if 0
+ 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;
+ }
+ /* At least one per-thread locale has now been set. */
+ __has_thread_locale = 1;
+ __detect_path_locale();
+#else
+ __has_thread_locale = 1;
+#endif
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+/* Single threaded pthread_once(3).  libc won't have to -lpthread. */
+static int
+_once(pthread_once_t *o, void (*init_routine)(void))
+{
+ if (o->state == PTHREAD_DONE_INIT)
+ return (0);
+ init_routine();
+ o->state = PTHREAD_DONE_INIT;
+ return (0);
+}
+
+static locale_t
+get_thread_locale(void)
+{
+
+ _once(&once_control, init_key);
+
+#if 0
+ return (fake_tls ? thread_local_locale :
+ pthread_getspecific(locale_info_key));
+#else
+ return thread_local_locale;
+#endif
+}
+
+#ifdef __NO_TLS
+locale_t
+__get_locale(void)
+{
+ locale_t l = get_thread_locale();
+ // XXX FreeBSD uses &__xlocale_global_locale
+ return (l ? l : &__xlocale_C_locale);
+
+}
+#endif
+
+static void
+set_thread_locale(locale_t loc)
+{
+
+ _once(&once_control, init_key);
+
+ if (NULL != loc) {
+ xlocale_retain((struct xlocale_refcounted*)loc);
+ }
+#if 0
+ 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);
+ }
+#ifndef __NO_TLS
+ __thread_locale = loc;
+ __set_thread_rune_locale(loc);
+#endif
+#else /* 0 */
+ thread_local_locale = loc;
+#endif
+}
+
+/**
+ * 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;
+ int type;
+
+ for (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 if (base->components[type]) {
+ new->components[type] = xlocale_retain(base->components[type]);
+ } else {
+ /* If the component was NULL, return success - if base is a
+ * valid locale then the flag indicating that this isn't
+ * present should be set.  If it isn't a valid locale, then
+ * we're stuck anyway. */
+ return 1;
+ }
+ 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);
+}
+
Index: locale/xlocale_private.h
===================================================================
RCS file: locale/xlocale_private.h
diff -N locale/xlocale_private.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ locale/xlocale_private.h 15 Oct 2013 12:42:22 -0000
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <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 mbrtoc16() calls. */
+ __mbstate_t mbrtoc16;
+ /** Persistent state used by mbrtoc32() calls. */
+ __mbstate_t mbrtoc32;
+ /** 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 c16rtomb() calls. */
+ __mbstate_t c16rtomb;
+ /** Persistent state used by c32rtomb() calls. */
+ __mbstate_t c32rtomb;
+ /** 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;
+ obj->retain_count++;
+ // XXX 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 = obj->retain_count--;
+ // XXX 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;
+
+/**
+ * Caches the rune table in TLS for fast access.
+ */
+void __set_thread_rune_locale(locale_t loc);
+/**
+ * Flag indicating whether a per-thread locale has been set.  If no per-thread
+ * locale has ever been set, then we always use the global locale.
+ */
+extern int __has_thread_locale;
+#ifndef __NO_TLS
+/**
+ * The per-thread locale.  Avoids the need to use pthread lookup functions when
+ * getting the per-thread locale.
+ */
+extern _Thread_local locale_t __thread_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.
+ */
+static inline locale_t __get_locale(void)
+{
+
+ if (!__has_thread_locale) {
+ return (&__xlocale_global_locale);
+ }
+ return (__thread_locale ? __thread_locale : &__xlocale_global_locale);
+}
+#else
+locale_t __get_locale(void);
+#endif
+
+/**
+ * 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
Index: stdio/asprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/asprintf.c,v
retrieving revision 1.19
diff -u -p -r1.19 asprintf.c
--- stdio/asprintf.c 30 May 2011 18:48:33 -0000 1.19
+++ stdio/asprintf.c 15 Oct 2013 12:42:22 -0000
@@ -21,11 +21,12 @@
 #include <string.h>
 #include <errno.h>
 #include <stdarg.h>
+#include <xlocale.h>
 #include "local.h"
 
 /* PRINTFLIKE2 */
 int
-asprintf(char **str, const char *fmt, ...)
+asprintf_l(char **str, locale_t locale, const char *fmt, ...)
 {
  int ret;
  va_list ap;
@@ -41,7 +42,7 @@ asprintf(char **str, const char *fmt, ..
  goto err;
  f._bf._size = f._w = 127; /* Leave room for the NUL */
  va_start(ap, fmt);
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
  va_end(ap);
  if (ret == -1)
  goto err;
@@ -61,3 +62,15 @@ err:
  errno = ENOMEM;
  return (-1);
 }
+int
+asprintf(char ** __restrict s, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vasprintf(s, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+
Index: stdio/fscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/fscanf.c,v
retrieving revision 1.10
diff -u -p -r1.10 fscanf.c
--- stdio/fscanf.c 30 May 2011 18:48:33 -0000 1.10
+++ stdio/fscanf.c 15 Oct 2013 12:42:22 -0000
@@ -33,8 +33,20 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <xlocale.h>
 
 /* SCANFLIKE2 */
+int
+fscanf_l(FILE *fp, locale_t locale, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfscanf_l(fp, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
 int
 fscanf(FILE *fp, const char *fmt, ...)
 {
Index: stdio/local.h
===================================================================
RCS file: /cvs/src/lib/libc/stdio/local.h,v
retrieving revision 1.20
diff -u -p -r1.20 local.h
--- stdio/local.h 8 Nov 2011 18:30:42 -0000 1.20
+++ stdio/local.h 15 Oct 2013 12:42:22 -0000
@@ -38,6 +38,7 @@
  */
 
 #include <wchar.h>
+#include <xlocale.h>
 #include "wcio.h"
 #include "fileext.h"
 
@@ -58,8 +59,8 @@ int __swsetup(FILE *);
 int __sflags(const char *, int *);
 wint_t __fgetwc_unlock(FILE *);
 wint_t __ungetwc(wint_t, FILE *);
-int __vfprintf(FILE *, const char *, __va_list);
-int __svfscanf(FILE * __restrict, const char * __restrict, __va_list);
+int __vfprintf(FILE *, locale_t, const char *, __va_list);
+int __svfscanf(FILE * __restrict, locale_t, const char * __restrict, __va_list);
 int __vfwprintf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 int __vfwscanf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 
Index: stdio/scanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/scanf.c,v
retrieving revision 1.10
diff -u -p -r1.10 scanf.c
--- stdio/scanf.c 30 May 2011 18:48:33 -0000 1.10
+++ stdio/scanf.c 15 Oct 2013 12:42:22 -0000
@@ -33,8 +33,20 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <xlocale.h>
 
 /* SCANFLIKE1 */
+int
+scanf_l(locale_t locale, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfscanf_l(stdin, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
 int
 scanf(const char *fmt, ...)
 {
Index: stdio/snprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/snprintf.c,v
retrieving revision 1.18
diff -u -p -r1.18 snprintf.c
--- stdio/snprintf.c 30 May 2011 18:48:33 -0000 1.18
+++ stdio/snprintf.c 15 Oct 2013 12:42:22 -0000
@@ -3,6 +3,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.
  *
@@ -31,11 +36,14 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <limits.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdarg.h>
+#include <string.h>
+
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 /* PRINTFLIKE3 */
 int
@@ -61,8 +69,38 @@ snprintf(char *str, size_t n, const char
  f._bf._base = f._p = (unsigned char *)str;
  f._bf._size = f._w = n - 1;
  va_start(ap, fmt);
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, __get_locale(), fmt, ap);
  va_end(ap);
  *f._p = '\0';
+ 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;
+ struct __sfileext fext;
+ FILE f;
+ FIX_LOCALE(locale);
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ *str = '\0';
+ return (EOF);
+ }
+ _FILEEXT_SETUP(&f, &fext);
+ va_start(ap, fmt);
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ ret = __vfprintf(&f, locale, fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ va_end(ap);
  return (ret);
 }
Index: stdio/sprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/sprintf.c,v
retrieving revision 1.17
diff -u -p -r1.17 sprintf.c
--- stdio/sprintf.c 30 May 2011 18:48:33 -0000 1.17
+++ stdio/sprintf.c 15 Oct 2013 12:42:22 -0000
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <limits.h>
+#include <xlocale.h>
 #include "local.h"
 
 #if defined(APIWARN)
@@ -44,7 +45,7 @@ __warn_references(sprintf,
 
 /* PRINTFLIKE2 */
 int
-sprintf(char *str, const char *fmt, ...)
+sprintf_l(char *str, locale_t locale, const char *fmt, ...)
 {
  int ret;
  va_list ap;
@@ -57,8 +58,20 @@ sprintf(char *str, const char *fmt, ...)
  f._bf._base = f._p = (unsigned char *)str;
  f._bf._size = f._w = INT_MAX;
  va_start(ap, fmt);
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
  va_end(ap);
  *f._p = '\0';
  return (ret);
 }
+int
+sprintf(char * __restrict str, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsprintf(str, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+
Index: stdio/sscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/sscanf.c,v
retrieving revision 1.14
diff -u -p -r1.14 sscanf.c
--- stdio/sscanf.c 8 Nov 2011 18:30:42 -0000 1.14
+++ stdio/sscanf.c 15 Oct 2013 12:42:22 -0000
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 /* ARGSUSED */
 static int
@@ -60,7 +61,26 @@ sscanf(const char *str, const char *fmt,
  f._read = eofread;
  f._lb._base = NULL;
  va_start(ap, fmt);
- ret = __svfscanf(&f, fmt, ap);
+ ret = __svfscanf(&f, __get_locale(), fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+sscanf_l(const char *str, locale_t locale, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FILE f;
+ struct __sfileext fext;
+
+ _FILEEXT_SETUP(&f, &fext);
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._read = eofread;
+ f._lb._base = NULL;
+ va_start(ap, fmt);
+ ret = __svfscanf(&f, locale, fmt, ap);
  va_end(ap);
  return (ret);
 }
Index: stdio/vasprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vasprintf.c,v
retrieving revision 1.16
diff -u -p -r1.16 vasprintf.c
--- stdio/vasprintf.c 9 Nov 2009 00:18:27 -0000 1.16
+++ stdio/vasprintf.c 15 Oct 2013 12:42:22 -0000
@@ -21,9 +21,10 @@
 #include <string.h>
 #include <errno.h>
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 int
-vasprintf(char **str, const char *fmt, __va_list ap)
+vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
 {
  int ret;
  FILE f;
@@ -37,7 +38,7 @@ vasprintf(char **str, const char *fmt, _
  if (f._bf._base == NULL)
  goto err;
  f._bf._size = f._w = 127; /* Leave room for the NUL */
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
  if (ret == -1)
  goto err;
  *f._p = '\0';
@@ -56,3 +57,9 @@ err:
  errno = ENOMEM;
  return (-1);
 }
+int
+vasprintf(char **str, const char *fmt, __va_list ap)
+{
+ return vasprintf_l(str, __get_locale(), fmt, ap);
+}
+
Index: stdio/vdprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vdprintf.c,v
retrieving revision 1.1
diff -u -p -r1.1 vdprintf.c
--- stdio/vdprintf.c 30 Jan 2013 00:08:13 -0000 1.1
+++ stdio/vdprintf.c 15 Oct 2013 12:42:22 -0000
@@ -39,6 +39,7 @@
 #include <unistd.h>
 
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 static int
 __dwrite(void *cookie, const char *buf, int n)
@@ -66,7 +67,7 @@ vdprintf(int fd, const char * __restrict
  f._cookie = &fd;
  f._write = __dwrite;
 
- if ((ret = __vfprintf(&f, fmt, ap)) < 0)
+ if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
  return ret;
 
  return fflush(&f) ? EOF : ret;
Index: stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.63
diff -u -p -r1.63 vfprintf.c
--- stdio/vfprintf.c 2 Mar 2013 19:40:08 -0000 1.63
+++ stdio/vfprintf.c 15 Oct 2013 12:42:22 -0000
@@ -6,6 +6,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:
@@ -54,6 +59,7 @@
 
 #include "local.h"
 #include "fvwrite.h"
+#include "../locale/xlocale_private.h"
 
 union arg {
  int intarg;
@@ -88,7 +94,7 @@ union arg {
 };
 
 static int __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
-    size_t *argtablesiz);
+    size_t *argtablesiz, locale_t locale);
 static int __grow_type_table(unsigned char **typetable, int *tablesize);
 
 /*
@@ -96,7 +102,7 @@ static int __grow_type_table(unsigned ch
  * 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;
 
@@ -116,7 +122,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;
@@ -136,7 +142,7 @@ __sbprintf(FILE *fp, const char *fmt, va
  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 && __sflush(&fake))
  ret = EOF;
  if (fake._flags & __SERR)
@@ -260,18 +266,31 @@ static int exponent(char *, int, int);
 #define MAXINT 0x1000 /* largest integer size (intmax_t) */
 
 int
-vfprintf(FILE *fp, const char *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);
- ret = __vfprintf(fp, fmt0, ap);
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+    fp->_file >= 0)
+ ret = __sbprintf(fp, locale, fmt0, ap);
+ else
+ 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);
+}
 
 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 */
@@ -359,7 +378,7 @@ __vfprintf(FILE *fp, const char *fmt0, _
  uio.uio_resid += (len); \
  iovp++; \
  if (++uio.uio_iovcnt >= NIOV) { \
- if (__sprint(fp, &uio)) \
+ if (__sprint(fp, &uio, locale)) \
  goto error; \
  iovp = iov; \
  } \
@@ -382,7 +401,7 @@ __vfprintf(FILE *fp, const char *fmt0, _
  PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
 } while(0)
 #define FLUSH() do { \
- if (uio.uio_resid && __sprint(fp, &uio)) \
+ if (uio.uio_resid && __sprint(fp, &uio, locale)) \
  goto error; \
  uio.uio_iovcnt = 0; \
  iovp = iov; \
@@ -438,7 +457,7 @@ __vfprintf(FILE *fp, const char *fmt0, _
  int hold = nextarg; \
  if (argtable == NULL) { \
  argtable = statargtable; \
- __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
+ __find_arguments(fmt0, orgap, &argtable, &argtablesiz, locale); \
  } \
  nextarg = n2; \
  val = GETARG(int); \
@@ -464,11 +483,6 @@ __vfprintf(FILE *fp, const char *fmt0, _
  return (EOF);
  }
 
- /* optimise fprintf(stderr) (and other unbuffered Unix files) */
- if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
-    fp->_file >= 0)
- return (__sbprintf(fp, fmt0, ap));
-
  fmt = (char *)fmt0;
  argtable = NULL;
  nextarg = 1;
@@ -487,7 +501,12 @@ __vfprintf(FILE *fp, const char *fmt0, _
  */
  for (;;) {
  cp = fmt;
+#if 0
+ while ((n = mbrtowc_l(&wc, fmt, MB_CUR_MAX_L(locale),
+    &ps, locale)) > 0) {
+#else
  while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
+#endif
  fmt += n;
  if (wc == '%') {
  fmt--;
@@ -565,7 +584,7 @@ reswitch: switch (ch) {
  if (argtable == NULL) {
  argtable = statargtable;
  __find_arguments(fmt0, orgap,
-    &argtable, &argtablesiz);
+    &argtable, &argtablesiz, locale);
  }
  goto rflag;
  }
@@ -591,7 +610,7 @@ reswitch: switch (ch) {
  if (argtable == NULL) {
  argtable = statargtable;
  __find_arguments(fmt0, orgap,
-    &argtable, &argtablesiz);
+    &argtable, &argtablesiz, locale);
  }
  goto rflag;
  }
@@ -637,8 +656,8 @@ reswitch: switch (ch) {
  size_t mbseqlen;
 
  memset(&mbs, 0, sizeof(mbs));
- mbseqlen = wcrtomb(buf,
-    (wchar_t)GETARG(wint_t), &mbs);
+ mbseqlen = wcrtomb_l(buf,
+    (wchar_t)GETARG(wint_t), &mbs, locale);
  if (mbseqlen == (size_t)-1) {
  fp->_flags |= __SERR;
  errno = EILSEQ;
@@ -1132,7 +1151,7 @@ finish:
  */
 static int
 __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
-    size_t *argtablesiz)
+    size_t *argtablesiz, locale_t locale)
 {
  char *fmt; /* format string */
  int ch; /* character from fmt */
@@ -1207,7 +1226,8 @@ __find_arguments(const char *fmt0, va_li
  */
  for (;;) {
  cp = fmt;
- while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
+ while ((n = mbrtowc_l(&wc, fmt, MB_CUR_MAX_L(locale),
+    &ps, locale)) > 0) {
  fmt += n;
  if (wc == '%') {
  fmt--;
Index: stdio/vfscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vfscanf.c,v
retrieving revision 1.30
diff -u -p -r1.30 vfscanf.c
--- stdio/vfscanf.c 17 Apr 2013 17:40:35 -0000 1.30
+++ stdio/vfscanf.c 15 Oct 2013 12:42:22 -0000
@@ -40,6 +40,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include "local.h"
+#include "../locale/mblocal.h"
+#include "../locale/xlocale_private.h"
 
 #ifdef FLOATING_POINT
 #include "floatio.h"
@@ -96,7 +98,7 @@ static u_char *__sccl(char *, u_char *);
  * Internal, unlocked 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)
 {
  u_char *fmt = (u_char *)fmt0;
  int c; /* character from format, or conversion */
@@ -129,9 +131,9 @@ __svfscanf(FILE *fp, const char *fmt0, _
  c = *fmt++;
  if (c == 0)
  return (nassigned);
- if (isspace(c)) {
+ if (isspace_l(c, locale)) {
  while ((fp->_r > 0 || __srefill(fp) == 0) &&
-    isspace(*fp->_p))
+    isspace_l(*fp->_p, locale))
  nread++, fp->_r--, fp->_p++;
  continue;
  }
@@ -315,7 +317,7 @@ literal:
  * that suppress this.
  */
  if ((flags & NOSKIP) == 0) {
- while (isspace(*fp->_p)) {
+ while (isspace_l(*fp->_p, locale)) {
  nread++;
  if (--fp->_r > 0)
  fp->_p++;
@@ -354,7 +356,8 @@ literal:
  fp->_p++;
  fp->_r--;
  bzero(&mbs, sizeof(mbs));
- nconv = mbrtowc(wcp, buf, n, &mbs);
+ nconv = XLOCALE_CTYPE(locale)->__mbrtowc(
+    wcp, buf, n, &mbs);
  if (nconv == (size_t)-1) {
  fp->_flags |= __SERR;
  goto input_failure;
@@ -436,7 +439,8 @@ literal:
  fp->_p++;
  fp->_r--;
  bzero(&mbs, sizeof(mbs));
- nconv = mbrtowc(wcp, buf, n, &mbs);
+ nconv = XLOCALE_CTYPE(locale)->__mbrtowc(
+    wcp, buf, n, &mbs);
  if (nconv == (size_t)-1) {
  fp->_flags |= __SERR;
  goto input_failure;
@@ -444,8 +448,8 @@ literal:
  if (nconv == 0)
  *wcp = L'\0';
  if (nconv != (size_t)-2) {
- if (wctob(*wcp) != EOF &&
-    !ccltab[wctob(*wcp)]) {
+ int b = wctob_l(*wcp, locale);
+ if (b != EOF && !ccltab[b]) {
  while (n != 0) {
  n--;
  ungetc(buf[n],
@@ -531,7 +535,7 @@ literal:
  else
  wcp = &twc;
  n = 0;
- while (!isspace(*fp->_p) && width != 0) {
+ while (!isspace_l(*fp->_p, locale) && width != 0) {
  if (n == MB_CUR_MAX) {
  fp->_flags |= __SERR;
  goto input_failure;
@@ -540,7 +544,8 @@ literal:
  fp->_p++;
  fp->_r--;
  bzero(&mbs, sizeof(mbs));
- nconv = mbrtowc(wcp, buf, n, &mbs);
+ nconv = XLOCALE_CTYPE(locale)->__mbrtowc(
+    wcp, buf, n, &mbs);
  if (nconv == (size_t)-1) {
  fp->_flags |= __SERR;
  goto input_failure;
@@ -578,7 +583,7 @@ literal:
 #endif /* SCANF_WIDE_CHAR */
  if (flags & SUPPRESS) {
  n = 0;
- while (!isspace(*fp->_p)) {
+ while (!isspace_l(*fp->_p, locale)) {
  n++, fp->_r--, fp->_p++;
  if (--width == 0)
  break;
@@ -588,7 +593,7 @@ literal:
  nread += n;
  } else {
  p0 = p = va_arg(ap, char *);
- while (!isspace(*fp->_p)) {
+ while (!isspace_l(*fp->_p, locale)) {
  fp->_r--;
  *p++ = *fp->_p++;
  if (--width == 0)
@@ -730,9 +735,9 @@ literal:
 
  *p = '\0';
  if (flags & UNSIGNED)
- res = strtoumax(buf, NULL, base);
+ res = strtoumax_l(buf, NULL, base, locale);
  else
- res = strtoimax(buf, NULL, base);
+ res = strtoimax_l(buf, NULL, base, locale);
  if (flags & POINTER)
  *va_arg(ap, void **) =
     (void *)(uintptr_t)res;
@@ -837,14 +842,14 @@ literal:
  if ((flags & SUPPRESS) == 0) {
  *p = '\0';
  if (flags & LONGDBL) {
- long double res = strtold(buf,
-    (char **)NULL);
+ long double res = strtold_l(buf,
+    (char **)NULL, locale);
  *va_arg(ap, long double *) = res;
  } else if (flags & LONG) {
- double res = strtod(buf, (char **)NULL);
+ double res = strtod_l(buf, (char **)NULL, locale);
  *va_arg(ap, double *) = res;
  } else {
- float res = strtof(buf, (char **)NULL);
+ float res = strtof_l(buf, (char **)NULL, locale);
  *va_arg(ap, float *) = res;
  }
  nassigned++;
@@ -958,12 +963,22 @@ doswitch:
 }
 
 int
+vfscanf_l(FILE *fp, locale_t locale, const char *fmt0, __va_list ap)
+{
+ int r;
+
+ FLOCKFILE(fp);
+ r = __svfscanf(fp, locale, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (r);
+}
+int
 vfscanf(FILE *fp, const char *fmt0, __va_list ap)
 {
  int r;
 
  FLOCKFILE(fp);
- r = __svfscanf(fp, fmt0, ap);
+ r = __svfscanf(fp, __get_locale(), fmt0, ap);
  FUNLOCKFILE(fp);
  return (r);
 }
Index: stdio/vsnprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsnprintf.c,v
retrieving revision 1.15
diff -u -p -r1.15 vsnprintf.c
--- stdio/vsnprintf.c 9 Nov 2009 00:18:28 -0000 1.15
+++ stdio/vsnprintf.c 15 Oct 2013 12:42:22 -0000
@@ -35,9 +35,10 @@
 #include <stdio.h>
 #include <string.h>
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 int
-vsnprintf(char *str, size_t n, const char *fmt, __va_list ap)
+vsnprintf_l(char *str, size_t n, locale_t locale, const char *fmt, __va_list ap)
 {
  int ret;
  char dummy;
@@ -58,7 +59,14 @@ vsnprintf(char *str, size_t n, const cha
  f._flags = __SWR | __SSTR;
  f._bf._base = f._p = (unsigned char *)str;
  f._bf._size = f._w = n - 1;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
  *f._p = '\0';
  return (ret);
 }
+int
+vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
+    __va_list ap)
+{
+ return vsnprintf_l(str, n, __get_locale(), fmt, ap);
+}
+
Index: stdio/vsprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsprintf.c,v
retrieving revision 1.16
diff -u -p -r1.16 vsprintf.c
--- stdio/vsprintf.c 9 Nov 2009 00:18:28 -0000 1.16
+++ stdio/vsprintf.c 15 Oct 2013 12:42:22 -0000
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <limits.h>
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 #if defined(APIWARN)
 __warn_references(vsprintf,
@@ -42,7 +43,7 @@ __warn_references(vsprintf,
 #endif
 
 int
-vsprintf(char *str, const char *fmt, __va_list ap)
+vsprintf_l(char *str, locale_t locale, const char *fmt, __va_list ap)
 {
  int ret;
  FILE f;
@@ -53,7 +54,13 @@ vsprintf(char *str, const char *fmt, __v
  f._flags = __SWR | __SSTR;
  f._bf._base = f._p = (unsigned char *)str;
  f._bf._size = f._w = INT_MAX;
- ret = __vfprintf(&f, fmt, ap);
+ ret = __vfprintf(&f, locale, fmt, ap);
  *f._p = '\0';
  return (ret);
 }
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+ return vsprintf_l(str, __get_locale(), fmt, ap);
+}
+
Index: stdio/vsscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsscanf.c,v
retrieving revision 1.12
diff -u -p -r1.12 vsscanf.c
--- stdio/vsscanf.c 8 Nov 2011 18:30:42 -0000 1.12
+++ stdio/vsscanf.c 15 Oct 2013 12:42:22 -0000
@@ -34,6 +34,7 @@
 #include <stdio.h>
 #include <string.h>
 #include "local.h"
+#include "../locale/xlocale_private.h"
 
 /* ARGSUSED */
 static int
@@ -55,5 +56,5 @@ vsscanf(const char *str, const char *fmt
  f._bf._size = f._r = strlen(str);
  f._read = eofread;
  f._lb._base = NULL;
- return (__svfscanf(&f, fmt, ap));
+ return (__svfscanf(&f, __get_locale(), fmt, ap));
 }
Index: stdlib/strtoimax.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtoimax.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtoimax.c
--- stdlib/strtoimax.c 13 Jan 2006 17:58:09 -0000 1.1
+++ stdlib/strtoimax.c 15 Oct 2013 12:42:22 -0000
@@ -31,6 +31,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include "../locale/xlocale_private.h"
 #include <inttypes.h>
 
 /*
@@ -40,12 +41,14 @@
  * alphabets and digits are each contiguous.
  */
 intmax_t
-strtoimax(const char *nptr, char **endptr, int base)
+strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+    locale_t locale)
 {
  const char *s;
  intmax_t acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * Skip white space and pick up leading +/- sign if any.
@@ -55,7 +58,7 @@ strtoimax(const char *nptr, char **endpt
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -138,3 +141,9 @@ strtoimax(const char *nptr, char **endpt
  *endptr = (char *) (any ? s - 1 : nptr);
  return (acc);
 }
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoimax_l(nptr, endptr, base, __get_locale());
+}
+
Index: stdlib/strtol.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtol.c,v
retrieving revision 1.9
diff -u -p -r1.9 strtol.c
--- stdlib/strtol.c 17 Apr 2013 17:40:35 -0000 1.9
+++ stdlib/strtol.c 15 Oct 2013 12:42:22 -0000
@@ -32,6 +32,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include "../locale/xlocale_private.h"
 
 
 /*
@@ -41,12 +42,13 @@
  * alphabets and digits are each contiguous.
  */
 long
-strtol(const char *nptr, char **endptr, int base)
+strtol_l(const char *nptr, char **endptr, int base, locale_t locale)
 {
  const char *s;
  long acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * Ensure that base is between 2 and 36 inclusive, or the special
@@ -67,7 +69,7 @@ strtol(const char *nptr, char **endptr,
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -148,4 +150,14 @@ strtol(const char *nptr, char **endptr,
  if (endptr != 0)
  *endptr = (char *) (any ? s - 1 : nptr);
  return (acc);
+}
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtol_l(nptr, endptr, base, __get_locale());
+}
+long double
+strtold(const char * __restrict nptr, char ** __restrict endptr)
+{
+ return strtold_l(nptr, endptr, __get_locale());
 }
Index: stdlib/strtoll.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtoll.c,v
retrieving revision 1.7
diff -u -p -r1.7 strtoll.c
--- stdlib/strtoll.c 28 Mar 2013 18:09:38 -0000 1.7
+++ stdlib/strtoll.c 15 Oct 2013 12:42:22 -0000
@@ -34,6 +34,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Convert a string to a long long.
@@ -42,12 +43,13 @@
  * alphabets and digits are each contiguous.
  */
 long long
-strtoll(const char *nptr, char **endptr, int base)
+strtoll_l(const char *nptr, char **endptr, int base, locale_t locale)
 {
  const char *s;
  long long acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * Skip white space and pick up leading +/- sign if any.
@@ -57,7 +59,7 @@ strtoll(const char *nptr, char **endptr,
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -139,6 +141,11 @@ strtoll(const char *nptr, char **endptr,
  if (endptr != 0)
  *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());
 }
 
 __strong_alias(strtoq, strtoll);
Index: stdlib/strtoul.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtoul.c,v
retrieving revision 1.8
diff -u -p -r1.8 strtoul.c
--- stdlib/strtoul.c 17 Apr 2013 17:40:35 -0000 1.8
+++ stdlib/strtoul.c 15 Oct 2013 12:42:22 -0000
@@ -32,6 +32,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Convert a string to an unsigned long integer.
@@ -40,12 +41,13 @@
  * alphabets and digits are each contiguous.
  */
 unsigned long
-strtoul(const char *nptr, char **endptr, int base)
+strtoul_l(const char *nptr, char **endptr, int base, locale_t locale)
 {
  const char *s;
  unsigned long acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * See strtol for comments as to the logic used.
@@ -53,7 +55,7 @@ strtoul(const char *nptr, char **endptr,
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -100,3 +102,9 @@ strtoul(const char *nptr, char **endptr,
  *endptr = (char *) (any ? s - 1 : nptr);
  return (acc);
 }
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoul_l(nptr, endptr, base, __get_locale());
+}
+
Index: stdlib/strtoull.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtoull.c,v
retrieving revision 1.6
diff -u -p -r1.6 strtoull.c
--- stdlib/strtoull.c 28 Mar 2013 18:09:38 -0000 1.6
+++ stdlib/strtoull.c 15 Oct 2013 12:42:22 -0000
@@ -34,6 +34,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Convert a string to an unsigned long long.
@@ -42,12 +43,13 @@
  * alphabets and digits are each contiguous.
  */
 unsigned long long
-strtoull(const char *nptr, char **endptr, int base)
+strtoull_l(const char *nptr, char **endptr, int base, locale_t locale)
 {
  const char *s;
  unsigned long long acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * See strtoq for comments as to the logic used.
@@ -55,7 +57,7 @@ strtoull(const char *nptr, char **endptr
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -101,6 +103,11 @@ strtoull(const char *nptr, char **endptr
  if (endptr != 0)
  *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());
 }
 
 __strong_alias(strtouq, strtoull);
Index: stdlib/strtoumax.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/strtoumax.c,v
retrieving revision 1.1
diff -u -p -r1.1 strtoumax.c
--- stdlib/strtoumax.c 13 Jan 2006 17:58:09 -0000 1.1
+++ stdlib/strtoumax.c 15 Oct 2013 12:42:22 -0000
@@ -31,6 +31,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include "../locale/xlocale_private.h"
 #include <inttypes.h>
 
 /*
@@ -40,12 +41,13 @@
  * alphabets and digits are each contiguous.
  */
 uintmax_t
-strtoumax(const char *nptr, char **endptr, int base)
+strtoumax_l(const char *nptr, char **endptr, int base, locale_t locale)
 {
  const char *s;
  uintmax_t acc, cutoff;
  int c;
  int neg, any, cutlim;
+ FIX_LOCALE(locale);
 
  /*
  * See strtoq for comments as to the logic used.
@@ -53,7 +55,7 @@ strtoumax(const char *nptr, char **endpt
  s = nptr;
  do {
  c = (unsigned char) *s++;
- } while (isspace(c));
+ } while (isspace_l(c, locale));
  if (c == '-') {
  neg = 1;
  c = *s++;
@@ -100,3 +102,9 @@ strtoumax(const char *nptr, char **endpt
  *endptr = (char *) (any ? s - 1 : nptr);
  return (acc);
 }
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoumax_l(nptr, endptr, base, __get_locale());
+}
+
Index: string/strcoll.c
===================================================================
RCS file: /cvs/src/lib/libc/string/strcoll.c,v
retrieving revision 1.5
diff -u -p -r1.5 strcoll.c
--- string/strcoll.c 8 Aug 2005 08:05:37 -0000 1.5
+++ string/strcoll.c 15 Oct 2013 12:42:22 -0000
@@ -32,13 +32,20 @@
  */
 
 #include <string.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Compare strings according to LC_COLLATE category of current locale.
  */
 int
-strcoll(const char *s1, const char *s2)
+strcoll_l(const char *s1, const char *s2, locale_t locale)
 {
  /* LC_COLLATE is unimplemented, hence always "C" */
  return (strcmp(s1, s2));
 }
+int
+strcoll(const char *s1, const char *s2)
+{
+ return strcoll_l(s1, s2, __get_locale());
+}
+
Index: string/strxfrm.c
===================================================================
RCS file: /cvs/src/lib/libc/string/strxfrm.c,v
retrieving revision 1.6
diff -u -p -r1.6 strxfrm.c
--- string/strxfrm.c 8 Aug 2005 08:05:37 -0000 1.6
+++ string/strxfrm.c 15 Oct 2013 12:42:22 -0000
@@ -32,6 +32,7 @@
  */
 
 #include <string.h>
+#include "../locale/xlocale_private.h"
 
 /*
  * Transform src, storing the result in dst, such that
@@ -39,7 +40,8 @@
  * on the original untransformed strings would return.
  */
 size_t
-strxfrm(char *dst, const char *src, size_t n)
+strxfrm_l(char * __restrict dst, const char * __restrict src, size_t n,
+    locale_t locale)
 {
 
  /*
@@ -49,3 +51,9 @@ strxfrm(char *dst, const char *src, size
  return (strlen(src));
  return (strlcpy(dst, src, n));
 }
+size_t
+strxfrm(char * __restrict dest, const char * __restrict src, size_t n)
+{
+ return strxfrm_l(dest, src, n, __get_locale());
+}
+
Index: string/wcscasecmp.c
===================================================================
RCS file: /cvs/src/lib/libc/string/wcscasecmp.c,v
retrieving revision 1.2
diff -u -p -r1.2 wcscasecmp.c
--- string/wcscasecmp.c 1 Jun 2011 19:29:48 -0000 1.2
+++ string/wcscasecmp.c 15 Oct 2013 12:42:22 -0000
@@ -27,7 +27,7 @@
 
 #include <wchar.h>
 #include <wctype.h>
-#include "locale/runetype.h"
+#include <runetype.h>
 
 int
 wcscasecmp(const wchar_t *s1, const wchar_t *s2)
Index: string/wcscmp.c
===================================================================
RCS file: /cvs/src/lib/libc/string/wcscmp.c,v
retrieving revision 1.4
diff -u -p -r1.4 wcscmp.c
--- string/wcscmp.c 8 Aug 2005 08:05:37 -0000 1.4
+++ string/wcscmp.c 15 Oct 2013 12:42:22 -0000
@@ -34,7 +34,7 @@
  */
 
 #include <wchar.h>
-#include "locale/runetype.h"
+#include <runetype.h>
 
 /*
  * Compare strings.
Index: string/wcsncmp.c
===================================================================
RCS file: /cvs/src/lib/libc/string/wcsncmp.c,v
retrieving revision 1.4
diff -u -p -r1.4 wcsncmp.c
--- string/wcsncmp.c 8 Aug 2005 08:05:37 -0000 1.4
+++ string/wcsncmp.c 15 Oct 2013 12:42:22 -0000
@@ -31,7 +31,7 @@
  */
 
 #include <wchar.h>
-#include "locale/runetype.h"
+#include <runetype.h>
 
 int
 wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
Index: string/wmemcmp.c
===================================================================
RCS file: /cvs/src/lib/libc/string/wmemcmp.c,v
retrieving revision 1.4
diff -u -p -r1.4 wmemcmp.c
--- string/wmemcmp.c 8 Aug 2005 08:05:37 -0000 1.4
+++ string/wmemcmp.c 15 Oct 2013 12:42:22 -0000
@@ -30,7 +30,7 @@
  */
 
 #include <wchar.h>
-#include "locale/runetype.h"
+#include <runetype.h>
 
 int
 wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n)
Index: time/strftime.c
===================================================================
RCS file: /cvs/src/lib/libc/time/strftime.c,v
retrieving revision 1.21
diff -u -p -r1.21 strftime.c
--- time/strftime.c 13 Sep 2012 11:14:20 -0000 1.21
+++ time/strftime.c 15 Oct 2013 12:42:22 -0000
@@ -33,6 +33,7 @@
 #include "tzfile.h"
 #include "fcntl.h"
 #include "locale.h"
+#include "../locale/xlocale_private.h"
 
 struct lc_time_T {
  const char * mon[MONSPERYEAR];
@@ -106,7 +107,7 @@ static const struct lc_time_T C_time_loc
 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[];
@@ -121,35 +122,33 @@ extern char * tzname[];
 #define IN_ALL 3
 
 size_t
-strftime(s, maxsize, format, t)
-char * const s;
-const size_t maxsize;
-const char * const format;
-const struct tm * const t;
+strftime_l(char * const __restrict s, const size_t maxsize,
+    const char * __restrict format, const struct tm * __restrict t, locale_t loc)
 {
  char * p;
  int warn;
+ FIX_LOCALE(loc);
 
  tzset();
 #ifdef LOCALE_HOME
  localebuf.mon[0] = 0;
 #endif /* defined LOCALE_HOME */
  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) {
@@ -160,14 +159,21 @@ const struct tm * const t;
  *p = '\0';
  return p - s;
 }
+size_t
+strftime(char * const __restrict s, const 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;
 {
  for ( ; *format; ++format) {
  if (*format == '%') {
@@ -216,7 +222,7 @@ label:
  {
  int warn2 = IN_SOME;
 
- pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
+ pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2, loc);
  if (warn2 == IN_ALL)
  warn2 = IN_THIS;
  if (warn2 > *warnp)
@@ -224,7 +230,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, "%02d", pt, ptlim);
@@ -245,7 +251,7 @@ label:
  pt = _conv(t->tm_mday, "%2d", 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, "%02d", pt, ptlim);
@@ -309,10 +315,10 @@ 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("%I:%M:%S %p", t, pt, ptlim, warnp);
+ pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, loc);
  continue;
  case 'S':
  pt = _conv(t->tm_sec, "%02d", pt, ptlim);
@@ -335,7 +341,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);
@@ -450,7 +456,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 -
@@ -463,13 +469,13 @@ label:
  pt = _conv(t->tm_wday, "%d", pt, ptlim);
  continue;
  case 'X':
- pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
+ pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, loc);
  continue;
  case 'x':
  {
  int warn2 = IN_SOME;
 
- pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
+ pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, loc);
  if (warn2 == IN_ALL)
  warn2 = IN_THIS;
  if (warn2 > *warnp)
@@ -555,7 +561,7 @@ label:
  continue;
  case '+':
  pt = _fmt(Locale->date_fmt, t, pt, ptlim,
- warnp);
+ warnp, loc);
  continue;
  case '%':
  /*

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Martin Pelikan
> - port xlocale(3) from FreeBSD -- this is what this patch does
>
> I did the patch in two parts, separating include/ and lib/libc/, because my

Second part (include/ headers) follows.
--
Martin Pelikan


Index: _ctype.h
===================================================================
RCS file: _ctype.h
diff -N _ctype.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ _ctype.h 15 Oct 2013 12:51:52 -0000
@@ -0,0 +1,189 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ *
+ * From @(#)ctype.h 8.4 (Berkeley) 1/21/94
+ * From FreeBSD: src/include/ctype.h,v 1.27 2004/06/23 07:11:39 tjr Exp
+ */
+
+#ifndef __CTYPE_H_
+#define __CTYPE_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+extern const _RuneLocale _DefaultRuneLocale;
+extern const _RuneLocale *_CurrentRuneLocale;
+
+#define _CTYPE_A 0x00000100L /* Alpha */
+#define _CTYPE_C 0x00000200L /* Control */
+#define _CTYPE_D 0x00000400L /* Digit */
+#define _CTYPE_G 0x00000800L /* Graph */
+#define _CTYPE_L 0x00001000L /* Lower */
+#define _CTYPE_P 0x00002000L /* Punct */
+#define _CTYPE_S 0x00004000L /* Space */
+#define _CTYPE_U 0x00008000L /* Upper */
+#define _CTYPE_X 0x00010000L /* X digit */
+#define _CTYPE_B 0x00020000L /* Blank */
+#define _CTYPE_R 0x00040000L /* Print */
+#define _CTYPE_I 0x00080000L /* Ideogram */
+#define _CTYPE_T 0x00100000L /* Special */
+#define _CTYPE_Q 0x00200000L /* Phonogram */
+#define _CTYPE_SW0 0x20000000L /* 0 width character */
+#define _CTYPE_SW1 0x40000000L /* 1 width character */
+#define _CTYPE_SW2 0x80000000L /* 2 width character */
+#define _CTYPE_SW3 0xc0000000L /* 3 width character */
+#define _CTYPE_SWM 0xe0000000L /* Mask for screen width data */
+#define _CTYPE_SWS 30 /* Bits to shift to get width */
+
+/* See comments in <sys/_types.h> about __ct_rune_t. */
+__BEGIN_DECLS
+unsigned long ___runetype(__ct_rune_t) __pure;
+__ct_rune_t ___tolower(__ct_rune_t) __pure;
+__ct_rune_t ___toupper(__ct_rune_t) __pure;
+__END_DECLS
+
+/*
+ * _EXTERNALIZE_CTYPE_INLINES_ is defined in locale/nomacros.c to tell us
+ * to generate code for extern versions of all our inline functions.
+ */
+#ifdef _EXTERNALIZE_CTYPE_INLINES_
+#define _USE_CTYPE_INLINE_
+#define static
+#define __inline
+#endif
+
+extern int __mb_sb_limit;
+
+/*
+ * Use inline functions if we are allowed to and the compiler supports them.
+ */
+#if !defined(_DONT_USE_CTYPE_INLINE_) && \
+    (defined(_USE_CTYPE_INLINE_) || defined(__GNUC__) || defined(__cplusplus))
+
+#include <runetype.h>
+
+static __inline int
+__maskrune(__ct_rune_t _c, unsigned long _f)
+{
+ return ((_c < 0 || _c >= _CACHED_RUNES) ? ___runetype(_c) :
+ _CurrentRuneLocale->rl_runetype[_c]) & _f;
+}
+
+static __inline int
+__sbmaskrune(__ct_rune_t _c, unsigned long _f)
+{
+ return (_c < 0 || _c >= __mb_sb_limit) ? 0 :
+       _CurrentRuneLocale->rl_runetype[_c] & _f;
+}
+
+static __inline int
+__istype(__ct_rune_t _c, unsigned long _f)
+{
+ return (!!__maskrune(_c, _f));
+}
+
+static __inline int
+__sbistype(__ct_rune_t _c, unsigned long _f)
+{
+ return (!!__sbmaskrune(_c, _f));
+}
+
+static __inline int
+__isctype(__ct_rune_t _c, unsigned long _f)
+{
+ return (_c < 0 || _c >= 128) ? 0 :
+       !!(_DefaultRuneLocale.rl_runetype[_c] & _f);
+}
+
+static __inline __ct_rune_t
+__toupper(__ct_rune_t _c)
+{
+ return (_c < 0 || _c >= _CACHED_RUNES) ? ___toupper(_c) :
+       _CurrentRuneLocale->rl_mapupper[_c];
+}
+
+static __inline __ct_rune_t
+__sbtoupper(__ct_rune_t _c)
+{
+ return (_c < 0 || _c >= __mb_sb_limit) ? _c :
+       _CurrentRuneLocale->rl_mapupper[_c];
+}
+
+static __inline __ct_rune_t
+__tolower(__ct_rune_t _c)
+{
+ return (_c < 0 || _c >= _CACHED_RUNES) ? ___tolower(_c) :
+       _CurrentRuneLocale->rl_maplower[_c];
+}
+
+static __inline __ct_rune_t
+__sbtolower(__ct_rune_t _c)
+{
+ return (_c < 0 || _c >= __mb_sb_limit) ? _c :
+       _CurrentRuneLocale->rl_maplower[_c];
+}
+
+static __inline int
+__wcwidth(__ct_rune_t _c)
+{
+ unsigned int _x;
+
+ if (_c == 0)
+ return (0);
+ _x = (unsigned int)__maskrune(_c, _CTYPE_SWM|_CTYPE_R);
+ if ((_x & _CTYPE_SWM) != 0)
+ return ((_x & _CTYPE_SWM) >> _CTYPE_SWS);
+ return ((_x & _CTYPE_R) != 0 ? 1 : -1);
+}
+
+#else /* not using inlines */
+
+__BEGIN_DECLS
+int __maskrune(__ct_rune_t, unsigned long);
+int __sbmaskrune(__ct_rune_t, unsigned long);
+int __istype(__ct_rune_t, unsigned long);
+int __sbistype(__ct_rune_t, unsigned long);
+int __isctype(__ct_rune_t, unsigned long);
+__ct_rune_t __toupper(__ct_rune_t);
+__ct_rune_t __sbtoupper(__ct_rune_t);
+__ct_rune_t __tolower(__ct_rune_t);
+__ct_rune_t __sbtolower(__ct_rune_t);
+int __wcwidth(__ct_rune_t);
+__END_DECLS
+#endif /* using inlines */
+
+#endif /* !__CTYPE_H_ */
Index: ctype.h
===================================================================
RCS file: /cvs/src/include/ctype.h,v
retrieving revision 1.22
diff -u -p -r1.22 ctype.h
--- ctype.h 1 Oct 2010 20:10:24 -0000 1.22
+++ ctype.h 15 Oct 2013 12:51:52 -0000
@@ -41,6 +41,8 @@
 #define _CTYPE_H_
 
 #include <sys/cdefs.h>
+#include <sys/types.h>
+typedef __rune_t __ct_rune_t;
 
 #define _U 0x01
 #define _L 0x02
Index: runetype.h
===================================================================
RCS file: runetype.h
diff -N runetype.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ runetype.h 15 Oct 2013 12:51:52 -0000
@@ -0,0 +1,220 @@
+#ifndef _NB_RUNETYPE_H_
+#define _NB_RUNETYPE_H_
+
+/* $OpenBSD: runetype.h,v 1.7 2012/12/05 23:20:00 deraadt Exp $ */
+/* $NetBSD: runetype.h,v 1.18 2003/08/07 16:43:04 agc Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)runetype.h 8.1 (Berkeley) 6/2/93
+ */
+
+#include <sys/types.h>
+//#include "ctype_private.h"
+#define CTYPE_NUM_CHARS 256
+
+typedef uint32_t rune_t;
+typedef uint64_t __runepad_t;
+
+
+#define _CACHED_RUNES (1 << 8) /* Must be a power of 2 */
+#define _RUNE_ISCACHED(c) ((c)>=0 && (c)<_CACHED_RUNES)
+
+#define _DEFAULT_INVALID_RUNE ((rune_t)-3)
+
+/*
+ * The lower 8 bits of runetype[] contain the digit value of the rune.
+ */
+typedef uint32_t _RuneType;
+
+#define _RUNETYPE_A 0x00000100U /* Alpha */
+#define _RUNETYPE_C 0x00000200U /* Control */
+#define _RUNETYPE_D 0x00000400U /* Digit */
+#define _RUNETYPE_G 0x00000800U /* Graph */
+#define _RUNETYPE_L 0x00001000U /* Lower */
+#define _RUNETYPE_P 0x00002000U /* Punct */
+#define _RUNETYPE_S 0x00004000U /* Space */
+#define _RUNETYPE_U 0x00008000U /* Upper */
+#define _RUNETYPE_X 0x00010000U /* X digit */
+#define _RUNETYPE_B 0x00020000U /* Blank */
+#define _RUNETYPE_R 0x00040000U /* Print */
+#define _RUNETYPE_I 0x00080000U /* Ideogram */
+#define _RUNETYPE_T 0x00100000U /* Special */
+#define _RUNETYPE_Q 0x00200000U /* Phonogram */
+#define _RUNETYPE_SWM 0xe0000000U /* Mask to get screen width data */
+#define _RUNETYPE_SWS 30 /* Bits to shift to get width */
+#define _RUNETYPE_SW0 0x20000000U /* 0 width character */
+#define _RUNETYPE_SW1 0x40000000U /* 1 width character */
+#define _RUNETYPE_SW2 0x80000000U /* 2 width character */
+#define _RUNETYPE_SW3 0xc0000000U /* 3 width character */
+
+
+/*
+ * rune file format.  network endian.
+ */
+typedef struct {
+ int32_t fre_min; /* First rune of the range */
+ int32_t fre_max; /* Last rune (inclusive) of the range */
+ int32_t fre_map; /* What first maps to in maps */
+} __packed _FileRuneEntry;
+
+
+typedef struct {
+ uint32_t frr_nranges; /* Number of ranges stored */
+} __packed _FileRuneRange;
+
+
+typedef struct {
+ char frl_magic[8]; /* Magic saying what version we are */
+ char frl_encoding[32];/* ASCII name of this encoding */
+
+ int32_t frl_invalid_rune;
+
+ _RuneType frl_runetype[_CACHED_RUNES];
+ int32_t frl_maplower[_CACHED_RUNES];
+ int32_t frl_mapupper[_CACHED_RUNES];
+
+ /*
+ * The following are to deal with Runes larger than _CACHED_RUNES - 1.
+ * Their data is actually contiguous with this structure so as to make
+ * it easier to read/write from/to disk.
+ */
+ _FileRuneRange frl_runetype_ext;
+ _FileRuneRange frl_maplower_ext;
+ _FileRuneRange frl_mapupper_ext;
+
+ int32_t frl_variable_len;/* how long that data is */
+
+ /* variable size data follows */
+} __packed _FileRuneLocale;
+
+
+/*
+ * expanded rune locale declaration.  local to the host.  host endian.
+ */
+typedef struct {
+ rune_t re_min; /* First rune of the range */
+ rune_t re_max; /* Last rune (inclusive) of the range */
+ rune_t re_map; /* What first maps to in maps */
+ _RuneType *re_rune_types; /* Array of types in range */
+} _RuneEntry;
+
+
+typedef struct {
+ uint32_t rr_nranges; /* Number of ranges stored */
+ _RuneEntry *rr_rune_ranges;
+} _RuneRange;
+
+
+/*
+ * wctrans stuffs.
+ */
+typedef struct _WCTransEntry {
+ char *te_name;
+ rune_t *te_cached;
+ _RuneRange *te_extmap;
+} _WCTransEntry;
+
+#define _WCTRANS_INDEX_LOWER 0
+#define _WCTRANS_INDEX_UPPER 1
+#define _WCTRANS_NINDEXES 2
+
+/*
+ * wctype stuffs.
+ */
+typedef struct _WCTypeEntry {
+ char *te_name;
+ _RuneType te_mask;
+} _WCTypeEntry;
+#define _WCTYPE_INDEX_ALNUM 0
+#define _WCTYPE_INDEX_ALPHA 1
+#define _WCTYPE_INDEX_BLANK 2
+#define _WCTYPE_INDEX_CNTRL 3
+#define _WCTYPE_INDEX_DIGIT 4
+#define _WCTYPE_INDEX_GRAPH 5
+#define _WCTYPE_INDEX_LOWER 6
+#define _WCTYPE_INDEX_PRINT 7
+#define _WCTYPE_INDEX_PUNCT 8
+#define _WCTYPE_INDEX_SPACE 9
+#define _WCTYPE_INDEX_UPPER 10
+#define _WCTYPE_INDEX_XDIGIT 11
+#define _WCTYPE_NINDEXES 12
+
+/*
+ * ctype stuffs
+ */
+
+struct old_tabs {
+ /* compatibility with `old' ctype */
+ char ctype_tab[CTYPE_NUM_CHARS + 1];
+ short tolower_tab[256 + 1];
+ short toupper_tab[256 + 1];
+};
+
+typedef struct {
+ /*
+ * copied from _FileRuneLocale
+ */
+ char rl_magic[8]; /* Magic saying what version we are */
+ char rl_encoding[32];/* ASCII name of this encoding */
+ rune_t rl_invalid_rune;
+ _RuneType rl_runetype[_CACHED_RUNES];
+ rune_t rl_maplower[_CACHED_RUNES];
+ rune_t rl_mapupper[_CACHED_RUNES];
+ _RuneRange rl_runetype_ext;
+ _RuneRange rl_maplower_ext;
+ _RuneRange rl_mapupper_ext;
+
+ void *rl_variable;
+ size_t rl_variable_len;
+
+ /*
+ * the following portion is generated on the fly
+ */
+ char *rl_codeset;
+ struct _citrus_ctype_rec *rl_citrus_ctype;
+ _WCTransEntry rl_wctrans[_WCTRANS_NINDEXES];
+ _WCTypeEntry rl_wctype[_WCTYPE_NINDEXES];
+
+ struct old_tabs * rl_tabs;
+
+} _RuneLocale;
+
+/* magic number for LC_CTYPE (rune)locale declaration */
+#define _RUNE_MAGIC_1 "RuneCT10" /* Indicates version 0 of RuneLocale */
+
+/* magic string for dynamic link module - type should be like "LC_CTYPE" */
+#define _RUNE_MODULE_1(type) "RuneModule10." type
+
+/* codeset tag */
+#define _RUNE_CODESET "CODESET="
+
+#endif
Index: xlocale.h
===================================================================
RCS file: xlocale.h
diff -N xlocale.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale.h 15 Oct 2013 12:51:52 -0000
@@ -0,0 +1,84 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XLOCALE_H_
+#define _XLOCALE_H_
+
+#include <locale.h>
+__BEGIN_DECLS
+#include <xlocale/_locale.h>
+
+#ifdef _STRING_H_
+#include <xlocale/_string.h>
+#endif
+
+#ifdef _INTTYPES_H_
+#include <xlocale/_inttypes.h>
+#endif
+
+#ifdef _MONETARY_H_
+#include <xlocale/_monetary.h>
+#endif
+
+#ifdef _STDLIB_H_
+#include <xlocale/_stdlib.h>
+#endif
+
+#ifdef _TIME_H_
+#include <xlocale/_time.h>
+#endif
+
+#ifdef _LANGINFO_H_
+#include <xlocale/_langinfo.h>
+#endif
+
+#ifdef _CTYPE_H_
+#include <xlocale/_ctype.h>
+#endif
+
+#ifdef _WCTYPE_H_
+#define _XLOCALE_WCTYPES 1
+#include <xlocale/_ctype.h>
+#endif
+
+#ifdef _STDIO_H_
+#include <xlocale/_stdio.h>
+#endif
+
+#ifdef _WCHAR_H_
+#include <xlocale/_wchar.h>
+#endif
+
+
+
+struct lconv *localeconv_l(locale_t);
+__END_DECLS
+
+#endif
Index: xlocale/Makefile
===================================================================
RCS file: xlocale/Makefile
diff -N xlocale/Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/Makefile 15 Oct 2013 12:51:52 -0000
@@ -0,0 +1,8 @@
+# $OpenBSD$
+
+NO_OBJ=
+INCS= _ctype.h _inttypes.h _langinfo.h _locale.h _monetary.h _stdio.h\
+ _stdlib.h _string.h _time.h _uchar.h _wchar.h
+INCSDIR=${INCLUDEDIR}/xlocale
+
+.include <bsd.prog.mk>
Index: xlocale/_ctype.h
===================================================================
RCS file: xlocale/_ctype.h
diff -N xlocale/_ctype.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_ctype.h 15 Oct 2013 12:51:52 -0000
@@ -0,0 +1,208 @@
+/* $OpenBSD$ */
+/*-
+ * 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.
+ */
+
+
+#if (defined(_XLOCALE_WCTYPES) && !defined(_XLOCALE_WCTYPE_H)) || \
+ (!defined(_XLOCALE_WCTYPES) && !defined(_XLOCALE_CTYPE_H))
+
+#if defined(__OpenBSD__)
+typedef int __ct_rune_t;
+#include <runetype.h>
+#include <_ctype.h>
+#endif /* (__OpenBSD__) */
+
+#ifdef _XLOCALE_WCTYPES
+#define _XLOCALE_WCTYPE_H
+#else
+#define _XLOCALE_CTYPE_H
+#endif
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+#ifndef _XLOCALE_RUN_FUNCTIONS_DEFINED
+#define _XLOCALE_RUN_FUNCTIONS_DEFINED 1
+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*);
+#endif
+
+#ifndef _XLOCALE_INLINE
+#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
+/* GNU89 inline has nonstandard semantics. */
+#define _XLOCALE_INLINE extern __inline
+#else
+/* Hack to work around people who define inline away */
+#ifdef inline
+#define _XLOCALE_INLINE static __inline
+#else
+/* Define with C++ / C99 compatible semantics */
+#define _XLOCALE_INLINE inline
+#endif
+#endif
+#endif /* _XLOCALE_INLINE */
+
+#ifdef _XLOCALE_WCTYPES
+_XLOCALE_INLINE int
+__maskrune_l(__ct_rune_t __c, unsigned long __f, locale_t __loc);
+_XLOCALE_INLINE int
+__istype_l(__ct_rune_t __c, unsigned long __f, locale_t __loc);
+
+_XLOCALE_INLINE int
+__maskrune_l(__ct_rune_t __c, unsigned long __f, locale_t __loc)
+{
+ int __limit;
+ _RuneLocale *runes = __runes_for_locale(__loc, &__limit);
+ return ((__c < 0 || __c >= _CACHED_RUNES) ? ___runetype_l(__c, __loc) :
+        runes->rl_runetype[__c]) & __f;
+}
+
+_XLOCALE_INLINE int
+__istype_l(__ct_rune_t __c, unsigned long __f, locale_t __loc)
+{
+ return (!!__maskrune_l(__c, __f, __loc));
+}
+
+#define XLOCALE_ISCTYPE(fname, cat) \
+ _XLOCALE_INLINE int isw##fname##_l(int, locale_t);\
+ _XLOCALE_INLINE int isw##fname##_l(int __c, locale_t __l)\
+ { return __istype_l(__c, cat, __l); }
+#else
+_XLOCALE_INLINE int
+__sbmaskrune_l(__ct_rune_t __c, unsigned long __f, locale_t __loc);
+_XLOCALE_INLINE int
+__sbistype_l(__ct_rune_t __c, unsigned long __f, locale_t __loc);
+
+_XLOCALE_INLINE int
+__sbmaskrune_l(__ct_rune_t __c, unsigned long __f, locale_t __loc)
+{
+ int __limit;
+ _RuneLocale *runes = __runes_for_locale(__loc, &__limit);
+ return (__c < 0 || __c >= __limit) ? 0 :
+       runes->rl_runetype[__c] & __f;
+}
+
+_XLOCALE_INLINE int
+__sbistype_l(__ct_rune_t __c, unsigned long __f, locale_t __loc)
+{
+ return (!!__sbmaskrune_l(__c, __f, __loc));
+}
+
+#define XLOCALE_ISCTYPE(__fname, __cat) \
+ _XLOCALE_INLINE int is##__fname##_l(int, locale_t); \
+ _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, locale_t);
+_XLOCALE_INLINE int __wcwidth_l(__ct_rune_t, locale_t);
+_XLOCALE_INLINE int towupper_l(int, locale_t);
+
+_XLOCALE_INLINE int towlower_l(int __c, locale_t __l)
+{
+ int __limit;
+ _RuneLocale *__runes = __runes_for_locale(__l, &__limit);
+ return (__c < 0 || __c >= _CACHED_RUNES) ? ___tolower_l(__c, __l) :
+       __runes->rl_maplower[__c];
+}
+_XLOCALE_INLINE int towupper_l(int __c, locale_t __l)
+{
+ int __limit;
+ _RuneLocale *__runes = __runes_for_locale(__l, &__limit);
+ return (__c < 0 || __c >= _CACHED_RUNES) ? ___toupper_l(__c, __l) :
+       __runes->rl_mapupper[__c];
+}
+_XLOCALE_INLINE int
+__wcwidth_l(__ct_rune_t _c, locale_t __l)
+{
+ unsigned int _x;
+
+ if (_c == 0)
+ return (0);
+ _x = (unsigned int)__maskrune_l(_c, _CTYPE_SWM|_CTYPE_R, __l);
+ 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 __l);
+wctype_t wctype_l(const char *property, locale_t __l);
+wint_t towctrans_l(wint_t __wc, wctrans_t desc, locale_t __l);
+wint_t nextwctype_l(wint_t __wc, wctype_t wct, locale_t __l);
+wctrans_t wctrans_l(const char *__charclass, locale_t __l);
+#undef _XLOCALE_WCTYPES
+#else
+_XLOCALE_INLINE int digittoint_l(int, locale_t);
+_XLOCALE_INLINE int tolower_l(int, locale_t);
+_XLOCALE_INLINE int toupper_l(int, locale_t);
+
+_XLOCALE_INLINE int digittoint_l(int __c, locale_t __l)
+{ return __sbmaskrune_l((__c), 0xFF, __l); }
+
+_XLOCALE_INLINE int tolower_l(int __c, locale_t __l)
+{
+ int __limit;
+ _RuneLocale *__runes = __runes_for_locale(__l, &__limit);
+ return (__c < 0 || __c >= __limit) ? __c :
+       __runes->rl_maplower[__c];
+}
+_XLOCALE_INLINE int toupper_l(int __c, locale_t __l)
+{
+ int __limit;
+ _RuneLocale *__runes = __runes_for_locale(__l, &__limit);
+ return (__c < 0 || __c >= __limit) ? __c :
+       __runes->rl_mapupper[__c];
+}
+#endif
+#endif /* (defined(_XLOCALE_WCTYPES) && !defined(_XLOCALE_WCTYPE_H)) || \
+ (!defined(_XLOCALE_WCTYPES) && !defined(_XLOCALE_CTYPE_H)) */
Index: xlocale/_inttypes.h
===================================================================
RCS file: xlocale/_inttypes.h
diff -N xlocale/_inttypes.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_inttypes.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 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.
+ */
+
+
+/*
+ * Extended locale versions of the locale-aware functions from inttypes.h.
+ * Include <inttypes.h> before <xlocale.h> to expose these.
+ */
+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);
Index: xlocale/_langinfo.h
===================================================================
RCS file: xlocale/_langinfo.h
diff -N xlocale/_langinfo.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_langinfo.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,41 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XLOCALE_LANGINFO_H
+#define _XLOCALE_LANGINFO_H
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+char *nl_langinfo_l(nl_item, locale_t);
+
+#endif /* _XLOCALE_LANGINFO_H */
Index: xlocale/_locale.h
===================================================================
RCS file: xlocale/_locale.h
diff -N xlocale/_locale.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_locale.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,55 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XLOCALE_LOCALE_H
+#define _XLOCALE_LOCALE_H
+
+#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)
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+locale_t duplocale(locale_t base);
+int freelocale(locale_t loc);
+locale_t newlocale(int mask, const char *locale, locale_t base);
+const char *querylocale(int mask, locale_t loc);
+locale_t uselocale(locale_t loc);
+
+#endif /* _XLOCALE_LOCALE_H */
Index: xlocale/_monetary.h
===================================================================
RCS file: xlocale/_monetary.h
diff -N xlocale/_monetary.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_monetary.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,44 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+#if __POSIX_VISIBLE >= 200809 || defined(_XLOCALE_H_)
+#ifndef _XLOCALE_MONETARY_H
+#define _XLOCALE_MONETARY_H
+
+ssize_t strfmon_l(char *, size_t, locale_t, const char *, ...)
+    __strfmonlike(4, 5);
+
+#endif /* _XLOCALE_MONETARY_H */
+#endif /* __POSIX_VISIBLE >= 200809 || defined(_XLOCALE_H_) */
Index: xlocale/_stdio.h
===================================================================
RCS file: xlocale/_stdio.h
diff -N xlocale/_stdio.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_stdio.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,54 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 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.
+ */
+
+int asprintf_l(char **, locale_t, const char *, ...);
+int dprintf_l(int, locale_t, const char * __restrict, ...);
+int fprintf_l(FILE * __restrict, locale_t, const char * __restrict, ...);
+int fscanf_l(FILE * __restrict, locale_t, const char * __restrict, ...);
+int printf_l(locale_t, const char * __restrict, ...);
+int scanf_l(locale_t, const char * __restrict, ...);
+int snprintf_l(char * __restrict, size_t, locale_t,
+    const char * __restrict, ...);
+int sprintf_l(char * __restrict, locale_t, const char * __restrict, ...);
+int sscanf_l(const char * __restrict, locale_t, const char * __restrict, ...);
+int vfprintf_l(FILE * __restrict, locale_t, const char * __restrict,
+    __va_list);
+int vprintf_l(locale_t, const char * __restrict, __va_list);
+int vsprintf_l(char * __restrict, locale_t, const char * __restrict,
+    __va_list);
+int vfscanf_l(FILE * __restrict, locale_t, const char * __restrict,
+    __va_list);
+int vscanf_l(locale_t, const char * __restrict, __va_list);
+int vsnprintf_l(char * __restrict, size_t, locale_t,
+    const char * __restrict, __va_list);
+int vsscanf_l(const char * __restrict, locale_t, const char * __restrict,
+    __va_list);
+int vdprintf_l(int, locale_t, const char * __restrict, __va_list);
+int vasprintf_l(char **, locale_t, const char *, __va_list);
Index: xlocale/_stdlib.h
===================================================================
RCS file: xlocale/_stdlib.h
diff -N xlocale/_stdlib.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_stdlib.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,58 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 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.
+ */
+
+/*
+ * Extended locale versions of the locale-aware functions from stdlib.h.
+ *
+ * Include <stdlib.h> before <xlocale.h> to expose these.
+ */
+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))
+
Index: xlocale/_string.h
===================================================================
RCS file: xlocale/_string.h
diff -N xlocale/_string.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_string.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,60 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+/*
+ * This file is included from both string.h and xlocale.h.  We need to expose
+ * the declarations unconditionally if we are included from xlocale.h, but only
+ * if we are in POSIX2008 mode if included from string.h.
+ */
+
+#ifndef _XLOCALE_STRING1_H
+#define _XLOCALE_STRING1_H
+
+/*
+ * POSIX2008 functions
+ */
+int strcoll_l(const char *, const char *, locale_t);
+size_t strxfrm_l(char *, const char *, size_t, locale_t);
+#endif /* _XLOCALE_STRING1_H */
+
+/*
+ * xlocale extensions
+ */
+#ifdef _XLOCALE_H_
+#ifndef _XLOCALE_STRING2_H
+#define _XLOCALE_STRING2_H
+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 /* _XLOCALE_STRING2_H */
+#endif /* _XLOCALE_H_ */
Index: xlocale/_time.h
===================================================================
RCS file: xlocale/_time.h
diff -N xlocale/_time.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_time.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,57 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+/*
+ * This file is included from both locale.h and xlocale.h.  We need to expose
+ * the declarations unconditionally if we are included from xlocale.h, but only
+ * if we are in POSIX2008 mode if included from locale.h.
+ */
+#ifndef _XLOCALE_LOCALE1_H
+#define _XLOCALE_LOCALE1_H
+
+size_t strftime_l(char * __restrict, size_t, const char * __restrict,
+    const struct tm * __restrict, locale_t);
+
+#endif /* _XLOCALE_LOCALE1_H */
+
+#ifdef _XLOCALE_H_
+#ifndef _XLOCALE_LOCALE2_H
+#define _XLOCALE_LOCALE2_H
+
+char *strptime_l(const char * __restrict, const char * __restrict,
+           struct tm * __restrict, locale_t);
+
+#endif /* _XLOCALE_LOCALE2_H */
+#endif /* _XLOCALE_H_ */
Index: xlocale/_uchar.h
===================================================================
RCS file: xlocale/_uchar.h
diff -N xlocale/_uchar.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_uchar.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,45 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2013 Ed Schouten <[hidden email]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+#ifndef _XLOCALE_UCHAR_H_
+#define _XLOCALE_UCHAR_H_
+
+size_t c16rtomb_l(char * __restrict, char16_t, mbstate_t * __restrict,
+    locale_t);
+size_t c32rtomb_l(char * __restrict, char32_t, mbstate_t * __restrict,
+    locale_t);
+size_t mbrtoc16_l(char16_t * __restrict, const char * __restrict, size_t,
+    mbstate_t * __restrict, locale_t);
+size_t mbrtoc32_l(char32_t * __restrict, const char * __restrict, size_t,
+    mbstate_t * __restrict, locale_t);
+
+#endif /* _XLOCALE_UCHAR_H_ */
Index: xlocale/_wchar.h
===================================================================
RCS file: xlocale/_wchar.h
diff -N xlocale/_wchar.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ xlocale/_wchar.h 15 Oct 2013 12:51:53 -0000
@@ -0,0 +1,132 @@
+/* $OpenBSD$ */
+/*-
+ * Copyright (c) 2011, 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct _xlocale *locale_t;
+#endif
+
+#ifndef _XLOCALE_WCHAR1_H
+#define _XLOCALE_WCHAR1_H
+int wcscasecmp_l(const wchar_t *, const wchar_t *,
+   locale_t);
+int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t,
+   locale_t);
+int wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
+size_t wcsxfrm_l(wchar_t * __restrict,
+   const wchar_t * __restrict, size_t, locale_t);
+
+#endif /* _XLOCALE_WCHAR1_H */
+
+/*
+ * Only declare the non-POSIX functions if we're included from xlocale.h.
+ */
+
+#ifdef _XLOCALE_H_
+#ifndef _XLOCALE_WCHAR2_H
+#define _XLOCALE_WCHAR2_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);
+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);
+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);
+size_t wcsnrtombs_l(char * __restrict,
+    const wchar_t ** __restrict, size_t, size_t,
+    mbstate_t * __restrict, locale_t);
+
+#endif /* _XLOCALE_WCHAR_H */
+#endif /* _XLOCALE_H_ */

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Martin Pelikan
> > - port xlocale(3) from FreeBSD -- this is what this patch does
> >
> Second part (include/ headers) follows.

Apologies, I left one bit out.  Here it is.
--
Martin Pelikan


Index: locale.h
===================================================================
RCS file: /cvs/src/include/locale.h,v
retrieving revision 1.8
diff -u -p -r1.8 locale.h
--- locale.h 3 Jul 2011 18:51:01 -0000 1.8
+++ locale.h 15 Oct 2013 19:21:31 -0000
@@ -54,6 +54,12 @@ struct lconv {
  char n_sep_by_space;
  char p_sign_posn;
  char n_sign_posn;
+ char int_p_cs_precedes;
+ char int_n_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
 };
 
 #ifndef NULL

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Philip Guenther-2
On Tue, 15 Oct 2013, Martin Pelikan wrote:
> Apologies, I left one bit out.  Here it is.
...

> --- locale.h 3 Jul 2011 18:51:01 -0000 1.8
> +++ locale.h 15 Oct 2013 19:21:31 -0000
> @@ -54,6 +54,12 @@ struct lconv {
>   char n_sep_by_space;
>   char p_sign_posn;
>   char n_sign_posn;
> + char int_p_cs_precedes;
> + char int_n_cs_precedes;
> + char int_p_sep_by_space;
> + char int_n_sep_by_space;
> + char int_p_sign_posn;
> + char int_n_sign_posn;
>  };

No chunk for libc/locale/localeconv.c to actually set those?  They'll also
need a manpage blurb.  With those, this tiny chunk seems basically
harmless.


Philip

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Philip Guenther-2
In reply to this post by Martin Pelikan
On Tue, 15 Oct 2013, Martin Pelikan wrote:
> my laptop now has libcxx working (most of the tests pass, but I haven't
> checked what is missing from the C++ runtime).  The steps required are:
>
> - port xlocale(3) from FreeBSD -- this is what this patch does

Interesting: this goes beyond POSIX.2008 in many places.  strtold_l()?  
This stuff required for the implementation of the C++11 standard library?  
Or just general random programs?  Should be in the implementation
namespace either way, with weak aliases in the latter case.


> - use ld(1) from binutils-2.17 to avoid linker errors (for some reason it
>   links symbols between first two object files and discards them for the
>   rest of the command line)

Can you describe the specific case where this happens?  Part of linking
something against libcxxrt/libcxx?


> Obviously, our locale support still sucks, this patch is mostly
> providing the API for filling the blanks later.

How much did the ramdisks grow by when you built release with this?  
Having just freed up a bunch of space on the ramdisks, I'll be pissed if
we squander it all immediately.



> @@ -106,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;

With threads supported, NO_LOCALE_CACHE has to be defined, no?


> Index: locale/___runetype_mb.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/locale/___runetype_mb.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 ___runetype_mb.c
> --- locale/___runetype_mb.c 5 Dec 2012 23:20:00 -0000 1.2
> +++ locale/___runetype_mb.c 15 Oct 2013 12:42:22 -0000
> @@ -66,3 +66,4 @@ ___runetype_mb(wint_t c)
>  
>   return (0U);
>  }
> +

Heh.


Philip Guenther

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Philip Guenther-2
In reply to this post by Martin Pelikan
On Tue, Oct 15, 2013 at 6:40 AM, Martin Pelikan
<[hidden email]> wrote:
> Second part (include/ headers) follows.

Is this <xlocale.h> specified anywhere so that we can evaluate our compliance?


Philip Guenther

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Stefan Sperling-8
In reply to this post by Philip Guenther-2
On Sat, Oct 19, 2013 at 09:26:47PM -0700, Philip Guenther wrote:
> On Tue, 15 Oct 2013, Martin Pelikan wrote:
> > Obviously, our locale support still sucks, this patch is mostly
> > providing the API for filling the blanks later.

Which blanks exactly? Locale features we don't have, such as collation?

Locale support sucks because most base applications don't make use of it.
Adding more stuff to libc won't fix that.

> How much did the ramdisks grow by when you built release with this?  
> Having just freed up a bunch of space on the ramdisks, I'll be pissed if
> we squander it all immediately.

The only locale code that belongs on the ramdisks is in
/usr/src/distrib/special/libstubs/{mbrtowc_sb.c,setlocale}.c.
These are required for vfprintf(). Anything else should not
be built into the ramdisk to avoid pulling in citrus as a dependency.

I'm not very excited about xlocale. If the only goal here is an API
shim to compile a C++ library, can't we put the shim somewhere else
than libc? Like the misc/libutf8 port we used to have?

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Martin Pelikan
> > > Obviously, our locale support still sucks, this patch is mostly
> > > providing the API for filling the blanks later.
>
> Which blanks exactly? Locale features we don't have, such as collation?

Yes.  The features why for example PostgreSQL won't sort tables
correctly, which if you live in a country with weird characters in their
language is... quite unfortunate.

I was planning on bringing specifically LC_COLLATE support for a long
time, but it's quite a lot of work. (and testing, and bugfixing with
languages I don't even know existed)

> > How much did the ramdisks grow by when you built release with this?  
> > Having just freed up a bunch of space on the ramdisks, I'll be pissed if
> > we squander it all immediately.

No objections against #ifndef SMALL_KERNEL-ing the big bits.

> I'm not very excited about xlocale. If the only goal here is an API
> shim to compile a C++ library, can't we put the shim somewhere else
> than libc? Like the misc/libutf8 port we used to have?

Thought about it too, but since apps expect to find this stuff in libc,
I went for a libc diff hoping that porters will have their lives easier.
The functions I ported were the ones ld-2.17 complained about.  I have
no idea whether that port is complete and I don't claim the diff to be
ready.  It gets the job done at the cost of being huge and probably
wrong in places, and is open for discussion.

I don't care about xlocale either.  What'd I like is to have C++11
working out of the box for the next release (Is that real?) and
hopefully collation support some time in the future.  Later in the
process I noticed there is an even smaller shim intended for Solaris as
a part of libcxx, but my thoughts were:
 - Locale has always been a pain in the ass, but something users demand.
   (or is it just me with postgresql?)
 - Sharing this stuff with FreeBSD will make our lives easier should
   anything go wrong with it.  Less work for us + satisfied customers.
 - We don't have to be complete, or even advertise it very much.  But
   stuff that is increasingly popular (like C++11) will work out of the
   box.  The ability to use modern toolchains for ports should make the
   latency-savvy desktop users happier.
 - Since a lot of operating systems have now adopted solutions (being it
   xlocale or others), I suspect libcxx maintainers won't be very happy
   about #ifdef __OpenBSD__ <remove half of the functionality>

Please correct me if the philosophy is wrong.  Or better, suggest other
ways forward :-)
--
Martin Pelikan

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Stefan Sperling-8
On Mon, Oct 21, 2013 at 12:45:58AM +0200, Martin Pelikan wrote:

> > > > Obviously, our locale support still sucks, this patch is mostly
> > > > providing the API for filling the blanks later.
> >
> > Which blanks exactly? Locale features we don't have, such as collation?
>
> Yes.  The features why for example PostgreSQL won't sort tables
> correctly, which if you live in a country with weird characters in their
> language is... quite unfortunate.
>
> I was planning on bringing specifically LC_COLLATE support for a long
> time, but it's quite a lot of work. (and testing, and bugfixing with
> languages I don't even know existed)

Indeed, doing collation properly (i.e. with Unicode, not just 8 bit
characters like FreeBSD does) really is a non-trivial effort.

It requires some expertise in linguistics and a solid understanding
of the unicode standard. You'd need to make use of something like ICU
(icu-project.org) to keep your sanity, or implement a whole lot of
that code base yourself...

> > > How much did the ramdisks grow by when you built release with this?  
> > > Having just freed up a bunch of space on the ramdisks, I'll be pissed if
> > > we squander it all immediately.
>
> No objections against #ifndef SMALL_KERNEL-ing the big bits.

This is about userland parts of the ramdisk. Locales don't affect
the kernel. Bloat in ramdisk libc is avoided by compiling API stubs
instead of the usual source files. Or some special-case #ifdef other
than SMALL_KERNEL.
 
> > I'm not very excited about xlocale. If the only goal here is an API
> > shim to compile a C++ library, can't we put the shim somewhere else
> > than libc? Like the misc/libutf8 port we used to have?
>
> Thought about it too, but since apps expect to find this stuff in libc,

Applications don't care where a symbol comes from.
Build scripts and Makefiles might expect them to be in libc and
would need to link an additional library, but that's trivial to do.

> I went for a libc diff hoping that porters will have their lives easier.
> The functions I ported were the ones ld-2.17 complained about.  I have
> no idea whether that port is complete and I don't claim the diff to be
> ready.  It gets the job done at the cost of being huge and probably
> wrong in places, and is open for discussion.

In my opinion, if you're putting something into libc it should be
a correct and functional implementation, not an API stub that doesn't
really provide the advertised functionality. Libc is not a stash for
missing symbols that exist on other operating systems.

> I don't care about xlocale either.  What'd I like is to have C++11
> working out of the box for the next release (Is that real?) and
> hopefully collation support some time in the future.

I think you should tackle your goals (C++11, collation) in isolation.
They aren't coupled, really.

> Later in the
> process I noticed there is an even smaller shim intended for Solaris as
> a part of libcxx,

Ah. So perhaps the right approach for now is to use reuse that shim?

> but my thoughts were:
>  - Locale has always been a pain in the ass, but something users demand.
>    (or is it just me with postgresql?)

You'll have to be a bit more specific about what's wrong with the
current locale implementation and what user demands we don't serve.
Otherwise it's hard to have a productive discussion.

>  - Sharing this stuff with FreeBSD will make our lives easier should
>    anything go wrong with it.  Less work for us + satisfied customers.

The FreeBSD collation implementation only works for characters
from Latin1. It is based on code from 1995:
http://svnweb.freebsd.org/base?view=revision&revision=6485
There haven't been any functional enhancements since.
If we bother with collation I think we should try to do better.

>  - We don't have to be complete, or even advertise it very much.  But
>    stuff that is increasingly popular (like C++11) will work out of the
>    box.  The ability to use modern toolchains for ports should make the
>    latency-savvy desktop users happier.

Then again we must resist adding stubs to our base libraries to
make 3rd party stuff happy. Otherwise the quality of base will
suffer in the long term.

>  - Since a lot of operating systems have now adopted solutions (being it
>    xlocale or others), I suspect libcxx maintainers won't be very happy
>    about #ifdef __OpenBSD__ <remove half of the functionality>

So they're happy about their Solaris shim, but won't take an OpenBSD one?

> Please correct me if the philosophy is wrong.  Or better, suggest other
> ways forward :-)

Since your priorities clearly lie with C++11 and not locale support
in our libc, I think you should try to make libcxx more portable.
Going the other way of adding a proper xlocale implementation to
libc is going to be frustrating for you if it is not a goal in itself.

I would suggest to implement a small and non-OS-specific stub for
libcxx that they can use on any OS lacking xlocale support.
Replace/enhance the existing shim for Solaris as part of this effort.
Work with the libcxx team to integrate your changes there.

If they tell you that they won't run on a non-xlocale OS that isn't
Solaris, implement the shim anyway and add it to our ports tree.

The shim is going to be a lot less work, and doesn't preclude an
implentation inside libc at a later stage.

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Martin Pelikan
> Indeed, doing collation properly (i.e. with Unicode, not just 8 bit
> characters like FreeBSD does) really is a non-trivial effort.
>
> It requires some expertise in linguistics and a solid understanding
> of the unicode standard. You'd need to make use of something like ICU
> (icu-project.org) to keep your sanity, or implement a whole lot of
> that code base yourself...

Unfortunately, that requires support in the 3rd party software itself.


> Applications don't care where a symbol comes from.
> Build scripts and Makefiles might expect them to be in libc and
> would need to link an additional library, but that's trivial to do.

For all such ports?  Ok then :-)

> I think you should tackle your goals (C++11, collation) in isolation.
> They aren't coupled, really.

Yes, but xlocale seemed like a thing they have in common.

> If we bother with collation I think we should try to do better.

Yes, but that I think is only applying a correct library.  As you've
said earlier, getting this right is really hard.

> I would suggest to implement a small and non-OS-specific stub for
> libcxx that they can use on any OS lacking xlocale support.
> Replace/enhance the existing shim for Solaris as part of this effort.
> Work with the libcxx team to integrate your changes there.
>
> If they tell you that they won't run on a non-xlocale OS that isn't
> Solaris, implement the shim anyway and add it to our ports tree.
>
> The shim is going to be a lot less work, and doesn't preclude an
> implentation inside libc at a later stage.

Thanks for showing the right direction.  I'll look into it as soon as
I have more time; at least I know what is needed and how big is it.
--
Martin Pelikan

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Stefan Sperling-8
On Mon, Oct 21, 2013 at 02:14:32PM +0200, Martin Pelikan wrote:
> > Applications don't care where a symbol comes from.
> > Build scripts and Makefiles might expect them to be in libc and
> > would need to link an additional library, but that's trivial to do.
>
> For all such ports?  Ok then :-)

How many ports do you expect will require xlocale?
 

> > I would suggest to implement a small and non-OS-specific stub for
> > libcxx that they can use on any OS lacking xlocale support.
> > Replace/enhance the existing shim for Solaris as part of this effort.
> > Work with the libcxx team to integrate your changes there.
> >
> > If they tell you that they won't run on a non-xlocale OS that isn't
> > Solaris, implement the shim anyway and add it to our ports tree.
> >
> > The shim is going to be a lot less work, and doesn't preclude an
> > implentation inside libc at a later stage.
>
> Thanks for showing the right direction.  I'll look into it as soon as
> I have more time; at least I know what is needed and how big is it.

If xlocale is needed beyond libcxx, take a look at the misc/libutf8
port in the CVS Attic. Perhaps a port like that could serve as an
API shim for xlocale until libc support for xlocale arrives.

If you'd still rather do this in libc itself, e.g. because a simple
shim won't provide enough functionality to make libcxx work, or because
you really need it coupled up with libc locale internals, don't just
copy files over from FreeBSD and make us review it all. Figure out
what the steps are to get us from here to there and let us review
each step.

I think starting with just the locale_t data type and related functions
(duplocale() etc.) on this page would be a good first step:
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html
This interface extension is small enough to be added in one diff, I think.
I don't care if you base the implementation on FreeBSD or write your own,
as long as the diff is concise and adds nicely on top what we've already got.
All the clutter from new *_l() convenience functions can come later.

This page provides a high-level overview of xlocale interfaces, BTW:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
That's quite a lot. I wouldn't want to add all that in one chunk.

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

vtamara
In reply to this post by Martin Pelikan
On Mon, Oct 21, 2013 at 02:14:32PM +0200, Martin Pelikan wrote:
> > Indeed, doing collation properly (i.e. with Unicode, not just 8 bit
> > characters like FreeBSD does) really is a non-trivial effort.
> >
> > It requires some expertise in linguistics and a solid understanding
> > of the unicode standard. You'd need to make use of something like ICU
> > (icu-project.org) to keep your sanity, or implement a whole lot of
> > that code base yourself...
>
> Unfortunately, that requires support in the 3rd party software itself.

Anyway, I updated to current the 8 bit collation support from FreeBSD I had
sent in in March and that was reviewed by Stephan in the previous Hackathon:
https://github.com/pasosdeJesus/adJ/blob/OBSD_CURRENT/arboldes/usr/src/03-cotejacion.patch

Also updated the xlocale patch, also based in FreeBSD that I sent in
February:
https://github.com/pasosdeJesus/adJ/blob/OBSD_CURRENT/arboldes/usr/src/04-xlocale-wchar.patch
https://github.com/pasosdeJesus/adJ/blob/OBSD_CURRENT/arboldes/usr/src/05-xlocale-ctype.patch
https://github.com/pasosdeJesus/adJ/blob/OBSD_CURRENT/arboldes/usr/src/06-xlocale-str.patch

And also updated patch for regress/lib/libc/locale/check_isw sent in
March:
https://github.com/pasosdeJesus/adJ/blob/OBSD_CURRENT/arboldes/usr/src/01-check_isw.patch

I want to compare in detail with the implementation that Martin sent,
few differences I see:

* I changed the sources in order to avoid runetype.h in /usr/include
* Martin implemented some pieces that I have not (e.g strtorx_l), I want to
  merge in what I have

> > If we bother with collation I think we should try to do better.

I agree full Unicode support is desirable, but IMHO having 8 bits collation
is better than nothing (for example withouth it spanish speakers have to
see ñ, á and other special symbols at the end of sorted results in
programs that support collations like PostgreSQL).

> > The shim is going to be a lot less work, and doesn't preclude an
> > implentation inside libc at a later stage.
>
> Thanks for showing the right direction.  I'll look into it as soon as
> I have more time; at least I know what is needed and how big is it.

Since xlocale is part of POSIX shouldn't we try to include that faster
in libc?

I think xlocale additions to POSIX were included in the Open Group Technical
Standard, 2006, Extended API Set Part 4.  That is what I understand
of the documentation of xlocale functions like strcoll_l, see bottom of:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcoll.html

However if Martin prefers to make a new library for this, hope the patches I
sent can be useful.

--
Dios, gracias por tu amor infinito.
--  
  Vladimir Támara Patiño.  http://vtamara.pasosdeJesus.org/
  http://www.pasosdejesus.org/dominio_publico_colombia.html

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

Stefan Sperling-8
On Mon, Oct 21, 2013 at 09:05:04AM -0500, Vladimir Támara Patiño wrote:
> I agree full Unicode support is desirable, but IMHO having 8 bits
> collation is better than nothing (for example withouth it spanish
> speakers have to
> see ñ, á and other special symbols at the end of sorted results in
> programs that support collations like PostgreSQL).

So we add 8 bit support, and then what?

Whoever would want to do it properly would have to throw the
8 bit stuff out and start all over again.

Reply | Threaded
Open this post in threaded view
|

Re: partial xlocale(3) port from FreeBSD

vtamara
In reply to this post by Martin Pelikan
Commenting differences I find between your patch and the one I sent

On Tue, Oct 15, 2013 at 03:32:29PM +0200, Martin Pelikan wrote:

> Index: Makefile
> +CFLAGS+=-D__NO_TLS
I had removed parts that used TLS, but this is better.

> Index: arch/amd64/gdtoa/strtold.c
I didn't have this  (neither for other architectures, however I
concentrate in amd64).

> Index: citrus/citrus_none.c
...

> +int
> +_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
> +{
> + l->__mbrtowc = _citrus_none_ctype_mbrtowc;
> + l->__mbsinit = _citrus_none_ctype_mbsinit;
> + l->__mbsnrtowcs = _citrus_none_ctype_mbsnrtowcs;
> + l->__wcrtomb = _citrus_none_ctype_wcrtomb;
> + l->__wcsnrtombs = _citrus_none_ctype_wcsnrtombs;
> + l->runes = rl;
> + l->__mb_cur_max = 1;
> + l->__mb_sb_limit = 256;
> + return (0);
> +}
...
> +struct xlocale_ctype __xlocale_global_ctype = {
...
> +struct xlocale_ctype __xlocale_C_ctype = {

I put that in locale/none.c

> +struct xlocale_collate {

I put in collate.h

> +struct xlocale_collate __xlocale_global_collate = {
> + {{0}, "C"}, 1, 0
> +};
> +struct xlocale_collate __xlocale_C_collate = {
> + {{0}, "C"}, 1, 0
> +};

In collate.c  (I had forgotten {{0}, "C"}, thanks, fixed!)

> Index: gdtoa/gdtoaimp.h
> +typedef struct _xlocale *locale_t;

Wouldn't be better #include <xlocale.h> ?

> Index: gdtoa/strtod.c
> Index: gdtoa/strtodg.c
> Index: gdtoa/strtof.c
> Index: gdtoa/strtorQ.c
> Index: gdtoa/strtord.c
> Index: gdtoa/strtorx.c

I didn't have these

> Index: locale/Makefile.inc
> - _wctrans.c wcsxfrm.c
> + _wctrans.c wcsxfrm.c xlocale.c ctype.c runetype.c tolower.c toupper.c
I added
 collate.c nextwctype.c none.c xlocale.c

>  
>  MLINKS+=setlocale.3 localeconv.3 \
>   iswalnum.3 iswalpha.3 \
>   iswalnum.3 iswblank.3 \

Here I added:

iswalnum.3 iswalpha.3 \
mblen.3 mblen_l.3\
mbrtowc.3 mbrtowc_l.3\
mbsinit.3 mbsinit_l.3\
mbstowcs.3 mbstowcs_l.3\
mbtowc.3 mbtowc_l.3\
setlocale.3 localeconv.3 \
towlower.3 towlower_l.3 \
towlower.3 towupper_l.3
wcstombs.3 wcstombs_l.3 \
wctob.3 wctob_l.3 \
wctomb.3 wctomb_l.3 \
mbsrtowcs.3 mbsnrtowcs_l.3 \
mbsrtowcs.3 mbsrtowcs_l.3 \
wcsrtombs.3 wcsnrtombs.3 \
wcsrtombs.3 wcsrtombs_l.3 \
wcsrtombs.3 wcsnrtombs_l.3

> Index: locale/__mb_cur_max.c

>  #include <sys/types.h>
>  #include <limits.h>
> +#include <wchar.h>
> +#include "mblocal.h"

Not needed

> Index: locale/btowc.c

...

>  wint_t
> -btowc(int c)
> +btowc_l(int c, locale_t l)
>  {
> - mbstate_t mbs;
> + static const mbstate_t initial;
> + mbstate_t mbs = initial;
>   char cc;
>   wchar_t wc;
> + FIX_LOCALE(l);
>  
>   if (c == EOF)
>   return (WEOF);
> @@ -44,9 +51,13 @@ btowc(int c)
>   * which detects error return values as well as "impossible" byte
>   * counts.
>   */
> - memset(&mbs, 0, sizeof(mbs));
>   cc = (char)c;
> - if (mbrtowc(&wc, &cc, 1, &mbs) > 1)
> + if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
>   return (WEOF);
>   return (wc);
> +}

I'm using

wint_t
btowc_l(int c, locale_t loc)
{
        mbstate_t mbs;
        char cc;
        wchar_t wc;

        if (c == EOF)
                return (WEOF);
        /*
         * We expect mbrtowc() to return 0 or 1, hence the check for n > 1
         * which detects error return values as well as "impossible" byte
         * counts.
         */
        memset(&mbs, 0, sizeof(mbs));
        cc = (char)c;
        if (mbrtowc_l(&wc, &cc, 1, &mbs, loc) > 1)
                return (WEOF);
        return (wc);
}

Other functions like mbrlen_l, mbtowc_l I implemented in similar way.

> Index: locale/localeconv.c
I didn't have this

> Index: locale/mblocal.h
...
> +#include <runetype.h>

Here  (an wherever runetype.h is included) I have
#include "runetype.h"

> Index: locale/multibyte_citrus.c
>  size_t
> -mbrtowc(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
> +mbrtowc_l(wchar_t *pwc, const char *s, size_t n,
> +    mbstate_t *ps, locale_t locale)
>  {
>   static mbstate_t mbs;
>   struct _citrus_ctype_rec *cc;
>  
> + /* XXX xlocale not yet implemented */
> + (void) locale;
>   if (ps == NULL)
>   ps = &mbs;
>   cc = _CurrentRuneLocale->rl_citrus_ctype;
>   return (*cc->cc_ops->co_mbrtowc)(pwc, s, n, _ps_to_private(ps));
>  }

This one I implemented:

size_t
mbrtowc_l(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps, locale_t l)
{
      static mbstate_t mbs;
      struct _citrus_ctype_rec *cc;

      if (ps == NULL)
             ps = &mbs;
      FIX_LOCALE(l);
      _RuneLocale *rl = XLOCALE_CTYPE(l)->runes;
      cc = rl->rl_citrus_ctype;
      return (*cc->cc_ops->co_mbrtowc)(pwc, s, n, _ps_to_private(ps));  
}


>  size_t
> -mbsrtowcs(wchar_t *dst, const char **src, size_t len, mbstate_t *ps)
> +mbsrtowcs_l(wchar_t *dst, const char **src, size_t len,
> +    mbstate_t *ps, locale_t locale)
>  {
>   static mbstate_t mbs;
>  
> + /* XXX xlocale not yet implemented */
> + (void) locale;
>   if (ps == NULL)
>   ps = &mbs;
>   return (mbsnrtowcs(dst, src, SIZE_MAX, len, ps));
>  }

This one and next:

size_t
mbsrtowcs_l(wchar_t *dst, const char **src, size_t len, mbstate_t *ps,
    locale_t l)
{
        static mbstate_t mbs;

        if (ps == NULL)
                ps = &mbs;
        return (mbsnrtowcs_l(dst, src, SIZE_MAX, len, ps, l));
}


size_t
mbsnrtowcs_l(wchar_t *dst, const char **src, size_t nmc, size_t len,
    mbstate_t *ps, locale_t l)
{
        static mbstate_t mbs;
        struct _citrus_ctype_rec *cc;
 
        if (ps == NULL)
                ps = &mbs;
        FIX_LOCALE(l);
        _RuneLocale *rl = XLOCALE_CTYPE(l)->runes;
        cc = rl->rl_citrus_ctype;
        return (*cc->cc_ops->co_mbsnrtowcs)(dst, src, nmc, len,
            _ps_to_private(ps));
}

 

>  size_t
> -wcrtomb(char *s, wchar_t wc, mbstate_t *ps)
> +wcrtomb_l(char *s, wchar_t wc, mbstate_t *ps, locale_t locale)
>  {
>   static mbstate_t mbs;
>   struct _citrus_ctype_rec *cc;
>  
> + /* XXX xlocale not yet implemented */
> + (void) locale;
>   if (ps == NULL)
>   ps = &mbs;
>   cc = _CurrentRuneLocale->rl_citrus_ctype;
>   return (*cc->cc_ops->co_wcrtomb)(s, wc, _ps_to_private(ps));
>  }

Here

size_t
wcrtomb_l(char *s, wchar_t wc, mbstate_t *ps, locale_t l)
{
        static mbstate_t mbs;
        struct _citrus_ctype_rec *cc;

        if (ps == NULL)
                ps = &mbs;
        FIX_LOCALE(l);
        _RuneLocale *rl = XLOCALE_CTYPE(l)->runes;
        cc = rl->rl_citrus_ctype;
        return (*cc->cc_ops->co_wcrtomb)(s, wc, _ps_to_private(ps));
}

In similar way implemented others.

> Index: locale/rune.h

> -extern _RuneLocale _DefaultRuneLocale;
> -extern _RuneLocale *_CurrentRuneLocale;
> +extern const _RuneLocale _DefaultRuneLocale;
> +extern const _RuneLocale *_CurrentRuneLocale;

Ok. I added const

> Index: locale/rune_local.h
> +#include "runetype.h"

I don't need it

> Index: locale/runetable.c
> +#include "mblocal.h"

Don't need

> -_RuneLocale _DefaultRuneLocale = {
> +const _RuneLocale _DefaultRuneLocale = {

I added const

> -_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
> +const _RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;

I added const

> +_RuneLocale *
> +__runes_for_locale(locale_t locale, int *mb_sb_limit)
I don't use this one

> Index: locale/runetype.c

I don't need this file

> Index: locale/runetype.h

You moved this one to /usr/include I didn't, but made this change:

@@ -40,7 +40,10 @@
 #include <sys/types.h>
 #include "ctype_private.h"
 
+#ifndef _RUNE_T_DEFINED
+#define _RUNE_T_DEFINED
 typedef uint32_t       rune_t;
+#endif
 typedef uint64_t       __runepad_t;


> Index: locale/setlocale.h

I don't use this, but

> +#define ENCODING_LEN 31
> +#define CATEGORY_LEN 11

I added to xlocale_private.h

> Index: locale/tolower.c

I don't use this

> Index: locale/toupper.c

Neither this

> Index: locale/wcscoll.c
> Index: locale/wcsxfrm.c

The one you sent are fine without collation support.

> Index: locale/wctob.c

> + static const mbstate_t initial;
> + mbstate_t mbs = initial;
>   char buf[MB_LEN_MAX];
> + FIX_LOCALE(locale);
>  
> - memset(&mbs, 0, sizeof(mbs));
> - if (c == WEOF || wcrtomb(buf, c, &mbs) != 1)
> + if (c == WEOF /* || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1 */)

I do
        mbstate_t mbs;
        char buf[MB_LEN_MAX];

        memset(&mbs, 0, sizeof(mbs));
              if (c == WEOF || wcrtomb_l(buf, c, &mbs, loc) != 1)
                            return (EOF);
        return ((unsigned char)*buf);

> Index: locale/xlocale.c
> +#if 0
> + &__xlocale_global_collate,
> + &__xlocale_global_ctype,
> + &__xlocale_global_monetary,
> + &__xlocale_global_numeric,
> + &__xlocale_global_time,
> + &__xlocale_global_messages
> +#endif

I have

                &__xlocale_global_collate,
                &__xlocale_global_ctype, 0, 0, 0, 0

...

> +void *__collate_load(const char *a, locale_t b) { return NULL; }

This one I have in collate.c (not NULL)

> +void *__ctype_load(const char *a, locale_t b) { return NULL; }

Instead of this I have in setrunelocale.c:

void
destruct_ctype(void *t)
{
        /* We don't free runes, because they are in the cache starting at
         * localerunes_head */
        if (t != NULL) {
                free(t);
        }
}


/** Based on __collate_load */
void *
__ctype_load(const char *locname, locale_t unused)
{
        struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);

        l->header.header.destructor = destruct_ctype;
        if (xlocale_setrunelocale(l, locname))
        {
                xlocale_release(l);
                return NULL;
        }
        return l;
}

> +void *__monetary_load(const char *a, locale_t b) { return NULL; }
> +void *__numeric_load(const char *a, locale_t b) { return NULL; }
> +void *__time_load(const char *a, locale_t b) { return NULL; }
> +void *__messages_load(const char *a, locale_t b) { return NULL; }

These I had in setlocale.c, but better I moved to xlocale.c

> +static pthread_key_t locale_info_key;

This one I commented

> +#else
> + __has_thread_locale = 1;

Here I added:

        fake_tls = 1;

> +
> +static pthread_once_t once_control = PTHREAD_ONCE_INIT;
> +/* Single threaded pthread_once(3).  libc won't have to -lpthread. */
> +static int
> +_once(pthread_once_t *o, void (*init_routine)(void))
> +{
> + if (o->state == PTHREAD_DONE_INIT)
> + return (0);
> + init_routine();
> + o->state = PTHREAD_DONE_INIT;
> + return (0);
> +}

I added this.   Thank you (what license does your patch have?).  

> + // XXX FreeBSD uses &__xlocale_global_locale
> + return (l ? l : &__xlocale_C_locale);

I also used &__xlocale_global_localeo

> Index: locale/xlocale_private.h
> +/**
> + * 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 = obj->retain_count--;
> + // XXX long count = atomic_fetchadd_long(&(obj->retain_count), -1) - 1;

Here I have
        obj->retain_count--;
        long count = obj->retain_count;

That I think is consistent with the implementation of atomic_fetchadd_long:
http://fxr.watson.org/fxr/source/ia64/include/atomic.h?im=excerpts#L379

> Index: stdio/asprintf.c
> Index: stdio/fscanf.c
> Index: stdio/local.h
> Index: stdio/scanf.c
> Index: stdio/snprintf.c
> Index: stdio/sprintf.c
> Index: stdio/sscanf.c
> Index: stdio/vasprintf.c
> Index: stdio/vdprintf.c
> Index: stdio/vfprintf.c
> Index: stdio/vfscanf.c
> Index: stdio/vsnprintf.c
> Index: stdio/vsprintf.c
> Index: stdio/vsscanf.c
> Index: stdlib/strtoimax.c
> Index: stdlib/strtol.c
> Index: stdlib/strtoll.c
> Index: stdlib/strtoul.c
> Index: stdlib/strtoull.c
> Index: stdlib/strtoumax.c

I didn't have these.

> Index: string/wcscasecmp.c
I have wcsncasecmp_l


> Index: string/wcscmp.c
> Index: string/wcsncmp.c
> Index: string/wmemcmp.c

I didn't touch these

> Index: time/strftime.c

I didn't have this one

Thank you, I updated my patches, and thanked you in commit message.
https://github.com/pasosdeJesus/adJ/commit/a5d66cd5bf2b814287cfc1bdc68e707cddf5ef17

I will be checking in detail new files you sent that I didn't have and
will try to add to my patches.


--
Dios, gracias por tu amor infinito.
--  
  Vladimir Támara Patiño.  http://vtamara.pasosdeJesus.org/
  http://www.pasosdejesus.org/dominio_publico_colombia.html