Hi,

In the process of upgrading the third-party components required to build NetSurf, it became apparent that OpenSSL 3 makes use of the extended locale APIs introduced in POSIX.1-2008. While it only uses a subset of these APIs, I've taken the opportunity to implement the majority of them in UnixLib.

Items outstanding (for the standard APIs -- I've ignored the GNU extensions entirely) are:

1. strftime_l() has not been implemented.
2. The uselocale() implementation does not conform to the specification.
   It should be setting a thread-local locale (and, further, the global
   variable it updates is entirely ignored by all the APIs that would
   ordinarily use the global locale -- these would need updating to make
   use of the thread-local locale, if it exists).

Additionally, the extended-locale ctype functions (i.e. isalpha_l() and friends) are not in any way optimised like their non-extended counterparts. Doing so will require making parts of the struct pointed to by a locale_t public (which is what glibc does, at least).

Note also that the wchar interfaces are implemented to approximately the same level as the pre-existing UnixLib support (which is to say; not extensively and with plenty of stub implementations that will abort).

Please find the patch attached.

Ta,


J.
Index: gcc4/recipe/files/gcc/libunixlib/Makefile.am
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/Makefile.am	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/Makefile.am	(working copy)
@@ -583,11 +583,11 @@
 else
 locale_src = \
 	locale/localeconv.c \
+	locale/newlocale.c \
 	locale/nl_langinfo.c \
 	locale/setlocale.c \
 	locale/strcoll.c \
-	locale/strxfrm.c \
-	locale/territory.c
+	locale/strxfrm.c
 endif
 locale_src += \
 	locale/iconv.c
@@ -1312,6 +1312,7 @@
 	bits/in.h \
 	bits/libc-lock.h \
 	bits/locale.h \
+	bits/locale_t.h \
 	bits/mathcalls.h \
 	bits/mathdef.h \
 	bits/mathinline.h \
Index: gcc4/recipe/files/gcc/libunixlib/ctype/ctypetable.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/ctypetable.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/ctypetable.c	(working copy)
@@ -10,36 +10,35 @@
 #include <internal/os.h>
 #include <internal/unix.h>
 
-/* Note the offset 1 and depth 257 instead of 0 and 256: ISO C says we must
-   support EOF.  */
-static unsigned char ctype[257];
-const unsigned char * const __ctype = &ctype[1];
+/* Global containing current locale settings. */
+struct _locale __locale_global;
+/* Offset 1 as the first entry is reserved for EOF.  */
+const unsigned char * const __ctype = &__locale_global.ctype[1];
+const short * const __ctype_upper = &__locale_global.ctype_upper[1];
+const short * const __ctype_lower = &__locale_global.ctype_lower[1];
 
-static short ctype_upper[257];
-const short * const __ctype_upper = &ctype_upper[1];
-
-static short ctype_lower[257];
-const short * const __ctype_lower = &ctype_lower[1];
-
 void
-__build_ctype_tables (int territory)
+__build_ctype_tables (locale_t locobj, int territory)
 {
   PTHREAD_UNSAFE
 
   if (territory == -2)
     {
-      /* Initialise the array. This is only done by __unixinit().  */
+      /* Initialise the array. This is only done by __unixinit()/newlocale().  */
       territory = -1;
-      for (int x = 0; x <= LC_ALL; x++)
-        __locale_territory[x] = -1;
+      for (int x = 0; x < LC_ALL; x++)
+        locobj->locale_territory[x] = -1;
+      __localeconv_lconv_init(&locobj->lc);
+      locobj->lc_needs_refresh = 1;
     }
 
   /* Initialise ctype_upper/ctype_lower tables.  */
   for (int x = 0; x < 257; x++)
     {
-      /* In the C/POSIX locate, tolower(top bit set char)
+      /* In the C/POSIX locale, tolower(top bit set char)
 	 should return the character unchanged.  */
-      ctype_lower[x] = ctype_upper[x] = x - 1;
+      locobj->ctype_lower[x] = locobj->ctype_upper[x] = x - 1;
+      locobj->ctype[x] = 0;
     }
 
   int regs[10];
@@ -61,7 +60,7 @@
 	  for (int offset = 1; bits; bits = bits >> 1, offset += 1)
 	    {
 	      if (bits & 1)
-		ctype[pos + offset] |= 1 << code;
+		locobj->ctype[pos + offset] |= 1 << code;
 	    }
 	  pos += 32;
 	}
@@ -80,7 +79,7 @@
   int y = (territory == -1) ? 128 : 256;
   for (int x = 1; x <= y; x++)
     {
-      ctype_lower[x] = (short)*p++;
-      ctype_upper[x] = (short)*q++;
+      locobj->ctype_lower[x] = (short)*p++;
+      locobj->ctype_upper[x] = (short)*q++;
     }
 }
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isalnum.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isalnum.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isalnum.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isalnum) (int c)
@@ -10,3 +11,8 @@
   return isalnum (c);
 }
 
+int
+isalnum_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & (___ctype_alpha | ___ctype_digit));
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isalpha.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isalpha.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isalpha.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isalpha) (int c)
@@ -10,3 +11,8 @@
   return isalpha (c);
 }
 
+int
+isalpha_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_alpha);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isascii.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isascii.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isascii.c	(working copy)
@@ -10,3 +10,9 @@
   return isascii (c);
 }
 
+int
+isascii_l (int c, locale_t locobj)
+{
+  (void) locobj;
+  return isascii (c);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isblank.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isblank.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isblank.c	(working copy)
@@ -9,3 +9,10 @@
 {
   return isblank (c);
 }
+
+int
+isblank_l (int c, locale_t locobj)
+{
+  (void) locobj;
+  return isblank (c);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/iscntrl.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/iscntrl.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/iscntrl.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (iscntrl) (int c)
@@ -10,3 +11,8 @@
   return iscntrl (c);
 }
 
+int
+iscntrl_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_ctrl);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isdigit.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isdigit.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isdigit.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isdigit) (int c)
@@ -10,3 +11,8 @@
   return isdigit (c);
 }
 
+int
+isdigit_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_digit);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isgraph.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isgraph.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isgraph.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isgraph) (int c)
@@ -10,3 +11,8 @@
   return isgraph (c);
 }
 
+int
+isgraph_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ~(___ctype_white | ___ctype_ctrl));
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/islower.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/islower.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/islower.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (islower) (int c)
@@ -10,3 +11,8 @@
   return islower (c);
 }
 
+int
+islower_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_lower);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isprint.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isprint.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isprint.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isprint) (int c)
@@ -10,3 +11,10 @@
   return isprint (c);
 }
 
+int
+isprint_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] &
+          (___ctype_upper | ___ctype_lower | ___ctype_digit | ___ctype_punc |
+           ___ctype_white)) && !((&locobj->ctype[1])[c] & ___ctype_ctrl);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/ispunct.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/ispunct.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/ispunct.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (ispunct) (int c)
@@ -10,3 +11,8 @@
   return ispunct (c);
 }
 
+int
+ispunct_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_punc);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isspace.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isspace.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isspace.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isspace) (int c)
@@ -10,3 +11,8 @@
   return isspace (c);
 }
 
+int
+isspace_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_white);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isupper.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isupper.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isupper.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isupper) (int c)
@@ -10,3 +11,8 @@
   return isupper (c);
 }
 
+int
+isupper_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_upper);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/isxdigit.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/isxdigit.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/isxdigit.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (isxdigit) (int c)
@@ -10,3 +11,8 @@
   return isxdigit (c);
 }
 
+int
+isxdigit_l (int c, locale_t locobj)
+{
+  return ((&locobj->ctype[1])[c] & ___ctype_xdigit);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/toascii.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/toascii.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/toascii.c	(working copy)
@@ -10,3 +10,9 @@
   return toascii (c);
 }
 
+int
+toascii_l (int c, locale_t locobj)
+{
+  (void) locobj;
+  return toascii (c);
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/tolower.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/tolower.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/tolower.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (tolower) (int c)
@@ -10,3 +11,8 @@
   return tolower (c);
 }
 
+int
+tolower_l (int c, locale_t locobj)
+{
+  return (&locobj->ctype_lower[1])[c];
+}
Index: gcc4/recipe/files/gcc/libunixlib/ctype/toupper.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/ctype/toupper.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/ctype/toupper.c	(working copy)
@@ -3,6 +3,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 
 int
 (toupper) (int c)
@@ -10,3 +11,8 @@
   return toupper (c);
 }
 
+int
+toupper_l (int c, locale_t locobj)
+{
+  return (&locobj->ctype_upper[1])[c];
+}
Index: gcc4/recipe/files/gcc/libunixlib/incl-local/locale.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/incl-local/locale.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/incl-local/locale.h	(working copy)
@@ -13,15 +13,36 @@
 
 #ifndef __TARGET_SCL__
 
-/* Territory number for each locale.  C locale is -1.  */
-extern int __locale_territory[LC_ALL + 1];
+struct _locale {
+  /* Map from locale category to territory number. C locale is -1. */
+  int locale_territory[LC_ALL];
 
-/* Set to 1 is setlocale has been called since the last call to
-   localeconv. localeconv uses this flag to cache the lconv structure.  */
-extern int __setlocale_called;
+  /* Character type LUTs: EOF + one entry per character
+   *
+   * EOF is defined as -1, so character entries start at offset 1.
+   */
+  short ctype_upper[257];
+  short ctype_lower[257];
+  unsigned char ctype[257];
 
-extern void __build_ctype_tables (int __territory) __THROW;
+  /* Set to 1 if the locale information has changed since the last time
+   * the lconv structure was updated. */
+  int lc_needs_refresh;
+  /* Numeric formatting information for locale */
+  struct lconv lc;
+};
 
+extern struct _locale __locale_global;
+
+extern void __build_ctype_tables (locale_t locobj, int __territory) __THROW;
+
+extern char *__setlocale_l (locale_t locobj, int __category,
+                            const char *__locale) __THROW;
+
+void __localeconv_lconv_init (struct lconv *lc);
+void __localeconv_lconv_fini (struct lconv *lc);
+void __localeconv_l (locale_t locobj);
+
 #endif
 
 __END_DECLS
Index: gcc4/recipe/files/gcc/libunixlib/include/bits/locale_t.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/bits/locale_t.h	(nonexistent)
+++ gcc4/recipe/files/gcc/libunixlib/include/bits/locale_t.h	(working copy)
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2022 UnixLib Developers
+ */
+
+#ifndef _BITS_LOCALE_T_H_
+#define _BITS_LOCALE_T_H_
+
+typedef struct _locale *locale_t;
+
+#endif
Index: gcc4/recipe/files/gcc/libunixlib/include/ctype.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/ctype.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/ctype.h	(working copy)
@@ -51,6 +51,48 @@
 extern int isblank (int __c) __THROW;
 
 #ifndef __TARGET_SCL__
+#  ifdef __USE_XOPEN2K8
+#    include <bits/locale_t.h>
+
+/* c is alphabetic or numeric.  */
+extern int isalnum_l (int __c, locale_t locobj) __THROW;
+
+/* c is alphabetic.  */
+extern int isalpha_l (int __c, locale_t locobj) __THROW;
+
+/* c is a control character.  */
+extern int iscntrl_l (int __c, locale_t locobj) __THROW;
+
+/* c is a decimal digit.  */
+extern int isdigit_l (int __c, locale_t locobj) __THROW;
+
+/* c is any printable character other than a space. */
+extern int isgraph_l (int __c, locale_t locobj) __THROW;
+
+/* c is a lower-case letter.  */
+extern int islower_l (int __c, locale_t locobj) __THROW;
+
+/* c is an upper-case letter.  */
+extern int isupper_l (int __c, locale_t locobj) __THROW;
+
+/* c is a printable character.  */
+extern int isprint_l (int __c, locale_t locobj) __THROW;
+
+/* c is a printable character other than a space or a
+   alphanumeric character.  */
+extern int ispunct_l (int __c, locale_t locobj) __THROW;
+
+/* c is a white space character e.g. space, newline, tab, linefeed,
+   return, vertical tab.  */
+extern int isspace_l (int __c, locale_t locobj) __THROW;
+
+/* c is a hex digit.  */
+extern int isxdigit_l (int __c, locale_t locobj) __THROW;
+
+/* c is tab or space.  */
+extern int isblank_l (int __c, locale_t locobj) __THROW;
+#  endif
+
 /* Characteristics. */
 extern const unsigned char * const __ctype;
 /* Lower case table.  */
@@ -108,6 +150,10 @@
 extern int toupper (int __c) __THROW;
 #ifndef __TARGET_SCL__
 #  define toupper(c) ((int) __ctype_upper[(int) (c)])
+
+#  ifdef __USE_XOPEN2K8
+extern int toupper_l (int __c, locale_t locobj) __THROW;
+#  endif
 #endif
 
 /* Convert c to lower case.  */
@@ -114,6 +160,10 @@
 extern int tolower (int __c) __THROW;
 #ifndef __TARGET_SCL__
 #  define tolower(c) ((int) __ctype_lower[(int) (c)])
+
+#  ifdef __USE_XOPEN2K8
+extern int tolower_l (int __c, locale_t locobj) __THROW;
+#  endif
 #endif
 
 #ifndef __TARGET_SCL__
@@ -135,6 +185,11 @@
 /* Is c an ASCII character.  */
 extern int isascii (int __c) __THROW;
 #    define isascii(c) ((unsigned)(c) <= 0x7f)
+
+#    ifdef __USE_XOPEN2K8
+extern int toascii_l (int __c, locale_t locobj) __THROW;
+extern int isascii_l (int __c, locale_t locobj) __THROW;
+#    endif
 #  endif
 #endif
 
Index: gcc4/recipe/files/gcc/libunixlib/include/langinfo.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/langinfo.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/langinfo.h	(working copy)
@@ -580,18 +580,12 @@
 extern char *nl_langinfo (nl_item __item) __THROW;
 
 
-#if 0
-#ifdef	__USE_GNU
-/* This interface is for the extended locale model.  See <locale.h> for
-   more information.  */
+#ifdef	__USE_XOPEN2K8
+# include <bits/locale_t.h>
 
-/* Get locale datatype definition.  */
-# include <xlocale.h>
-
 /* Just like nl_langinfo but get the information from the locale object L.  */
-extern char *nl_langinfo_l (nl_item __item, __locale_t l);
+extern char *nl_langinfo_l (nl_item __item, locale_t __l);
 #endif
-#endif
 
 __END_DECLS
 
Index: gcc4/recipe/files/gcc/libunixlib/include/locale.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/locale.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/locale.h	(working copy)
@@ -33,16 +33,16 @@
 /* Entire locale.  */
 #  define LC_ALL 6
 
-#define LC_COLLATE_MASK (1L << 1)
-#define LC_CTYPE_MASK (1L << 2)
-#define LC_MESSAGES_MASK (1L << 3)
-#define LC_MONETARY_MASK (1L << 4)
-#define LC_NUMERIC_MASK (1L << 5)
-#define LC_TIME_MASK (1L << 6)
-#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+#  ifdef __USE_XOPEN2K8
+#    define LC_COLLATE_MASK (1L << 0)
+#    define LC_CTYPE_MASK (1L << 1)
+#    define LC_MESSAGES_MASK (1L << 2)
+#    define LC_MONETARY_MASK (1L << 3)
+#    define LC_NUMERIC_MASK (1L << 4)
+#    define LC_TIME_MASK (1L << 5)
+#    define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+#  endif
 
-typedef struct _locale *locale_t;
-
 #else
 /* String collation (functions 'strcoll' and 'strxfrm').  */
 #  define LC_COLLATE 1
@@ -121,6 +121,9 @@
 extern struct lconv *localeconv (void) __THROW;
 
 #ifndef __TARGET_SCL__
+#  ifdef __USE_XOPEN2K8
+#    include <bits/locale_t.h>
+
 extern locale_t uselocale(locale_t newloc);
 
 extern void freelocale(locale_t locobj);
@@ -127,7 +130,11 @@
 
 extern locale_t newlocale(int category_mask, const char *locale,
                           locale_t base);
-# define LC_GLOBAL_LOCALE        ((locale_t) -1L)
+
+extern locale_t duplocale(locale_t locobj);
+
+#    define LC_GLOBAL_LOCALE        ((locale_t) -1L)
+#  endif
 #endif
 
 __END_NAMESPACE_STD
Index: gcc4/recipe/files/gcc/libunixlib/include/string.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/string.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/string.h	(working copy)
@@ -93,6 +93,16 @@
 		       const char *__restrict __src, size_t __n)
      __THROW __nonnull ((2));
 
+#ifdef __USE_XOPEN2K8
+#include <bits/locale_t.h>
+
+extern int strcoll_l (const char *__s1, const char *__s2, locale_t __l)
+     __THROW __attribute_pure__ __nonnull ((1, 2, 3));
+
+extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
+			 locale_t __l) __THROW __nonnull ((2, 4));
+#endif
+
 /* Find the first occurrence of c in s. */
 extern char *strchr (const char *__s, int __c)
      __THROW __attribute_pure__ __nonnull ((1)) __wur;
@@ -281,6 +291,17 @@
 /* Compare no more than N chars of S1 and S2, ignoring case.  */
 extern int strncasecmp (const char *__s1, const char *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2)) __wur;
+
+#  ifdef __USE_XOPEN2K8
+#    include <bits/locale_t.h>
+
+extern int strcasecmp_l (const char *__s1, const char *__s2, locale_t __loc)
+     __THROW __attribute_pure__ __nonnull ((1, 2, 3));
+
+extern int strncasecmp_l (const char *__s1, const char *__s2,
+                          size_t __n, locale_t __loc)
+     __THROW __attribute_pure__ __nonnull ((1, 2, 4));
+#  endif
 #endif /* Use BSD.  */
 
 #if defined __USE_XOPEN2K || defined __USE_MISC
@@ -289,6 +310,11 @@
      __THROW __nonnull ((2));
 #endif
 
+#ifdef __USE_XOPEN2K8
+/* Translate error number to string according to the locale L.  */
+extern char *strerror_l (int __errnum, locale_t __l) __THROW;
+#endif
+
 #ifndef __TARGET_SCL__
 # ifndef basename
 /* Return the file name within directory of FILENAME.  We don't
Index: gcc4/recipe/files/gcc/libunixlib/include/strings.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/strings.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/strings.h	(working copy)
@@ -37,7 +37,17 @@
 /* Compare n chars of S1 and S2, ignoring case.  */
 extern int strncasecmp (const char *__s1, const char *__s2, size_t __n);
 
+#  ifdef __USE_XOPEN2K8
+#    include <bits/locale_t.h>
 
+extern int strcasecmp_l (const char *__s1, const char *__s2, locale_t __loc)
+     __THROW __attribute_pure__ __nonnull ((1, 2, 3));
+
+extern int strncasecmp_l (const char *__s1, const char *__s2,
+                          size_t __n, locale_t __loc)
+     __THROW __attribute_pure__ __nonnull ((1, 2, 4));
+#  endif
+
 /* Return the position of the first bit set in I, or 0 if none are set.
    The least-significant bit is position 1, the most-significant 32.  */
 extern int ffs (int __i);
Index: gcc4/recipe/files/gcc/libunixlib/include/wchar.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/wchar.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/wchar.h	(working copy)
@@ -1,7 +1,7 @@
 /*
  * File taken from glibc 2.11.
  * Following changes were made:
- *   - Disabled non-standard reentrant locale prototypes.
+ *   - None
  */
 
 /* Copyright (C) 1995-2008, 2009 Free Software Foundation, Inc.
@@ -172,7 +172,6 @@
 __END_NAMESPACE_STD
 #endif
 
-#if 0
 #ifdef __USE_XOPEN2K8
 /* Compare S1 and S2, ignoring case.  */
 extern int wcscasecmp (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;
@@ -183,15 +182,14 @@
 
 /* Similar to the two functions above but take the information from
    the provided locale and not the global locale.  */
-# include <xlocale.h>
+# include <bits/locale_t.h>
 
 extern int wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
-			 __locale_t __loc) __THROW;
+			 locale_t __loc) __THROW;
 
 extern int wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
-			  size_t __n, __locale_t __loc) __THROW;
+			  size_t __n, locale_t __loc) __THROW;
 #endif
-#endif
 
 __BEGIN_NAMESPACE_STD
 /* Compare S1 and S2, both interpreted as appropriate to the
@@ -205,7 +203,6 @@
 __END_NAMESPACE_STD
 
 #ifdef __USE_XOPEN2K8
-#if 0
 /* Similar to the two functions above but take the information from
    the provided locale and not the global locale.  */
 
@@ -212,14 +209,13 @@
 /* Compare S1 and S2, both interpreted as appropriate to the
    LC_COLLATE category of the given locale.  */
 extern int wcscoll_l (__const wchar_t *__s1, __const wchar_t *__s2,
-		      __locale_t __loc) __THROW;
+		      locale_t __loc) __THROW;
 
 /* Transform S2 into array pointed to by S1 such that if wcscmp is
    applied to two transformed strings the result is the as applying
    `wcscoll' to the original strings.  */
 extern size_t wcsxfrm_l (wchar_t *__s1, __const wchar_t *__s2,
-			 size_t __n, __locale_t __loc) __THROW;
-#endif
+			 size_t __n, locale_t __loc) __THROW;
 
 #ifndef __TARGET_SCL__
 /* Duplicate S, returning an identical malloc'd string.  */
Index: gcc4/recipe/files/gcc/libunixlib/include/wctype.h
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/include/wctype.h	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/include/wctype.h	(working copy)
@@ -3,7 +3,6 @@
  * Following changes were made:
  *  - Replaced "#include <bits/types.h>" into "#include <unixlib/types.h>"
  *  - Add wint_t typedef when it hasn't been defined in stddef.h.
- *  - Disabled non-standard reentrant locale prototypes.
  */
 
 /* Copyright (C) 1996-2002,2005,2007,2008,2009 Free Software Foundation, Inc.
@@ -191,7 +190,6 @@
 /* Determine whether the wide-character WC has the property described by
    DESC.  */
 extern int iswctype (wint_t __wc, wctype_t __desc) __THROW;
-#define iswctype_l(c, d, l) iswctype(c, d)
 
 __END_NAMESPACE_C99
 
@@ -241,73 +239,71 @@
 extern wint_t towctrans (wint_t __wc, wctrans_t __desc) __THROW;
 __END_NAMESPACE_C99
 
-#if 0
 # ifdef __USE_XOPEN2K8
-/* Declare the interface to extended locale model.  */
-#  include <xlocale.h>
+#  include <bits/locale_t.h>
 
 /* Test for any wide character for which `iswalpha' or `iswdigit' is
    true.  */
-extern int iswalnum_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswalnum_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character for which `iswupper' or 'iswlower' is
    true, or any wide character that is one of a locale-specific set of
    wide-characters for which none of `iswcntrl', `iswdigit',
    `iswpunct', or `iswspace' is true.  */
-extern int iswalpha_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswalpha_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any control wide character.  */
-extern int iswcntrl_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswcntrl_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to a decimal-digit
    character.  */
-extern int iswdigit_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswdigit_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character for which `iswprint' is true and
    `iswspace' is false.  */
-extern int iswgraph_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswgraph_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to a lowercase letter
    or is one of a locale-specific set of wide characters for which
    none of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true.  */
-extern int iswlower_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswlower_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any printing wide character.  */
-extern int iswprint_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswprint_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any printing wide character that is one of a
    locale-specific et of wide characters for which neither `iswspace'
    nor `iswalnum' is true.  */
-extern int iswpunct_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswpunct_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to a locale-specific
    set of wide characters for which none of `iswalnum', `iswgraph', or
    `iswpunct' is true.  */
-extern int iswspace_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswspace_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to an uppercase letter
    or is one of a locale-specific set of wide character for which none
    of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true.  */
-extern int iswupper_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswupper_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to a hexadecimal-digit
    character equivalent to that performed be the functions described
    in the previous subclause.  */
-extern int iswxdigit_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswxdigit_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Test for any wide character that corresponds to a standard blank
    wide character or a locale-specific set of wide characters for
    which `iswalnum' is false.  */
-extern int iswblank_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswblank_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Construct value that describes a class of wide characters identified
    by the string argument PROPERTY.  */
-extern wctype_t wctype_l (__const char *__property, __locale_t __locale)
+extern wctype_t wctype_l (__const char *__property, locale_t __locale)
      __THROW;
 
 /* Determine whether the wide-character WC has the property described by
    DESC.  */
-extern int iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale)
+extern int iswctype_l (wint_t __wc, wctype_t __desc, locale_t __locale)
      __THROW;
 
 
@@ -316,22 +312,21 @@
  */
 
 /* Converts an uppercase letter to the corresponding lowercase letter.  */
-extern wint_t towlower_l (wint_t __wc, __locale_t __locale) __THROW;
+extern wint_t towlower_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Converts an lowercase letter to the corresponding uppercase letter.  */
-extern wint_t towupper_l (wint_t __wc, __locale_t __locale) __THROW;
+extern wint_t towupper_l (wint_t __wc, locale_t __locale) __THROW;
 
 /* Construct value that describes a mapping between wide characters
    identified by the string argument PROPERTY.  */
-extern wctrans_t wctrans_l (__const char *__property, __locale_t __locale)
+extern wctrans_t wctrans_l (__const char *__property, locale_t __locale)
      __THROW;
 
 /* Map the wide character WC using the mapping described by DESC.  */
 extern wint_t towctrans_l (wint_t __wc, wctrans_t __desc,
-			   __locale_t __locale) __THROW;
+			   locale_t __locale) __THROW;
 
 # endif /* Use POSIX 2008.  */
-#endif
 
 __END_DECLS
 
Index: gcc4/recipe/files/gcc/libunixlib/locale/localeconv.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/localeconv.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/localeconv.c	(working copy)
@@ -14,8 +14,6 @@
 
 /* #define DEBUG */
 
-int __setlocale_called = 1;
-
 static int
 read_symbol (int reason_code, int territory)
 {
@@ -71,26 +69,44 @@
   *grouping = new_grouping;
 }
 
-static struct lconv lc = { NULL, NULL, NULL, NULL, NULL,
-			   NULL, NULL, NULL, NULL, NULL,
-			   CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
-			   CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX };
+void
+__localeconv_lconv_init (struct lconv *lc)
+{
+  memset(lc, 0, sizeof(*lc));
+  lc->int_frac_digits = lc->frac_digits = lc->p_cs_precedes =
+  lc->p_sep_by_space = lc->n_cs_precedes = lc->n_sep_by_space =
+  lc->p_sign_posn = lc->n_sign_posn = CHAR_MAX;
+}
 
-/* Defined by POSIX as not threadsafe */
-struct lconv *
-localeconv (void)
+void
+__localeconv_lconv_fini (struct lconv *lc)
 {
+  free(lc->decimal_point);
+  free(lc->thousands_sep);
+  free(lc->grouping);
+  free(lc->int_curr_symbol);
+  free(lc->currency_symbol);
+  free(lc->mon_decimal_point);
+  free(lc->mon_thousands_sep);
+  free(lc->mon_grouping);
+  free(lc->positive_sign);
+  free(lc->negative_sign);
+}
+
+void
+__localeconv_l (locale_t locobj)
+{
   int numeric, monetary;
 
   /* If setlocale has not been called since the last call to
      localeconv, then the lconv structure will be the same.  */
-  if (!__setlocale_called)
-    return &lc;
+  if (!locobj->lc_needs_refresh)
+    return;
 
-  __setlocale_called = 0;
+  locobj->lc_needs_refresh = 0;
 
-  numeric = __locale_territory[LC_NUMERIC];
-  monetary = __locale_territory[LC_MONETARY];
+  numeric = locobj->locale_territory[LC_NUMERIC];
+  monetary = locobj->locale_territory[LC_MONETARY];
 
   /* See the PRMs regarding SWI Territory_ReadSymbols for the
      meanings of the following numbers.  */
@@ -97,71 +113,80 @@
   if (numeric == -1)
     {
       /* We're using the 'C' locale.  */
-      free (lc.decimal_point);
-      lc.decimal_point = strdup (".");
-      free (lc.thousands_sep);
-      lc.thousands_sep = strdup ("");
-      free (lc.grouping);
-      lc.grouping = strdup ("");
+      free (locobj->lc.decimal_point);
+      locobj->lc.decimal_point = strdup (".");
+      free (locobj->lc.thousands_sep);
+      locobj->lc.thousands_sep = strdup ("");
+      free (locobj->lc.grouping);
+      locobj->lc.grouping = strdup ("");
     }
   else
     {
-      free (lc.decimal_point);
-      lc.decimal_point = strdup ((char *) read_symbol (0, numeric));
-      free (lc.thousands_sep);
-      lc.thousands_sep = strdup ((char *) read_symbol (1, numeric));
-      read_byte_list (2, &lc.grouping, numeric);
+      free (locobj->lc.decimal_point);
+      locobj->lc.decimal_point = strdup ((char *) read_symbol (0, numeric));
+      free (locobj->lc.thousands_sep);
+      locobj->lc.thousands_sep = strdup ((char *) read_symbol (1, numeric));
+      read_byte_list (2, &locobj->lc.grouping, numeric);
     }
   if (monetary == -1)
     {
       /* We using the 'C' locale.  Empty strings and CHAR_MAX means
 	 that these fields are unspecified.  */
-      free (lc.mon_decimal_point);
-      lc.mon_decimal_point = strdup ("");
-      free (lc.mon_thousands_sep);
-      lc.mon_thousands_sep = strdup ("");
-      free (lc.mon_grouping);
-      lc.mon_grouping = strdup ("");
-      lc.int_frac_digits = CHAR_MAX;
-      lc.frac_digits = CHAR_MAX;
-      free (lc.currency_symbol);
-      lc.currency_symbol = strdup ("");
-      free (lc.int_curr_symbol);
-      lc.int_curr_symbol = strdup ("");
-      lc.p_cs_precedes = CHAR_MAX;
-      lc.n_cs_precedes = CHAR_MAX;
-      lc.p_sep_by_space = CHAR_MAX;
-      lc.n_sep_by_space = CHAR_MAX;
-      free (lc.positive_sign);
-      lc.positive_sign = strdup ("");
-      free (lc.negative_sign);
-      lc.negative_sign = strdup ("");
-      lc.p_sign_posn = CHAR_MAX;
-      lc.n_sign_posn = CHAR_MAX;
+      free (locobj->lc.mon_decimal_point);
+      locobj->lc.mon_decimal_point = strdup ("");
+      free (locobj->lc.mon_thousands_sep);
+      locobj->lc.mon_thousands_sep = strdup ("");
+      free (locobj->lc.mon_grouping);
+      locobj->lc.mon_grouping = strdup ("");
+      locobj->lc.int_frac_digits = CHAR_MAX;
+      locobj->lc.frac_digits = CHAR_MAX;
+      free (locobj->lc.currency_symbol);
+      locobj->lc.currency_symbol = strdup ("");
+      free (locobj->lc.int_curr_symbol);
+      locobj->lc.int_curr_symbol = strdup ("");
+      locobj->lc.p_cs_precedes = CHAR_MAX;
+      locobj->lc.n_cs_precedes = CHAR_MAX;
+      locobj->lc.p_sep_by_space = CHAR_MAX;
+      locobj->lc.n_sep_by_space = CHAR_MAX;
+      free (locobj->lc.positive_sign);
+      locobj->lc.positive_sign = strdup ("");
+      free (locobj->lc.negative_sign);
+      locobj->lc.negative_sign = strdup ("");
+      locobj->lc.p_sign_posn = CHAR_MAX;
+      locobj->lc.n_sign_posn = CHAR_MAX;
     }
   else
     {
-      free (lc.int_curr_symbol);
-      lc.int_curr_symbol = strdup ((char *)read_symbol (3, monetary));
-      free (lc.currency_symbol);
-      lc.currency_symbol = strdup ((char *)read_symbol (4, monetary));
-      free (lc.mon_decimal_point);
-      lc.mon_decimal_point = strdup ((char *)read_symbol (5, monetary));
-      free (lc.mon_thousands_sep);
-      lc.mon_thousands_sep = strdup ((char *)read_symbol (6, monetary));
-      read_byte_list (7, &lc.mon_grouping, monetary);
-      free (lc.positive_sign);
-      lc.positive_sign = strdup ((char *)read_symbol (8, monetary));
-      free (lc.negative_sign);
-      lc.negative_sign = strdup ((char *)read_symbol (9, monetary));
-      lc.int_frac_digits = (char)read_symbol (10, monetary);
-      lc.frac_digits = (char)read_symbol (11, monetary);
-      lc.p_cs_precedes = (char)read_symbol (12, monetary);
-      lc.p_sep_by_space = (char)read_symbol (13, monetary);
-      lc.n_cs_precedes = (char)read_symbol (14, monetary);
-      lc.n_sep_by_space = (char)read_symbol (15, monetary);
-      lc.p_sign_posn = (char)read_symbol (16, monetary);
-      lc.n_sign_posn = (char)read_symbol (17, monetary);
+      free (locobj->lc.int_curr_symbol);
+      locobj->lc.int_curr_symbol = strdup ((char *)read_symbol (3, monetary));
+      free (locobj->lc.currency_symbol);
+      locobj->lc.currency_symbol = strdup ((char *)read_symbol (4, monetary));
+      free (locobj->lc.mon_decimal_point);
+      locobj->lc.mon_decimal_point = strdup ((char *)read_symbol (5, monetary));
+      free (locobj->lc.mon_thousands_sep);
+      locobj->lc.mon_thousands_sep = strdup ((char *)read_symbol (6, monetary));
+      read_byte_list (7, &locobj->lc.mon_grouping, monetary);
+      free (locobj->lc.positive_sign);
+      locobj->lc.positive_sign = strdup ((char *)read_symbol (8, monetary));
+      free (locobj->lc.negative_sign);
+      locobj->lc.negative_sign = strdup ((char *)read_symbol (9, monetary));
+      locobj->lc.int_frac_digits = (char)read_symbol (10, monetary);
+      locobj->lc.frac_digits = (char)read_symbol (11, monetary);
+      locobj->lc.p_cs_precedes = (char)read_symbol (12, monetary);
+      locobj->lc.p_sep_by_space = (char)read_symbol (13, monetary);
+      locobj->lc.n_cs_precedes = (char)read_symbol (14, monetary);
+      locobj->lc.n_sep_by_space = (char)read_symbol (15, monetary);
+      locobj->lc.p_sign_posn = (char)read_symbol (16, monetary);
+      locobj->lc.n_sign_posn = (char)read_symbol (17, monetary);
     }
-  return &lc;
+  return;
 }
+
+/* Defined by POSIX as not threadsafe */
+struct lconv *
+localeconv (void)
+{
+  __localeconv_l (&__locale_global);
+
+  return &__locale_global.lc;
+}
Index: gcc4/recipe/files/gcc/libunixlib/locale/newlocale.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/newlocale.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/newlocale.c	(working copy)
@@ -1,17 +1,17 @@
 /* Copyright (c) 2019 UnixLib Developers
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
 #include <stdlib.h>
-#include <locale.h>
 #include <stdio.h>
-#include <errno.h>
+#include <string.h>
 
-struct _locale {
-  struct lconv lc;
-};
+#include <internal/unix.h>
 
 /* This is supposed to be per-thread.  */
-static locale_t current_locale;
+static locale_t current_locale = LC_GLOBAL_LOCALE;
 
 locale_t uselocale(locale_t newloc)
 {
@@ -27,20 +27,94 @@
 
 void freelocale(locale_t locobj)
 {
-  if (locobj)
+  if (locobj) {
+    __localeconv_lconv_fini(&locobj->lc);
     free(locobj);
+  }
 }
 
 locale_t newlocale(int category_mask, const char *locale,
                           locale_t base)
 {
-  locale_t loc = (locale_t)malloc(sizeof(*loc));
-  if (!loc) {
+  struct _locale tmp;
+
+  PTHREAD_UNSAFE
+
+  if ((category_mask & ~LC_ALL_MASK) || locale == NULL) {
+    __set_errno (EINVAL);
+    return 0;
+  }
+
+  /* The locale provided will be verified by __setlocale_l() */
+
+  /* Prepare the temporary locale we will modify */
+  if (base != 0 && base != LC_GLOBAL_LOCALE) {
+    memcpy(&tmp, base, sizeof(tmp));
+  } else {
+    if (base == LC_GLOBAL_LOCALE) {
+      /* Undefined: be helpful to client */
+      memcpy(&tmp, &__locale_global, sizeof(tmp));
+    } else {
+      /* Initialise to C locale */
+      __build_ctype_tables(&tmp, -2);
+    }
+  }
+
+  /* Now, apply the requested locale to each of the categories in the mask */
+  if (category_mask == LC_ALL_MASK) {
+    /* Special-case LC_ALL to handle the encoded locale string */
+    if (__setlocale_l(&tmp, LC_ALL, locale) == NULL) {
+      return 0;
+    }
+  } else {
+    int category = 0, mask = category_mask;
+    while (mask != 0) {
+      if (mask & 1) {
+        if (__setlocale_l(&tmp, category, locale) == NULL) {
+          return 0;
+        }
+      }
+      category++;
+      mask >>= 1;
+    }
+  }
+
+  /* Allocate the result, if necessary */
+  if (base == 0 || base == LC_GLOBAL_LOCALE) {
+    base = (locale_t)malloc(sizeof(*base));
+    if (!base) {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+  }
+  /* Fill it in */
+  memcpy(base, &tmp, sizeof(tmp));
+
+  /* Mark the lconv data stale */
+  base->lc_needs_refresh = 1;
+
+  return base;
+}
+
+locale_t duplocale(locale_t locobj)
+{
+  locale_t loc;
+
+  loc = (locale_t) malloc(sizeof(*loc));
+  if (loc == NULL) {
     __set_errno (ENOMEM);
     return 0;
   }
 
-  loc->lc = *localeconv();
+  if (locobj == LC_GLOBAL_LOCALE) {
+    memcpy(loc, &__locale_global, sizeof(*loc));
+  } else {
+    memcpy(loc, locobj, sizeof(*loc));
+  }
 
+  /* Invalidate lconv in the copy */
+  __localeconv_lconv_init(&loc->lc);
+  loc->lc_needs_refresh = 1;
+
   return loc;
 }
Index: gcc4/recipe/files/gcc/libunixlib/locale/nl_langinfo.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/nl_langinfo.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/nl_langinfo.c	(working copy)
@@ -24,3 +24,10 @@
 
   return (char *)value;
 }
+
+char *
+nl_langinfo_l (nl_item item, locale_t l)
+{
+  (void) l;
+  return nl_langinfo(item);
+}
Index: gcc4/recipe/files/gcc/libunixlib/locale/setlocale.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/setlocale.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/setlocale.c	(working copy)
@@ -195,7 +195,7 @@
 }
 
 static void
-do_lc_all (char *buffer, int size)
+do_lc_all (locale_t locobj, char *buffer, int size)
 {
   char temp[64];
   int category, same = 1;
@@ -204,13 +204,13 @@
      setlocale to set all locales.  If all locales are
      the same, then we can produce a very short string.  */
   for (category = 1; category < LC_ALL; ++category)
-    if (__locale_territory[0] != __locale_territory[category])
+    if (locobj->locale_territory[0] != locobj->locale_territory[category])
       same = 0;
 
   if (same)
     {
       /* All locales are set to the same territory.  */
-      territory_name (__locale_territory[0], buffer, size);
+      territory_name (locobj->locale_territory[0], buffer, size);
     }
   else
     {
@@ -218,7 +218,7 @@
 	   LC_CATEGORY=country;LC_CATEGORY=country; ...  */
       for (category = 0; category < LC_ALL; ++category)
 	{
-	  territory_name (__locale_territory[category], temp, sizeof (temp));
+	  territory_name (locobj->locale_territory[category], temp, sizeof (temp));
 	  buffer = stpcpy (buffer, locale_names[category]);
 	  *buffer++ = '=';
 	  buffer = stpcpy (buffer, temp);
@@ -230,15 +230,13 @@
 }
 
 char *
-setlocale (int category, const char *locale)
+__setlocale_l (locale_t locobj, int category, const char *locale)
 {
   int new_territory, changed;
   static char old_locale[256];
 
-  PTHREAD_UNSAFE
-
   /* This tells localeconv to re-read data for the lconv structure.  */
-  __setlocale_called = 1;
+  locobj->lc_needs_refresh = 1;
 
   if (locale == NULL)
     {
@@ -247,11 +245,11 @@
 	{
 	  /* The locale string is specially encoded for LC_ALL so we
 	     could restore all locales at any time.  */
-	  do_lc_all (old_locale, sizeof (old_locale));
+	  do_lc_all (locobj, old_locale, sizeof (old_locale));
 	  return old_locale;
 	}
 
-      territory_name (__locale_territory[category], old_locale, sizeof (old_locale));
+      territory_name (locobj->locale_territory[category], old_locale, sizeof (old_locale));
       return old_locale;
     }
 
@@ -270,7 +268,7 @@
       /* Encode the locale string, as we will be returning this
 	 later.  Remember, setlocale returns the locale settings
 	 that are about to be changed.  */
-      do_lc_all (old_locale, sizeof (old_locale));
+      do_lc_all (locobj, old_locale, sizeof (old_locale));
 
       /* Check for an encoded (composite) name.  Simply looking for
 	 a semi-colon will verify this.  */
@@ -332,11 +330,11 @@
 
 	  /* We now know all locales exist, so set them.  */
 	  for (category = 0; category < LC_ALL; ++category)
-	    __locale_territory[category] = territory_number (newnames[category]);
+	    locobj->locale_territory[category] = territory_number (newnames[category]);
 
 	  /* Re-build the character type tables according to the new
 	     locale settings.  */
-	  __build_ctype_tables (__locale_territory[LC_CTYPE]);
+	  __build_ctype_tables (locobj, locobj->locale_territory[LC_CTYPE]);
 	  return old_locale;
 	}
     }
@@ -359,9 +357,9 @@
       /* Change the locale for all categories. old_locale was created
 	 when we previously checked for a composite string.  */
       for (category = 0; category < LC_ALL; ++category)
-	if (__locale_territory[category] != new_territory)
+	if (locobj->locale_territory[category] != new_territory)
 	  {
-	    __locale_territory[category] = new_territory;
+	    locobj->locale_territory[category] = new_territory;
 	    changed = 1;
 	  }
     }
@@ -368,12 +366,12 @@
   else
     {
       /* Change the locale for just one category.  */
-      territory_name (__locale_territory[category],
+      territory_name (locobj->locale_territory[category],
 		      old_locale, sizeof (old_locale));
 
-      if (__locale_territory[category] != new_territory)
+      if (locobj->locale_territory[category] != new_territory)
 	{
-	  __locale_territory[category] = new_territory;
+	  locobj->locale_territory[category] = new_territory;
 	  changed = 1;
 	}
     }
@@ -384,7 +382,16 @@
      is changing.  The GNU Java compiler is known to repeatedly call
      setlocale.  */
   if (changed && (category == LC_ALL || category == LC_CTYPE))
-    __build_ctype_tables (new_territory);
+    __build_ctype_tables (locobj, new_territory);
 
   return old_locale;
 }
+
+char *
+setlocale (int category, const char *locale)
+{
+
+  PTHREAD_UNSAFE
+
+  return __setlocale_l(&__locale_global, category, locale);
+}
Index: gcc4/recipe/files/gcc/libunixlib/locale/strcoll.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/strcoll.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/strcoll.c	(working copy)
@@ -11,9 +11,15 @@
 int
 strcoll (const char *s1, const char *s2)
 {
+  return strcoll_l (s1, s2, &__locale_global);
+}
+
+int
+strcoll_l (const char *s1, const char *s2, locale_t l)
+{
   int regs[10];
 
-  regs[0] = __locale_territory[LC_COLLATE];
+  regs[0] = l->locale_territory[LC_COLLATE];
   regs[1] = (int)s1;
   regs[2] = (int)s2;
   regs[3] = 0;
@@ -21,3 +27,4 @@
   __os_swi (Territory_Collate, regs);
   return regs[0];
 }
+
Index: gcc4/recipe/files/gcc/libunixlib/locale/strxfrm.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/strxfrm.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/strxfrm.c	(working copy)
@@ -11,9 +11,15 @@
 size_t
 strxfrm (char *to, const char *from, size_t size)
 {
+  return strxfrm_l (to, from, size, &__locale_global);
+}
+
+size_t
+strxfrm_l (char *to, const char *from, size_t size, locale_t l)
+{
   int regs[10];
 
-  regs[0] = __locale_territory[LC_COLLATE];
+  regs[0] = l->locale_territory[LC_COLLATE];
   regs[1] = (int)to;
   regs[2] = (int)from;
   regs[3] = size;
Index: gcc4/recipe/files/gcc/libunixlib/locale/territory.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/locale/territory.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/locale/territory.c	(nonexistent)
@@ -1,10 +0,0 @@
-/* __locale_territory
- * Copyright (c) 2000-2006 UnixLib Developers
- */
-
-#include <locale.h>
-
-/* Global used for all calls to the Territory module. These variable
-   contain the territory number as set by setlocale. A value of
-   -1 means use the C locale.  */
-int __locale_territory[LC_ALL + 1];
Index: gcc4/recipe/files/gcc/libunixlib/string/stricmp.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/string/stricmp.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/string/stricmp.c	(working copy)
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <strings.h>
 #include <ctype.h>
+#include <locale.h>
 
 int
 stricmp (const char *s1, const char *s2)
@@ -26,3 +27,24 @@
   return result;
 }
 strong_alias (stricmp, strcasecmp)
+
+int
+strcasecmp_l (const char *s1, const char *s2, locale_t locobj)
+{
+  const unsigned char *p1 = (const unsigned char *) s1;
+  const unsigned char *p2 = (const unsigned char *) s2;
+  int result = 0;
+
+  if (p1 == p2)
+    return result;
+
+  while (! result)
+    {
+      result = tolower_l (*p1, locobj) - tolower_l (*p2, locobj);
+      if (*p1++ == '\0')
+        break;
+      p2 ++;
+    }
+
+  return result;
+}
Index: gcc4/recipe/files/gcc/libunixlib/string/strnicmp.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/string/strnicmp.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/string/strnicmp.c	(working copy)
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <strings.h>
 #include <ctype.h>
+#include <locale.h>
 
 int
 strnicmp (const char *s1, const char *s2, size_t n)
@@ -26,3 +27,22 @@
 }
 strong_alias (strnicmp, strncasecmp)
 
+int
+strncasecmp_l (const char *s1, const char *s2, size_t n, locale_t locobj)
+{
+  int i, j;
+
+  if (!n)
+    return 0;
+
+  do
+    {
+      i = *s1++, j = *s2++;
+      i = tolower_l (i, locobj);
+      j = tolower_l (j, locobj);
+    }
+  while (i && i == j && --n);
+
+  return i - j;
+}
+
Index: gcc4/recipe/files/gcc/libunixlib/sys/errlist.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/sys/errlist.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/sys/errlist.c	(working copy)
@@ -211,3 +211,10 @@
 
   return 0;
 }
+
+char *
+strerror_l (int errnum, locale_t l)
+{
+  (void) l;
+  return strerror (errnum);
+}
Index: gcc4/recipe/files/gcc/libunixlib/time/broken.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/broken.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/broken.c	(working copy)
@@ -49,7 +49,7 @@
 #ifdef __TARGET_SCL__
 					     -1,
 #else
-					     __locale_territory[LC_TIME],
+					     __locale_global.locale_territory[LC_TIME],
 #endif
 					     riscos_time, ordinals);
 }
Index: gcc4/recipe/files/gcc/libunixlib/time/gmtime_r.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/gmtime_r.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/gmtime_r.c	(working copy)
@@ -46,7 +46,7 @@
 #ifdef __TARGET_SCL__
 						     -1,
 #else
-						     __locale_territory[LC_TIME],
+						     __locale_global.locale_territory[LC_TIME],
 #endif
 						     riscos_time, ordinals)) != NULL)
     {
Index: gcc4/recipe/files/gcc/libunixlib/time/localtime_r.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/localtime_r.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/localtime_r.c	(working copy)
@@ -28,7 +28,7 @@
 #ifdef __TARGET_SCL__
 						  -1,
 #else
-						  __locale_territory[LC_TIME],
+						  __locale_global.locale_territory[LC_TIME],
 #endif
 						  riscos_time, ordinals)) != NULL)
     {
Index: gcc4/recipe/files/gcc/libunixlib/time/mktime.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/mktime.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/mktime.c	(working copy)
@@ -23,7 +23,7 @@
 #ifdef __TARGET_SCL__
 						     -1,
 #else
-						     __locale_territory[LC_TIME],
+						     __locale_global.locale_territory[LC_TIME],
 #endif
 						     riscos_time,
 						     ordinals)) != NULL)
Index: gcc4/recipe/files/gcc/libunixlib/time/stdtime.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/stdtime.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/stdtime.c	(working copy)
@@ -48,7 +48,7 @@
 #ifdef __TARGET_SCL__
 					       -1,
 #else
-					       __locale_territory[LC_TIME],
+					       __locale_global.locale_territory[LC_TIME],
 #endif
 					       riscos_time,
 					       result,
Index: gcc4/recipe/files/gcc/libunixlib/time/strftime.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/strftime.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/strftime.c	(working copy)
@@ -353,7 +353,7 @@
   int regs[10];
   char buffer[64];
 
-  regs[0] = __locale_territory[LC_TIME];
+  regs[0] = __locale_global.locale_territory[LC_TIME];
   regs[1] = (int)timep;
   regs[2] = (int)buffer;
   regs[3] = sizeof (buffer) - 1;
@@ -368,7 +368,7 @@
   int regs[10];
   char buffer[64];
 
-  regs[0] = __locale_territory[LC_TIME];
+  regs[0] = __locale_global.locale_territory[LC_TIME];
   regs[1] = (int)timep;
   regs[2] = (int)buffer;
   regs[3] = sizeof (buffer) - 1;
Index: gcc4/recipe/files/gcc/libunixlib/time/tzset.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/time/tzset.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/time/tzset.c	(working copy)
@@ -36,7 +36,7 @@
   /* Get timezone information for current territory.  */
   _kernel_swi_regs regs;
 #ifndef __TARGET_SCL__
-  regs.r[0] = __locale_territory[LC_TIME];
+  regs.r[0] = __locale_global.locale_territory[LC_TIME];
 #else
   regs.r[0] = -1; /* Current territory.  */
 #endif
Index: gcc4/recipe/files/gcc/libunixlib/unix/unix.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/unix/unix.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/unix/unix.c	(working copy)
@@ -191,7 +191,7 @@
   __pthread_prog_init ();
   __unixlib_signal_initialise (__u);
   /* Initialise ctype tables to the C locale.  */
-  __build_ctype_tables (-2);
+  __build_ctype_tables (&__locale_global, -2);
   /* Define and initialise the Unix I/O.  */
   initialise_unix_io ();
   __stdioinit ();
Index: gcc4/recipe/files/gcc/libunixlib/vscript
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/vscript	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/vscript	(working copy)
@@ -58,6 +58,9 @@
      __init_des_r;
      __init_des;
      __invalidate;
+     __locale_global;
+     __localeconv_lconv_init;
+     __localeconv_lconv_fini;
      malloc_trim;
      malloc_trim_unlocked;
      malloc_unlocked;
@@ -80,6 +83,7 @@
      __res_vinit;
      __runtime_features;
      __setup_signalhandler_stack;
+     __setlocale_l;
      __sdirinit;
      __sfixinit;
      __sfixfind;
Index: gcc4/recipe/files/gcc/libunixlib/wchar/wctype.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/wchar/wctype.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/wchar/wctype.c	(working copy)
@@ -4,6 +4,7 @@
  */
 
 #include <ctype.h>
+#include <locale.h>
 #include <wctype.h>
 
 int
@@ -71,3 +72,69 @@
 {
   return isxdigit (wc);
 }
+
+int
+iswalnum_l (wint_t wc, locale_t locale)
+{
+  return isalnum_l (wc, locale);
+}
+
+int
+iswalpha_l (wint_t wc, locale_t locale)
+{
+  return isalpha_l (wc, locale);
+}
+
+int
+iswcntrl_l (wint_t wc, locale_t locale)
+{
+  return iscntrl_l (wc, locale);
+}
+
+int
+iswdigit_l (wint_t wc, locale_t locale)
+{
+  return isdigit_l (wc, locale);
+}
+
+int
+iswgraph_l (wint_t wc, locale_t locale)
+{
+  return isgraph_l (wc, locale);
+}
+
+int
+iswprint_l (wint_t wc, locale_t locale)
+{
+  return isprint_l (wc, locale);
+}
+
+int
+iswpunct_l (wint_t wc, locale_t locale)
+{
+  return ispunct_l (wc, locale);
+}
+
+int
+iswspace_l (wint_t wc, locale_t locale)
+{
+  return isspace_l (wc, locale);
+}
+
+int
+iswxdigit_l (wint_t wc, locale_t locale)
+{
+  return isxdigit_l (wc, locale);
+}
+
+wint_t
+towlower_l (wint_t wc, locale_t locale)
+{
+  return tolower_l (wc, locale);
+}
+
+wint_t
+towupper_l (wint_t wc, locale_t locale)
+{
+  return toupper_l (wc, locale);
+}
Index: gcc4/recipe/files/gcc/libunixlib/wchar/wmissing.c
===================================================================
--- gcc4/recipe/files/gcc/libunixlib/wchar/wmissing.c	(revision 7698)
+++ gcc4/recipe/files/gcc/libunixlib/wchar/wmissing.c	(working copy)
@@ -1,7 +1,7 @@
+#include <locale.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <wctype.h>
-#include <wctype.h>
-#include <stdio.h>
 
 int iswupper (wint_t __wc)
 {
@@ -9,13 +9,26 @@
   abort();
 }
 
-unsigned long int wcstoul (__const wchar_t *__restrict __nptr,
-				  wchar_t **__restrict __endptr, int __base)
+int
+iswupper_l (wint_t wc, locale_t locale)
 {
   printf("%s: Not implemented\n", __func__);
   abort();
 }
 
+int iswlower (wint_t __wc)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
+int
+iswlower_l (wint_t wc, locale_t locale)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 int wcscoll (__const wchar_t *__s1, __const wchar_t *__s2)
 {
   printf("%s: Not implemented\n", __func__);
@@ -22,12 +35,47 @@
   abort();
 }
 
-int iswlower (wint_t __wc)
+int wcscoll_l (__const wchar_t *__s1, __const wchar_t *__s2,
+		locale_t loc)
 {
   printf("%s: Not implemented\n", __func__);
   abort();
 }
 
+int wcscasecmp (__const wchar_t *__s1, __const wchar_t *__s2)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
+int wcsncasecmp (__const wchar_t *__s1, __const wchar_t *__s2,
+		size_t __n)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
+int wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
+		 locale_t __loc)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
+int wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
+		size_t __n, locale_t __loc)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
+unsigned long int wcstoul (__const wchar_t *__restrict __nptr,
+				  wchar_t **__restrict __endptr, int __base)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 long long int wcstoll (__const wchar_t *__restrict __nptr,
 			      wchar_t **__restrict __endptr, int __base)
 {
@@ -63,6 +111,13 @@
   abort();
 }
 
+size_t wcsxfrm_l (wchar_t *__s1, __const wchar_t *__s2,
+		size_t __n, locale_t __loc)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 float wcstof (__const wchar_t *__restrict __nptr,
 		     wchar_t **__restrict __endptr)
 {
@@ -83,6 +138,13 @@
   abort();
 }
 
+int
+iswblank_l (wint_t __wc, locale_t __locale)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 int iswctype (wint_t __wc, wctype_t __desc)
 {
   printf("%s: Not implemented\n", __func__);
@@ -89,6 +151,12 @@
   abort();
 }
 
+int iswctype_l (wint_t __wc, wctype_t __desc, locale_t __locale)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 unsigned long long int wcstoull (__const wchar_t *__restrict __nptr,
 					wchar_t **__restrict __endptr,
 					int __base)
@@ -116,6 +184,12 @@
   abort();
 }
 
+wctype_t wctype_l (__const char *__property, locale_t __locale)
+{
+  printf("%s: Not implemented\n", __func__);
+  abort();
+}
+
 wint_t ungetwc(wint_t wc, FILE *stream)
 {
   printf("%s: Not implemented\n", __func__);
_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Reply via email to