This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] POSIX-1.2008 per-thread locales, groundwork part 1


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=a6a477fa8190b13d4ef0150875e2bd114cb5b132

commit a6a477fa8190b13d4ef0150875e2bd114cb5b132
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Wed Jul 13 16:51:33 2016 +0200

    POSIX-1.2008 per-thread locales, groundwork part 1
    
    Introduce first cut of struct _thr_locale_t used for the locale_t definition.
    Introduce global instance called __global_locale used by default.
    Introduce internal inline functions __get_global_locale, __get_locale_r,
    __get_current_locale.
    
    Remove usage of global variables in favor of accessor functions pointing to
    __global_locale for now.  Include all local headers in locale subdir from
    setlocale.h to get single include for internal locale access.
    
    Introduce __CTYPE_PTR macro to replace direct access to __ctype_ptr__
    and use throughout in isxxx functions.
    
    Signed-off by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 newlib/libc/ctype/ctype_.c       |  67 +++--------
 newlib/libc/ctype/isalnum.c      |   2 +-
 newlib/libc/ctype/isalpha.c      |   2 +-
 newlib/libc/ctype/isblank.c      |   2 +-
 newlib/libc/ctype/iscntrl.c      |   2 +-
 newlib/libc/ctype/isdigit.c      |   2 +-
 newlib/libc/ctype/islower.c      |   2 +-
 newlib/libc/ctype/isprint.c      |   2 +-
 newlib/libc/ctype/ispunct.c      |   2 +-
 newlib/libc/ctype/isspace.c      |   2 +-
 newlib/libc/ctype/isupper.c      |   2 +-
 newlib/libc/ctype/isxdigit.c     |   2 +-
 newlib/libc/include/ctype.h      |  16 ++-
 newlib/libc/include/locale.h     |  15 +++
 newlib/libc/locale/lctype.c      | 112 ++++++++++--------
 newlib/libc/locale/lctype.h      |   5 +-
 newlib/libc/locale/lmessages.c   |  87 ++++++++------
 newlib/libc/locale/lmessages.h   |   5 +-
 newlib/libc/locale/lmonetary.c   | 138 +++++++++-------------
 newlib/libc/locale/lmonetary.h   |   5 +-
 newlib/libc/locale/lnumeric.c    |  94 +++++++--------
 newlib/libc/locale/lnumeric.h    |   5 +-
 newlib/libc/locale/locale.c      | 247 +++++++++++++++++++++------------------
 newlib/libc/locale/nl_langinfo.c |   6 +-
 newlib/libc/locale/setlocale.h   |  81 +++++++++++++
 newlib/libc/locale/timelocal.c   |  82 +++++++------
 newlib/libc/locale/timelocal.h   |   5 +-
 winsup/cygwin/common.din         |   1 +
 winsup/cygwin/ctype.cc           |  27 +++--
 winsup/cygwin/nlsfuncs.cc        |  67 +++++++----
 winsup/cygwin/regex/regcomp.c    |   7 +-
 31 files changed, 610 insertions(+), 484 deletions(-)

diff --git a/newlib/libc/ctype/ctype_.c b/newlib/libc/ctype/ctype_.c
index 164a8ee..f6ea637 100644
--- a/newlib/libc/ctype/ctype_.c
+++ b/newlib/libc/ctype/ctype_.c
@@ -98,13 +98,6 @@ char _ctype_b[128 + 256] = {
 	_CTYPE_DATA_128_255
 };
 
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-#ifndef _MB_CAPABLE
-_CONST
-#endif
-char __EXPORT *__ctype_ptr = (char *) _ctype_b + 128;
-#endif
-
 #ifndef _MB_CAPABLE
 _CONST
 #endif
@@ -135,7 +128,7 @@ _CONST char _ctype_[1 + 256] = {
 };
 #  endif /* !__CYGWIN__ */
 
-#else	/* !defined(ALLOW_NEGATIVE_CTYPE_INDEX) */
+#else	/* !ALLOW_NEGATIVE_CTYPE_INDEX */
 
 _CONST char _ctype_[1 + 256] = {
 	0,
@@ -143,30 +136,24 @@ _CONST char _ctype_[1 + 256] = {
 	_CTYPE_DATA_128_255
 };
 
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-#ifndef _MB_CAPABLE
-_CONST
-#endif
-char *__ctype_ptr = (char *) _ctype_ + 1;
-#endif
-
 #ifndef _MB_CAPABLE
 _CONST
 #endif
 char *__ctype_ptr__ = (char *) _ctype_;
 
-#endif
+#endif	/* !ALLOW_NEGATIVE_CTYPE_INDEX */
 
 #if defined(_MB_CAPABLE)
 /* Cygwin has its own implementation which additionally maintains backward
    compatibility with applications built under older Cygwin releases. */
 #ifndef __CYGWIN__
 void
-__set_ctype (const char *charset)
+__set_ctype (struct _reent *, const char *charset)
 {
 #if defined(_MB_EXTENDED_CHARSETS_ISO) || defined(_MB_EXTENDED_CHARSETS_WINDOWS)
   int idx;
 #endif
+  char *ctype_ptr = NULL;
 
   switch (*charset)
     {
@@ -180,50 +167,32 @@ __set_ctype (const char *charset)
         idx = 0;
       else
         ++idx;
-#  if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-      __ctype_ptr = (char *) (__ctype_iso[idx] + 128);
-#endif
-      __ctype_ptr__ = (char *) (__ctype_iso[idx] + 127);
-#  else
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-      __ctype_ptr = (char *) __ctype_iso[idx] + 1;
-#endif
-      __ctype_ptr__ = (char *) __ctype_iso[idx];
-#  endif
-      return;
+      ctype_ptr = __ctype_iso[idx];
+      break;
 #endif
 #if defined(_MB_EXTENDED_CHARSETS_WINDOWS)
     case 'C':
       idx = __cp_index (charset + 2);
       if (idx < 0)
         break;
-#  if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-      __ctype_ptr = (char *) (__ctype_cp[idx] + 128);
-#endif
-      __ctype_ptr__ = (char *) (__ctype_cp[idx] + 127);
-#  else
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-      __ctype_ptr = (char *) __ctype_cp[idx] + 1;
-#endif
-      __ctype_ptr__ = (char *) __ctype_cp[idx];
-#  endif
-      return;
+      ctype_ptr = __ctype_cp[idx];
+      break;
 #endif
     default:
       break;
     }
+  if (!ctype_ptr)
+    {
 #  if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-  __ctype_ptr = (char *) _ctype_b + 128;
-#endif
-  __ctype_ptr__ = (char *) _ctype_b + 127;
+      ctype_ptr = _ctype_b;
 #  else
-#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
-  __ctype_ptr = (char *) _ctype_ + 1;
-#endif
-  __ctype_ptr__ = (char *) _ctype_;
+      ctype_ptr = _ctype_;
+#  endif
+    }
+#  if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
+      __ctype_ptr__ = ctype_ptr + 127;
+#  else
+      __ctype_ptr__ = ctype_ptr;
 #  endif
 }
 #endif /* !__CYGWIN__ */
diff --git a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c
index 8bc2897..6c6aab8 100644
--- a/newlib/libc/ctype/isalnum.c
+++ b/newlib/libc/ctype/isalnum.c
@@ -41,6 +41,6 @@ No OS subroutines are required.
 int
 _DEFUN(isalnum,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & (_U|_L|_N));
+	return(__CTYPE_PTR[c+1] & (_U|_L|_N));
 }
 
diff --git a/newlib/libc/ctype/isalpha.c b/newlib/libc/ctype/isalpha.c
index d25a8fa..26e5d6c 100644
--- a/newlib/libc/ctype/isalpha.c
+++ b/newlib/libc/ctype/isalpha.c
@@ -39,6 +39,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isalpha,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & (_U|_L));
+	return(__CTYPE_PTR[c+1] & (_U|_L));
 }
 
diff --git a/newlib/libc/ctype/isblank.c b/newlib/libc/ctype/isblank.c
index 896a007..ecde00b 100644
--- a/newlib/libc/ctype/isblank.c
+++ b/newlib/libc/ctype/isblank.c
@@ -38,5 +38,5 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isblank,(c),int c)
 {
-	return ((__ctype_ptr__[c+1] & _B) || (c == '\t'));
+	return ((__CTYPE_PTR[c+1] & _B) || (c == '\t'));
 }
diff --git a/newlib/libc/ctype/iscntrl.c b/newlib/libc/ctype/iscntrl.c
index 76b0f55..2984784 100644
--- a/newlib/libc/ctype/iscntrl.c
+++ b/newlib/libc/ctype/iscntrl.c
@@ -42,7 +42,7 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iscntrl,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & _C);
+	return(__CTYPE_PTR[c+1] & _C);
 }
 
 
diff --git a/newlib/libc/ctype/isdigit.c b/newlib/libc/ctype/isdigit.c
index 9db2700..94daca5 100644
--- a/newlib/libc/ctype/isdigit.c
+++ b/newlib/libc/ctype/isdigit.c
@@ -39,5 +39,5 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isdigit,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & _N);
+	return(__CTYPE_PTR[c+1] & _N);
 }
diff --git a/newlib/libc/ctype/islower.c b/newlib/libc/ctype/islower.c
index ec43096..6d0eba8 100644
--- a/newlib/libc/ctype/islower.c
+++ b/newlib/libc/ctype/islower.c
@@ -39,6 +39,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(islower,(c),int c)
 {
-	return ((__ctype_ptr__[c+1] & (_U|_L)) == _L);
+	return ((__CTYPE_PTR[c+1] & (_U|_L)) == _L);
 }
 
diff --git a/newlib/libc/ctype/isprint.c b/newlib/libc/ctype/isprint.c
index b95aedd..87254f4 100644
--- a/newlib/libc/ctype/isprint.c
+++ b/newlib/libc/ctype/isprint.c
@@ -48,7 +48,7 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isgraph,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & (_P|_U|_L|_N));
+	return(__CTYPE_PTR[c+1] & (_P|_U|_L|_N));
 }
 
 
diff --git a/newlib/libc/ctype/ispunct.c b/newlib/libc/ctype/ispunct.c
index 9ca6749..43571bb 100644
--- a/newlib/libc/ctype/ispunct.c
+++ b/newlib/libc/ctype/ispunct.c
@@ -41,6 +41,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(ispunct,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & _P);
+	return(__CTYPE_PTR[c+1] & _P);
 }
 
diff --git a/newlib/libc/ctype/isspace.c b/newlib/libc/ctype/isspace.c
index 3658241..9e51a22 100644
--- a/newlib/libc/ctype/isspace.c
+++ b/newlib/libc/ctype/isspace.c
@@ -39,6 +39,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isspace,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & _S);
+	return(__CTYPE_PTR[c+1] & _S);
 }
 
diff --git a/newlib/libc/ctype/isupper.c b/newlib/libc/ctype/isupper.c
index 4994af2..4f491cc 100644
--- a/newlib/libc/ctype/isupper.c
+++ b/newlib/libc/ctype/isupper.c
@@ -38,6 +38,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isupper,(c),int c)
 {
-	return ((__ctype_ptr__[c+1] & (_U|_L)) == _U);
+	return ((__CTYPE_PTR[c+1] & (_U|_L)) == _U);
 }
 
diff --git a/newlib/libc/ctype/isxdigit.c b/newlib/libc/ctype/isxdigit.c
index 314f74e..63cace0 100644
--- a/newlib/libc/ctype/isxdigit.c
+++ b/newlib/libc/ctype/isxdigit.c
@@ -40,6 +40,6 @@ No supporting OS subroutines are required.
 int
 _DEFUN(isxdigit,(c),int c)
 {
-	return(__ctype_ptr__[c+1] & ((_X)|(_N)));
+	return(__CTYPE_PTR[c+1] & ((_X)|(_N)));
 }
 
diff --git a/newlib/libc/include/ctype.h b/newlib/libc/include/ctype.h
index 58a1238..7e6ddb6 100644
--- a/newlib/libc/include/ctype.h
+++ b/newlib/libc/include/ctype.h
@@ -44,18 +44,24 @@ int _EXFUN(toascii, (int __c));
 _CONST
 #endif
 extern	__IMPORT char	*__ctype_ptr__;
+#ifdef __HAVE_LOCALE_INFO__
+char *_EXFUN(__locale_ctype_ptr, (void));
+# define __CTYPE_PTR	(__locale_ctype_ptr ())
+#else
+# define __CTYPE_PTR	(__ctype_ptr__)
+#endif
 
 #ifndef __cplusplus
 /* These macros are intentionally written in a manner that will trigger
    a gcc -Wall warning if the user mistakenly passes a 'char' instead
    of an int containing an 'unsigned char'.  Note that the sizeof will
-   always be 1, which is what we want for mapping EOF to __ctype_ptr__[0];
+   always be 1, which is what we want for mapping EOF to __CTYPE_PTR[0];
    the use of a raw index inside the sizeof triggers the gcc warning if
    __c was of type char, and sizeof masks side effects of the extra __c.
-   Meanwhile, the real index to __ctype_ptr__+1 must be cast to int,
+   Meanwhile, the real index to __CTYPE_PTR+1 must be cast to int,
    since isalpha(0x100000001LL) must equal isalpha(1), rather than being
    an out-of-bounds reference on a 64-bit machine.  */
-#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
+#define __ctype_lookup(__c) ((__CTYPE_PTR+sizeof(""[__c]))[(int)(__c)])
 
 #define	isalpha(__c)	(__ctype_lookup(__c)&(_U|_L))
 #define	isupper(__c)	((__ctype_lookup(__c)&(_U|_L))==_U)
@@ -92,10 +98,10 @@ extern	__IMPORT char	*__ctype_ptr__;
    function.  */
 #   define toupper(__c) \
   __extension__ ({ __typeof__ (__c) __x = (__c);	\
-      (void) __ctype_ptr__[__x]; (toupper) (__x);})
+      (void) __CTYPE_PTR[__x]; (toupper) (__x);})
 #   define tolower(__c) \
   __extension__ ({ __typeof__ (__c) __x = (__c);	\
-      (void) __ctype_ptr__[__x]; (tolower) (__x);})
+      (void) __CTYPE_PTR[__x]; (tolower) (__x);})
 #  endif /* _MB_EXTENDED_CHARSETS* */
 # endif /* __GNUC__ */
 
diff --git a/newlib/libc/include/locale.h b/newlib/libc/include/locale.h
index cbd658e..c7bfd59 100644
--- a/newlib/libc/include/locale.h
+++ b/newlib/libc/include/locale.h
@@ -20,6 +20,21 @@
 #define LC_TIME     5
 #define LC_MESSAGES 6
 
+#if __POSIX_VISIBLE >= 200809
+#define LC_ALL_MASK		(1 << LC_ALL)
+#define LC_COLLATE_MASK		(1 << LC_COLLATE)
+#define LC_CTYPE_MASK		(1 << LC_CTYPE)
+#define LC_MONETARY_MASK	(1 << LC_MONETARY)
+#define LC_NUMERIC_MASK		(1 << LC_NUMERIC)
+#define LC_TIME_MASK		(1 << LC_TIME)
+#define LC_MESSAGES_MASK	(1 << LC_MESSAGES)
+
+#define LC_GLOBAL_LOCALE	((struct _thr_locale_t *) -1)
+
+struct _thr_locale_t;
+typedef struct _thr_locale_t *locale_t;
+#endif
+
 _BEGIN_STD_C
 
 struct lconv
diff --git a/newlib/libc/locale/lctype.c b/newlib/libc/locale/lctype.c
index 28575dd..a776ee0 100644
--- a/newlib/libc/locale/lctype.c
+++ b/newlib/libc/locale/lctype.c
@@ -21,9 +21,6 @@
  * SUCH DAMAGE.
  */
 
-#include <limits.h>
-#include <string.h>
-#include "lctype.h"
 #include "ldpart.h"
 #include "setlocale.h"
 
@@ -53,59 +50,78 @@ static char	*_ctype_locale_buf;
 static char _ctype_locale_buf[_CTYPE_BUF_SIZE];
 #endif
 
+/* NULL locale indicates global locale (called from setlocale) */
 int
-__ctype_load_locale(const char *name, void *f_wctomb, const char *charset,
-		    int mb_cur_max)
+__ctype_load_locale (struct _thr_locale_t *locale, const char *name,
+		     void *f_wctomb, const char *charset, int mb_cur_max)
 {
-	int ret;
+  int ret;
+  struct lc_ctype_T ct;
+  char *bufp = NULL;
 
 #ifdef __CYGWIN__
-	extern int __set_lc_ctype_from_win (const char *,
-					    const struct lc_ctype_T *,
-					    struct lc_ctype_T *, char **,
-					    void *, const char *, int);
-	int old_ctype_using_locale = _ctype_using_locale;
-	_ctype_using_locale = 0;
-	ret = __set_lc_ctype_from_win (name, &_C_ctype_locale, &_ctype_locale,
-				       &_ctype_locale_buf, f_wctomb, charset,
-				       mb_cur_max);
-	/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
-	if (ret < 0)
-	  _ctype_using_locale = old_ctype_using_locale;
-	else
-	  {
-	    _ctype_using_locale = ret;
-	    ret = 0;
-	  }
+  extern int __set_lc_ctype_from_win (const char *, const struct lc_ctype_T *,
+				      struct lc_ctype_T *, char **, void *,
+				      const char *, int);
+  ret = __set_lc_ctype_from_win (name, &_C_ctype_locale, &ct, &bufp,
+				 f_wctomb, charset, mb_cur_max);
+  /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
+  if (ret >= 0)
+    {
+      struct lc_ctype_T *ctp = NULL;
+
+      if (ret > 0)
+	{
+	  ctp = (struct lc_ctype_T *) calloc (1, sizeof *ctp);
+	  if (!ctp)
+	    return -1;
+	  memcpy (ctp, &ct, sizeof *ctp);
+	}
+      locale->ctype = ret == 0 ? NULL : ctp;
+      if (locale->ctype_buf)
+	free (locale->ctype_buf);
+      locale->ctype_buf = bufp;
+      ret = 0;
+    }
 #elif !defined (__HAVE_LOCALE_INFO_EXTENDED__)
-	if (!strcmp (name, "C"))
-	  _ctype_using_locale = 0;
-	else
-	  {
-	    _ctype_locale.codeset = strcpy (_ctype_locale_buf, charset);
-	    char *mbc = _ctype_locale_buf + _CTYPE_BUF_SIZE - 2;
-	    mbc[0] = mb_cur_max;
-	    mbc[1] = '\0';
-	    _ctype_locale.mb_cur_max = mbc;
-	    _ctype_using_locale = 1;
-	  }
-	ret = 0;
+  ret = 0;
+  if (!strcmp (name, "C"))
+    locale->ctype = NULL;
+  else
+    {
+      if (locale == __get_global_locale ())
+	bufp = _ctype_locale_buf;
+      else
+	bufp = (char *) malloc (_CTYPE_BUF_SIZE);
+      if (*bufp)
+	{
+	  _ctype_locale.codeset = strcpy (bufp, charset);
+	  char *mbc = bufp + _CTYPE_BUF_SIZE - 2;
+	  mbc[0] = mb_cur_max;
+	  mbc[1] = '\0';
+	  _ctype_locale.mb_cur_max = mbc;
+	  if (locale->ctype_buf && locale->ctype_buf != _ctype_locale_buf)
+	    free (locale->ctype_buf);
+	  locale->ctype_buf = bufp;
+	}
+      else
+	ret = -1;
+    }
 #else
-	ret = __part_load_locale(name, &_ctype_using_locale,
-		_ctype_locale_buf, "LC_CTYPE",
-		LCCTYPE_SIZE, LCCTYPE_SIZE,
-		(const char **)&_ctype_locale);
-	if (ret == 0 && _ctype_using_locale)
-		_ctype_locale.grouping =
-			__fix_locale_grouping_str(_ctype_locale.grouping);
+  ret = __part_load_locale(name, &_ctype_using_locale,
+			   _ctype_locale_buf, "LC_CTYPE",
+			   LCCTYPE_SIZE, LCCTYPE_SIZE,
+			   (const char **)&_ctype_locale);
+  if (ret == 0 && _ctype_using_locale)
+    _ctype_locale.grouping =
+	    __fix_locale_grouping_str(_ctype_locale.grouping);
 #endif
-	return ret;
+  return ret;
 }
 
 struct lc_ctype_T *
-__get_current_ctype_locale(void) {
-
-	return (_ctype_using_locale
-		? &_ctype_locale
-		: (struct lc_ctype_T *)&_C_ctype_locale);
+__get_current_ctype_locale (void)
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->ctype ?: (struct lc_ctype_T *) &_C_ctype_locale;
 }
diff --git a/newlib/libc/locale/lctype.h b/newlib/libc/locale/lctype.h
index 663074f..ead08c5 100644
--- a/newlib/libc/locale/lctype.h
+++ b/newlib/libc/locale/lctype.h
@@ -39,8 +39,9 @@ struct lc_ctype_T {
 #endif
 };
 
-struct lc_ctype_T *__get_current_ctype_locale(void);
-int	__ctype_load_locale(const char *, void *, const char *, int);
+struct lc_ctype_T *__get_current_ctype_locale (void);
+int __ctype_load_locale (struct _thr_locale_t *, const char *, void *,
+			 const char *, int);
 
 __END_DECLS
 
diff --git a/newlib/libc/locale/lmessages.c b/newlib/libc/locale/lmessages.c
index 9fb1df4..7d9096e 100644
--- a/newlib/libc/locale/lmessages.c
+++ b/newlib/libc/locale/lmessages.c
@@ -28,7 +28,7 @@
 
 #include <stddef.h>
 
-#include "lmessages.h"
+#include "setlocale.h"
 #include "ldpart.h"
 
 #define LCMESSAGES_SIZE_FULL (sizeof(struct lc_messages_T) / sizeof(char *))
@@ -53,57 +53,68 @@ static const struct lc_messages_T _C_messages_locale = {
 #endif
 };
 
+#ifndef __CYGWIN__
 static struct lc_messages_T _messages_locale;
 static int	_messages_using_locale;
 static char	*_messages_locale_buf;
+#endif
 
 int
-__messages_load_locale (const char *name, void *f_wctomb, const char *charset)
+__messages_load_locale (struct _thr_locale_t *locale, const char *name,
+			void *f_wctomb, const char *charset)
 {
+  int ret;
+  struct lc_messages_T me;
+  char *bufp = NULL;
+
 #ifdef __CYGWIN__
-	extern int __set_lc_messages_from_win (const char *,
-					       const struct lc_messages_T *,
-					       struct lc_messages_T *, char **,
-					       void *, const char *);
-	int ret;
+  extern int __set_lc_messages_from_win (const char *,
+					 const struct lc_messages_T *,
+					 struct lc_messages_T *, char **,
+					 void *, const char *);
 
-	int old_messages_using_locale = _messages_using_locale;
-	_messages_using_locale = 0;
-	ret = __set_lc_messages_from_win (name, &_C_messages_locale,
-					  &_messages_locale,
-					  &_messages_locale_buf,
-					  f_wctomb, charset);
-	/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
-	if (ret < 0)
-	  _messages_using_locale = old_messages_using_locale;
-	else
-	  {
-	    _messages_using_locale = ret;
-	    ret = 0;
-	  }
-	return ret;
+  ret = __set_lc_messages_from_win (name, &_C_messages_locale, &me, &bufp,
+				    f_wctomb, charset);
+  /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
+  if (ret >= 0)
+    {
+      struct lc_messages_T *mep = NULL;
+
+      if (ret > 0)
+	{
+	  mep = (struct lc_messages_T *) calloc (1, sizeof *mep);
+	  if (!mep)
+	    return -1;
+	  memcpy (mep, &me, sizeof *mep);
+	}
+      locale->messages = ret == 0 ? NULL : mep;
+      if (locale->messages_buf)
+	free (locale->messages_buf);
+      locale->messages_buf = bufp;
+      ret = 0;
+    }
 #else
-	/*
-	 * Propose that we can have incomplete locale file (w/o "{yes,no}str").
-	 * Initialize them before loading.  In case of complete locale, they'll
-	 * be initialized to loaded value, otherwise they'll not be touched.
-	 */
-	_messages_locale.yesstr = empty;
-	_messages_locale.nostr = empty;
+  /*
+   * Propose that we can have incomplete locale file (w/o "{yes,no}str").
+   * Initialize them before loading.  In case of complete locale, they'll
+   * be initialized to loaded value, otherwise they'll not be touched.
+   */
+  _messages_locale.yesstr = empty;
+  _messages_locale.nostr = empty;
 
-	return __part_load_locale(name, &_messages_using_locale,
-		_messages_locale_buf, "LC_MESSAGES",
-		LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
-		(const char **)&_messages_locale);
+  ret = __part_load_locale(name, &_messages_using_locale,
+			   _messages_locale_buf, "LC_MESSAGES",
+			   LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
+			   (const char **)&_messages_locale);
 #endif
+  return ret;
 }
 
 struct lc_messages_T *
-__get_current_messages_locale(void) {
-
-	return (_messages_using_locale
-		? &_messages_locale
-		: (struct lc_messages_T *)&_C_messages_locale);
+__get_current_messages_locale (void)
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->messages ?: (struct lc_messages_T *) &_C_messages_locale;
 }
 
 #ifdef LOCALE_DEBUG
diff --git a/newlib/libc/locale/lmessages.h b/newlib/libc/locale/lmessages.h
index 079895d..242a67e 100644
--- a/newlib/libc/locale/lmessages.h
+++ b/newlib/libc/locale/lmessages.h
@@ -49,8 +49,9 @@ struct	lc_messages_T {
 #endif
 };
 
-struct lc_messages_T *__get_current_messages_locale(void);
-int __messages_load_locale(const char *, void *, const char *);
+struct lc_messages_T *__get_current_messages_locale (void);
+int __messages_load_locale (struct _thr_locale_t *, const char *, void *,
+			    const char *);
 
 __END_DECLS
 
diff --git a/newlib/libc/locale/lmonetary.c b/newlib/libc/locale/lmonetary.c
index 80c2d04..344a6d8 100644
--- a/newlib/libc/locale/lmonetary.c
+++ b/newlib/libc/locale/lmonetary.c
@@ -28,10 +28,9 @@
 
 #include <limits.h>
 #include <stdlib.h>
-#include "lmonetary.h"
+#include "setlocale.h"
 #include "ldpart.h"
 
-extern int __mlocale_changed;
 extern const char * __fix_locale_grouping_str(const char *);
 
 #define LCMONETARY_SIZE (sizeof(struct lc_monetary_T) / sizeof(char *))
@@ -75,11 +74,11 @@ static const struct lc_monetary_T _C_monetary_locale = {
 #endif
 };
 
+#ifndef __CYGWIN__
 static struct lc_monetary_T _monetary_locale;
 static int	_monetary_using_locale;
 static char	*_monetary_locale_buf;
 
-#ifndef __CYGWIN__
 static char
 cnv(const char *str) {
 	int i = strtol(str, NULL, 10);
@@ -90,97 +89,66 @@ cnv(const char *str) {
 #endif
 
 int
-__monetary_load_locale(const char *name , void *f_wctomb, const char *charset)
+__monetary_load_locale (struct _thr_locale_t *locale, const char *name ,
+			void *f_wctomb, const char *charset)
 {
-	int ret;
+  int ret;
+  struct lc_monetary_T mo;
+  char *bufp = NULL;
 
 #ifdef __CYGWIN__
-	extern int __set_lc_monetary_from_win (const char *,
-					       const struct lc_monetary_T *,
-					       struct lc_monetary_T *, char **,
-					       void *, const char *);
-	int old_monetary_using_locale = _monetary_using_locale;
-	_monetary_using_locale = 0;
-	ret = __set_lc_monetary_from_win (name, &_C_monetary_locale,
-					  &_monetary_locale,
-					  &_monetary_locale_buf,
-					  f_wctomb, charset);
-	/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
-	if (ret < 0)
-	  _monetary_using_locale = old_monetary_using_locale;
-	else
-	  {
-	    _monetary_using_locale = ret;
-	    __mlocale_changed = 1;
-	    ret = 0;
-	  }
+  extern int __set_lc_monetary_from_win (const char *,
+					 const struct lc_monetary_T *,
+					 struct lc_monetary_T *, char **,
+					 void *, const char *);
+  ret = __set_lc_monetary_from_win (name, &_C_monetary_locale, &mo, &bufp,
+				    f_wctomb, charset);
+  /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
+  if (ret >= 0)
+    {
+      struct lc_monetary_T *mop = NULL;
+
+      if (ret > 0)
+	{
+	  mop = (struct lc_monetary_T *) calloc (1, sizeof *mop);
+	  if (!mop)
+	    return -1;
+	  memcpy (mop, &mo, sizeof *mop);
+	}
+      locale->monetary = ret == 0 ? NULL : mop;
+      if (locale->monetary_buf)
+	free (locale->monetary_buf);
+      locale->monetary_buf = bufp;
+      ret = 0;
+    }
 #else
-	__mlocale_changed = 1;
-	ret = __part_load_locale(name, &_monetary_using_locale,
-		_monetary_locale_buf, "LC_MONETARY",
-		LCMONETARY_SIZE, LCMONETARY_SIZE,
-		(const char **)&_monetary_locale);
-	if (ret == 0 && _monetary_using_locale) {
-		_monetary_locale.mon_grouping =
-		     __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+  ret = __part_load_locale(name, &_monetary_using_locale,
+			   _monetary_locale_buf, "LC_MONETARY",
+			   LCMONETARY_SIZE, LCMONETARY_SIZE,
+			   (const char **)&_monetary_locale);
+  if (ret == 0 && _monetary_using_locale) {
+    _monetary_locale.mon_grouping =
+	 __fix_locale_grouping_str(_monetary_locale.mon_grouping);
 
 #define M_ASSIGN_CHAR(NAME) (((char *)_monetary_locale.NAME)[0] = \
-			     cnv(_monetary_locale.NAME))
+		       cnv(_monetary_locale.NAME))
 
-		M_ASSIGN_CHAR(int_frac_digits);
-		M_ASSIGN_CHAR(frac_digits);
-		M_ASSIGN_CHAR(p_cs_precedes);
-		M_ASSIGN_CHAR(p_sep_by_space);
-		M_ASSIGN_CHAR(n_cs_precedes);
-		M_ASSIGN_CHAR(n_sep_by_space);
-		M_ASSIGN_CHAR(p_sign_posn);
-		M_ASSIGN_CHAR(n_sign_posn);
-	}
+    M_ASSIGN_CHAR(int_frac_digits);
+    M_ASSIGN_CHAR(frac_digits);
+    M_ASSIGN_CHAR(p_cs_precedes);
+    M_ASSIGN_CHAR(p_sep_by_space);
+    M_ASSIGN_CHAR(n_cs_precedes);
+    M_ASSIGN_CHAR(n_sep_by_space);
+    M_ASSIGN_CHAR(p_sign_posn);
+    M_ASSIGN_CHAR(n_sign_posn);
+  }
 #endif
-	return ret;
+  return ret;
 }
 
 struct lc_monetary_T *
-__get_current_monetary_locale(void) {
-
-	return (_monetary_using_locale
-		? &_monetary_locale
-		: (struct lc_monetary_T *)&_C_monetary_locale);
-}
-
-#ifdef LOCALE_DEBUG
-void
-monetdebug() {
-printf(	"int_curr_symbol = %s\n"
-	"currency_symbol = %s\n"
-	"mon_decimal_point = %s\n"
-	"mon_thousands_sep = %s\n"
-	"mon_grouping = %s\n"
-	"positive_sign = %s\n"
-	"negative_sign = %s\n"
-	"int_frac_digits = %d\n"
-	"frac_digits = %d\n"
-	"p_cs_precedes = %d\n"
-	"p_sep_by_space = %d\n"
-	"n_cs_precedes = %d\n"
-	"n_sep_by_space = %d\n"
-	"p_sign_posn = %d\n"
-	"n_sign_posn = %d\n",
-	_monetary_locale.int_curr_symbol,
-	_monetary_locale.currency_symbol,
-	_monetary_locale.mon_decimal_point,
-	_monetary_locale.mon_thousands_sep,
-	_monetary_locale.mon_grouping,
-	_monetary_locale.positive_sign,
-	_monetary_locale.negative_sign,
-	_monetary_locale.int_frac_digits[0],
-	_monetary_locale.frac_digits[0],
-	_monetary_locale.p_cs_precedes[0],
-	_monetary_locale.p_sep_by_space[0],
-	_monetary_locale.n_cs_precedes[0],
-	_monetary_locale.n_sep_by_space[0],
-	_monetary_locale.p_sign_posn[0],
-	_monetary_locale.n_sign_posn[0]
-);
+__get_current_monetary_locale (void)
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->monetary ?: (struct lc_monetary_T *) &_C_monetary_locale;
 }
-#endif /* LOCALE_DEBUG */
diff --git a/newlib/libc/locale/lmonetary.h b/newlib/libc/locale/lmonetary.h
index 7aa21e2..98000d6 100644
--- a/newlib/libc/locale/lmonetary.h
+++ b/newlib/libc/locale/lmonetary.h
@@ -68,8 +68,9 @@ struct lc_monetary_T {
 #endif
 };
 
-struct lc_monetary_T *__get_current_monetary_locale(void);
-int	__monetary_load_locale(const char *, void *, const char *);
+struct lc_monetary_T *__get_current_monetary_locale (void);
+int __monetary_load_locale (struct _thr_locale_t *, const char *, void *,
+			    const char *);
 
 __END_DECLS
 
diff --git a/newlib/libc/locale/lnumeric.c b/newlib/libc/locale/lnumeric.c
index ae24470..f74c446 100644
--- a/newlib/libc/locale/lnumeric.c
+++ b/newlib/libc/locale/lnumeric.c
@@ -24,11 +24,9 @@
  * SUCH DAMAGE.
  */
 
-#include <limits.h>
-#include "lnumeric.h"
+#include "setlocale.h"
 #include "ldpart.h"
 
-extern int __nlocale_changed;
 extern const char *__fix_locale_grouping_str(const char *);
 
 #define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
@@ -46,64 +44,60 @@ static const struct lc_numeric_T _C_numeric_locale = {
 #endif
 };
 
+#ifndef __CYGWIN__
 static struct lc_numeric_T _numeric_locale;
 static int	_numeric_using_locale;
 static char	*_numeric_locale_buf;
+#endif
 
 int
-__numeric_load_locale(const char *name , void *f_wctomb, const char *charset)
+__numeric_load_locale (struct _thr_locale_t *locale, const char *name ,
+		       void *f_wctomb, const char *charset)
 {
-	int ret;
+  int ret;
+  struct lc_numeric_T nm;
+  char *bufp = NULL;
 
 #ifdef __CYGWIN__
-	extern int __set_lc_numeric_from_win (const char *,
-					      const struct lc_numeric_T *,
-					      struct lc_numeric_T *, char **,
-					      void *, const char *);
-	int old_numeric_using_locale = _numeric_using_locale;
-	_numeric_using_locale = 0;
-	ret = __set_lc_numeric_from_win (name, &_C_numeric_locale,
-					 &_numeric_locale, &_numeric_locale_buf,
-					 f_wctomb, charset);
-	/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
-	if (ret < 0)
-	  _numeric_using_locale = old_numeric_using_locale;
-	else
-	  {
-	    _numeric_using_locale = ret;
-	    __nlocale_changed = 1;
-	    ret = 0;
-	  }
+  extern int __set_lc_numeric_from_win (const char *,
+					const struct lc_numeric_T *,
+					struct lc_numeric_T *, char **,
+					void *, const char *);
+  ret = __set_lc_numeric_from_win (name, &_C_numeric_locale, &nm, &bufp,
+				   f_wctomb, charset);
+  /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
+  if (ret >= 0)
+    {
+      struct lc_numeric_T *nmp = NULL;
+
+      if (ret > 0)
+	{
+	  nmp = (struct lc_numeric_T *) calloc (1, sizeof *nmp);
+	  if (!nmp)
+	    return -1;
+	  memcpy (nmp, &nm, sizeof *nmp);
+	}
+      locale->numeric = ret == 0 ? NULL : nmp;
+      if (locale->numeric_buf)
+	free (locale->numeric_buf);
+      locale->numeric_buf = bufp;
+      ret = 0;
+    }
 #else
-	__nlocale_changed = 1;
-	ret = __part_load_locale(name, &_numeric_using_locale,
-		_numeric_locale_buf, "LC_NUMERIC",
-		LCNUMERIC_SIZE, LCNUMERIC_SIZE,
-		(const char **)&_numeric_locale);
-	if (ret == 0 && _numeric_using_locale)
-		_numeric_locale.grouping =
-			__fix_locale_grouping_str(_numeric_locale.grouping);
+  ret = __part_load_locale(name, &_numeric_using_locale,
+			   _numeric_locale_buf, "LC_NUMERIC",
+			   LCNUMERIC_SIZE, LCNUMERIC_SIZE,
+			   (const char **)&_numeric_locale);
+  if (ret == 0 && _numeric_using_locale)
+      _numeric_locale.grouping =
+	      __fix_locale_grouping_str(_numeric_locale.grouping);
 #endif
-	return ret;
+  return ret;
 }
 
 struct lc_numeric_T *
-__get_current_numeric_locale(void) {
-
-	return (_numeric_using_locale
-		? &_numeric_locale
-		: (struct lc_numeric_T *)&_C_numeric_locale);
-}
-
-#ifdef LOCALE_DEBUG
-void
-numericdebug(void) {
-printf(	"decimal_point = %s\n"
-	"thousands_sep = %s\n"
-	"grouping = %s\n",
-	_numeric_locale.decimal_point,
-	_numeric_locale.thousands_sep,
-	_numeric_locale.grouping
-);
+__get_current_numeric_locale (void)
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->numeric ?: (struct lc_numeric_T *) &_C_numeric_locale;
 }
-#endif /* LOCALE_DEBUG */
diff --git a/newlib/libc/locale/lnumeric.h b/newlib/libc/locale/lnumeric.h
index 2bd7d97..8a41966 100644
--- a/newlib/libc/locale/lnumeric.h
+++ b/newlib/libc/locale/lnumeric.h
@@ -46,8 +46,9 @@ struct lc_numeric_T {
 #endif
 };
 
-struct lc_numeric_T *__get_current_numeric_locale(void);
-int	__numeric_load_locale(const char *, void *, const char *);
+struct lc_numeric_T *__get_current_numeric_locale (void);
+int __numeric_load_locale (struct _thr_locale_t *, const char *, void *,
+			   const char *);
 
 __END_DECLS
 
diff --git a/newlib/libc/locale/locale.c b/newlib/libc/locale/locale.c
index 33b5359..83d83a5 100644
--- a/newlib/libc/locale/locale.c
+++ b/newlib/libc/locale/locale.c
@@ -172,30 +172,22 @@ No supporting OS subroutines are required.
 
 #include <newlib.h>
 #include <errno.h>
-#include <locale.h>
+#include <ctype.h>
 #include <string.h>
 #include <limits.h>
 #include <reent.h>
 #include <stdlib.h>
 #include <wchar.h>
-#include "lmessages.h"
-#include "lmonetary.h"
-#include "lnumeric.h"
-#include "lctype.h"
-#include "timelocal.h"
+#include "setlocale.h"
 #include "../stdlib/local.h"
 
-#define _LC_LAST      7
-#define ENCODING_LEN 31
-
-#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */
+#ifdef __CYGWIN__ /* Has to be kept available as exported symbol for
+		     backward compatibility.  Set it in setlocale, but
+		     otherwise ignore it.  Applications compiled after
+		     2010 don't use it anymore. */
 int __EXPORT __mb_cur_max = 6;
-#else
-int __EXPORT __mb_cur_max = 1;
 #endif
 
-int __nlocale_changed = 0;
-int __mlocale_changed = 0;
 char *_PathLocale = NULL;
 
 static
@@ -234,44 +226,56 @@ static char *categories[_LC_LAST] = {
  */
 char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE;
 
-/*
- * Current locales for each category
- */
-static char current_categories[_LC_LAST][ENCODING_LEN + 1] = {
-    "C",
-    "C",
-#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */
-    "C.UTF-8",
+struct _thr_locale_t __global_locale =
+{
+  { "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
+#ifdef __CYGWIN__
+  __utf8_wctomb,
+  __utf8_mbtowc,
+#else
+  __ascii_wctomb,
+  __ascii_mbtowc,
+#endif
+  NULL,
+  0,
+#ifndef __HAVE_LOCALE_INFO__
+  "\1",
+  "ASCII",
+  "ASCII",
 #else
-    "C",
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+#ifdef __CYGWIN__
+  NULL,
+#endif
 #endif
-    "C",
-    "C",
-    "C",
-    "C",
 };
 
 /*
- * The locales we are going to try and load
+ * The locales we are going to try and load.  These are only temporary
+ * variables and only used in setlocale.
  */
 static char new_categories[_LC_LAST][ENCODING_LEN + 1];
 static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
 
-static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
+/* Renamed from current_locale_string to make clear this is only the
+   *global* string for setlocale (LC_ALL, NULL).  There's no equivalent
+   functionality for uselocale. */
+static char global_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
 static char *currentlocale(void);
 static char *loadlocale(struct _reent *, int);
 static const char *__get_locale_env(struct _reent *, int);
 
 #endif /* _MB_CAPABLE */
 
-#ifdef __CYGWIN__
-static char lc_ctype_charset[ENCODING_LEN + 1] = "UTF-8";
-#else
-static char lc_ctype_charset[ENCODING_LEN + 1] = "ASCII";
-#endif
-static char lc_message_charset[ENCODING_LEN + 1] = "ASCII";
-static int lc_ctype_cjk_lang = 0;
-
 char *
 _DEFUN(_setlocale_r, (p, category, locale),
        struct _reent *p _AND
@@ -297,13 +301,13 @@ _DEFUN(_setlocale_r, (p, category, locale),
     }
 
   if (locale == NULL)
-    return category != LC_ALL ? current_categories[category] : currentlocale();
+    return category != LC_ALL ? __global_locale.categories[category] : currentlocale();
 
   /*
    * Default to the current locale for everything.
    */
   for (i = 1; i < _LC_LAST; ++i)
-    strcpy (new_categories[i], current_categories[i]);
+    strcpy (new_categories[i], __global_locale.categories[i]);
 
   /*
    * Now go fill up new_categories from the locale argument
@@ -395,7 +399,7 @@ _DEFUN(_setlocale_r, (p, category, locale),
 
   for (i = 1; i < _LC_LAST; ++i)
     {
-      strcpy (saved_categories[i], current_categories[i]);
+      strcpy (saved_categories[i], __global_locale.categories[i]);
       if (loadlocale (p, i) == NULL)
 	{
 	  saverr = p->_errno;
@@ -422,18 +426,18 @@ currentlocale()
 {
         int i;
 
-        (void)strcpy(current_locale_string, current_categories[1]);
+        (void)strcpy(global_locale_string, __global_locale.categories[1]);
 
         for (i = 2; i < _LC_LAST; ++i)
-                if (strcmp(current_categories[1], current_categories[i])) {
+                if (strcmp(__global_locale.categories[1], __global_locale.categories[i])) {
                         for (i = 2; i < _LC_LAST; ++i) {
-                                (void)strcat(current_locale_string, "/");
-                                (void)strcat(current_locale_string,
-                                             current_categories[i]);
+                                (void)strcat(global_locale_string, "/");
+                                (void)strcat(global_locale_string,
+                                             __global_locale.categories[i]);
                         }
                         break;
                 }
-        return (current_locale_string);
+        return (global_locale_string);
 }
 #endif /* _MB_CAPABLE */
 
@@ -441,10 +445,11 @@ currentlocale()
 #ifdef __CYGWIN__
 extern void __set_charset_from_locale (const char *locale, char *charset);
 extern char *__set_locale_from_locale_alias (const char *, char *);
-extern int __collate_load_locale (const char *, void *, const char *);
+extern int __collate_load_locale (struct _thr_locale_t *, const char *, void *,
+				  const char *);
 #endif /* __CYGWIN__ */
 
-extern void __set_ctype (const char *charset);
+extern void __set_ctype (struct _reent *, const char *charset);
 
 static char *
 loadlocale(struct _reent *p, int category)
@@ -455,7 +460,7 @@ loadlocale(struct _reent *p, int category)
      The string must be in one of the allowed locale strings, either
      one in POSIX-style, or one in the old newlib style to maintain
      backward compatibility.  If the local string is correct, the charset
-     is extracted and stored in lc_ctype_charset or lc_message_charset
+     is extracted and stored in ctype_codeset or message_charset
      dependent on the cateogry. */
   char *locale = NULL;
   char charset[ENCODING_LEN + 1];
@@ -468,8 +473,8 @@ loadlocale(struct _reent *p, int category)
   int cjknarrow = 0;
 
   /* Avoid doing everything twice if nothing has changed. */
-  if (!strcmp (new_categories[category], current_categories[category]))
-    return current_categories[category];
+  if (!strcmp (new_categories[category], __global_locale.categories[category]))
+    return __global_locale.categories[category];
 
 #ifdef __CYGWIN__
   /* This additional code handles the case that the incoming locale string
@@ -852,49 +857,61 @@ restart:
   switch (category)
     {
     case LC_CTYPE:
-      strcpy (lc_ctype_charset, charset);
-      __mb_cur_max = mbc_max;
+#ifndef __HAVE_LOCALE_INFO__
+      strcpy (__global_locale.ctype_codeset, charset);
+      __global_locale.mb_cur_max[0] = mbc_max;
+#endif
+#ifdef __CYGWIN__
+      __mb_cur_max = mbc_max;	/* Only for backward compat */
+#endif
       __wctomb = l_wctomb;
       __mbtowc = l_mbtowc;
-      __set_ctype (charset);
+      __set_ctype (NULL, charset);
       /* Determine the width for the "CJK Ambiguous Width" category of
          characters. This is used in wcwidth(). Assume single width for
          single-byte charsets, and double width for multi-byte charsets
          other than UTF-8. For UTF-8, use double width for the East Asian
          languages ("ja", "ko", "zh"), and single width for everything else.
          Single width can also be forced with the "@cjknarrow" modifier. */
-      lc_ctype_cjk_lang = !cjknarrow
+      __global_locale.cjk_lang = !cjknarrow
 			  && mbc_max > 1
 			  && (charset[0] != 'U'
 			      || strncmp (locale, "ja", 2) == 0
 			      || strncmp (locale, "ko", 2) == 0
 			      || strncmp (locale, "zh", 2) == 0);
 #ifdef __HAVE_LOCALE_INFO__
-      ret = __ctype_load_locale (locale, (void *) l_wctomb, charset, mbc_max);
+      ret = __ctype_load_locale (__get_global_locale (), locale,
+				 (void *) l_wctomb, charset, mbc_max);
 #endif /* __HAVE_LOCALE_INFO__ */
       break;
     case LC_MESSAGES:
-      strcpy (lc_message_charset, charset);
 #ifdef __HAVE_LOCALE_INFO__
-      ret = __messages_load_locale (locale, (void *) l_wctomb, charset);
+      ret = __messages_load_locale (__get_global_locale (), locale,
+				    (void *) l_wctomb, charset);
       if (!ret)
+#else
+      strcpy (__global_locale.message_codeset, charset);
 #endif /* __HAVE_LOCALE_INFO__ */
       break;
 #ifdef __HAVE_LOCALE_INFO__
 #ifdef __CYGWIN__
   /* Right now only Cygwin supports a __collate_load_locale function at all. */
     case LC_COLLATE:
-      ret = __collate_load_locale (locale, (void *) l_mbtowc, charset);
+      ret = __collate_load_locale (__get_global_locale (), locale,
+				   (void *) l_mbtowc, charset);
       break;
 #endif
     case LC_MONETARY:
-      ret = __monetary_load_locale (locale, (void *) l_wctomb, charset);
+      ret = __monetary_load_locale (__get_global_locale (), locale,
+				    (void *) l_wctomb, charset);
       break;
     case LC_NUMERIC:
-      ret = __numeric_load_locale (locale, (void *) l_wctomb, charset);
+      ret = __numeric_load_locale (__get_global_locale (), locale,
+				   (void *) l_wctomb, charset);
       break;
     case LC_TIME:
-      ret = __time_load_locale (locale, (void *) l_wctomb, charset);
+      ret = __time_load_locale (__get_global_locale (), locale,
+				(void *) l_wctomb, charset);
       break;
 #endif /* __HAVE_LOCALE_INFO__ */
     default:
@@ -904,7 +921,7 @@ restart:
   if (ret)
     FAIL;
 #endif /* __HAVE_LOCALE_INFO__ */
-  return strcpy(current_categories[category], new_categories[category]);
+  return strcpy(__global_locale.categories[category], new_categories[category]);
 }
 
 static const char *
@@ -934,88 +951,96 @@ __get_locale_env(struct _reent *p, int category)
 char *
 _DEFUN_VOID(__locale_charset)
 {
-#if 0//def __HAVE_LOCALE_INFO__
-  return __get_current_ctype_locale ()->codeset;
+#ifdef __HAVE_LOCALE_INFO__
+  return (char *) __get_current_ctype_locale ()->codeset;
 #else
-  return lc_ctype_charset;
+  return __global_locale.ctype_codeset;
 #endif
 }
 
 int
 _DEFUN_VOID(__locale_mb_cur_max)
 {
-#if 0//def __HAVE_LOCALE_INFO__
+#ifdef __HAVE_LOCALE_INFO__
   return __get_current_ctype_locale ()->mb_cur_max[0];
 #else
-  return __mb_cur_max;
+  return __global_locale.mb_cur_max[0];
 #endif
 }
 
-
 char *
 _DEFUN_VOID(__locale_msgcharset)
 {
 #ifdef __HAVE_LOCALE_INFO__
   return (char *) __get_current_messages_locale ()->codeset;
 #else
-  return lc_message_charset;
+  return (char *) __global_locale.message_codeset;
 #endif
 }
 
 int
 _DEFUN_VOID(__locale_cjk_lang)
 {
-  return lc_ctype_cjk_lang;
+#ifdef __HAVE_LOCALE_INFO__
+  return __get_current_locale ()->cjk_lang;
+#else
+  return __global_locale.cjk_lang;
+#endif
 }
 
+#ifdef __HAVE_LOCALE_INFO__
+char *
+_DEFUN_VOID(__locale_ctype_ptr)
+{
+  /* Only check if the current thread/reent has a locale.  ctype_ptr is unused
+     in __global_locale, rather the global variable __ctype_ptr__ is used. */
+  return __get_locale_r (_REENT) ? __get_locale_r (_REENT)->ctype_ptr
+				 : __ctype_ptr__;
+}
+
+#endif
+
 struct lconv *
 _DEFUN(_localeconv_r, (data), 
       struct _reent *data)
 {
 #ifdef __HAVE_LOCALE_INFO__
-  if (__nlocale_changed)
-    {
-      struct lc_numeric_T *n = __get_current_numeric_locale ();
-      lconv.decimal_point = (char *) n->decimal_point;
-      lconv.thousands_sep = (char *) n->thousands_sep;
-      lconv.grouping = (char *) n->grouping;
-      __nlocale_changed = 0;
-    }
-  if (__mlocale_changed)
-    {
-      struct lc_monetary_T *m = __get_current_monetary_locale ();
-      lconv.int_curr_symbol = (char *) m->int_curr_symbol;
-      lconv.currency_symbol = (char *) m->currency_symbol;
-      lconv.mon_decimal_point = (char *) m->mon_decimal_point;
-      lconv.mon_thousands_sep = (char *) m->mon_thousands_sep;
-      lconv.mon_grouping = (char *) m->mon_grouping;
-      lconv.positive_sign = (char *) m->positive_sign;
-      lconv.negative_sign = (char *) m->negative_sign;
-      lconv.int_frac_digits = m->int_frac_digits[0];
-      lconv.frac_digits = m->frac_digits[0];
-      lconv.p_cs_precedes = m->p_cs_precedes[0];
-      lconv.p_sep_by_space = m->p_sep_by_space[0];
-      lconv.n_cs_precedes = m->n_cs_precedes[0];
-      lconv.n_sep_by_space = m->n_sep_by_space[0];
-      lconv.p_sign_posn = m->p_sign_posn[0];
-      lconv.n_sign_posn = m->n_sign_posn[0];
+  struct lc_numeric_T *n = __get_current_numeric_locale ();
+  struct lc_monetary_T *m = __get_current_monetary_locale ();
+
+  lconv.decimal_point = (char *) n->decimal_point;
+  lconv.thousands_sep = (char *) n->thousands_sep;
+  lconv.grouping = (char *) n->grouping;
+  lconv.int_curr_symbol = (char *) m->int_curr_symbol;
+  lconv.currency_symbol = (char *) m->currency_symbol;
+  lconv.mon_decimal_point = (char *) m->mon_decimal_point;
+  lconv.mon_thousands_sep = (char *) m->mon_thousands_sep;
+  lconv.mon_grouping = (char *) m->mon_grouping;
+  lconv.positive_sign = (char *) m->positive_sign;
+  lconv.negative_sign = (char *) m->negative_sign;
+  lconv.int_frac_digits = m->int_frac_digits[0];
+  lconv.frac_digits = m->frac_digits[0];
+  lconv.p_cs_precedes = m->p_cs_precedes[0];
+  lconv.p_sep_by_space = m->p_sep_by_space[0];
+  lconv.n_cs_precedes = m->n_cs_precedes[0];
+  lconv.n_sep_by_space = m->n_sep_by_space[0];
+  lconv.p_sign_posn = m->p_sign_posn[0];
+  lconv.n_sign_posn = m->n_sign_posn[0];
 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
-      lconv.int_p_cs_precedes = m->int_p_cs_precedes[0];
-      lconv.int_p_sep_by_space = m->int_p_sep_by_space[0];
-      lconv.int_n_cs_precedes = m->int_n_cs_precedes[0];
-      lconv.int_n_sep_by_space = m->int_n_sep_by_space[0];
-      lconv.int_n_sign_posn = m->int_n_sign_posn[0];
-      lconv.int_p_sign_posn = m->int_p_sign_posn[0];
+  lconv.int_p_cs_precedes = m->int_p_cs_precedes[0];
+  lconv.int_p_sep_by_space = m->int_p_sep_by_space[0];
+  lconv.int_n_cs_precedes = m->int_n_cs_precedes[0];
+  lconv.int_n_sep_by_space = m->int_n_sep_by_space[0];
+  lconv.int_n_sign_posn = m->int_n_sign_posn[0];
+  lconv.int_p_sign_posn = m->int_p_sign_posn[0];
 #else /* !__HAVE_LOCALE_INFO_EXTENDED__ */
-      lconv.int_p_cs_precedes = m->p_cs_precedes[0];
-      lconv.int_p_sep_by_space = m->p_sep_by_space[0];
-      lconv.int_n_cs_precedes = m->n_cs_precedes[0];
-      lconv.int_n_sep_by_space = m->n_sep_by_space[0];
-      lconv.int_n_sign_posn = m->n_sign_posn[0];
-      lconv.int_p_sign_posn = m->p_sign_posn[0];
+  lconv.int_p_cs_precedes = m->p_cs_precedes[0];
+  lconv.int_p_sep_by_space = m->p_sep_by_space[0];
+  lconv.int_n_cs_precedes = m->n_cs_precedes[0];
+  lconv.int_n_sep_by_space = m->n_sep_by_space[0];
+  lconv.int_n_sign_posn = m->n_sign_posn[0];
+  lconv.int_p_sign_posn = m->p_sign_posn[0];
 #endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
-      __mlocale_changed = 0;
-    }
 #endif /* __HAVE_LOCALE_INFO__ */
   return (struct lconv *) &lconv;
 }
diff --git a/newlib/libc/locale/nl_langinfo.c b/newlib/libc/locale/nl_langinfo.c
index 4b7e983..3acbc3a 100644
--- a/newlib/libc/locale/nl_langinfo.c
+++ b/newlib/libc/locale/nl_langinfo.c
@@ -32,11 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "lctype.h"
-#include "timelocal.h"
-#include "lnumeric.h"
-#include "lmonetary.h"
-#include "lmessages.h"
+#include "setlocale.h"
 
 #ifndef __CYGWIN__
 #define TRANSITION_PERIOD_HACK
diff --git a/newlib/libc/locale/setlocale.h b/newlib/libc/locale/setlocale.h
index 3eb7698..a4b55a6 100644
--- a/newlib/libc/locale/setlocale.h
+++ b/newlib/libc/locale/setlocale.h
@@ -29,8 +29,89 @@
 #ifndef _SETLOCALE_H_
 #define	_SETLOCALE_H_
 
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include "lctype.h"
+#include "lmessages.h"
+#include "lnumeric.h"
+#include "timelocal.h"
+#include "lmonetary.h"
+
 #define ENCODING_LEN 31
 #define CATEGORY_LEN 11
+#define _LC_LAST      7
+
+#ifdef __CYGWIN__
+struct lc_collate_T;
+#endif
+
+struct _thr_locale_t
+{
+  char			 categories[_LC_LAST][ENCODING_LEN + 1];
+  int			(*__wctomb) (struct _reent *, char *, wchar_t,
+				     const char *, mbstate_t *);
+  int			(*__mbtowc) (struct _reent *, wchar_t *, const char *,
+				     size_t, const char *, mbstate_t *);
+  char			*ctype_ptr; /* Unused in __global_locale */
+  int			 cjk_lang;
+#ifndef __HAVE_LOCALE_INFO__
+  char			 mb_cur_max[2];
+  char			 ctype_codeset[ENCODING_LEN + 1];
+  char			 message_codeset[ENCODING_LEN + 1];
+#else
+  struct lc_ctype_T	*ctype;
+  char			*ctype_buf;
+  struct lc_monetary_T	*monetary;
+  char			*monetary_buf;
+  struct lc_numeric_T	*numeric;
+  char			*numeric_buf;
+  struct lc_time_T	*time;
+  char			*time_buf;
+  struct lc_messages_T	*messages;
+  char			*messages_buf;
+#ifdef __CYGWIN__
+  struct lc_collate_T	*collate;
+#endif
+  /* Append more categories here. */
+#endif
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct _thr_locale_t __global_locale;
+
+/* In POSIX terms the global locale is the process-wide locale.  Use this
+   function to always refer to the global locale. */
+_ELIDABLE_INLINE struct _thr_locale_t *
+__get_global_locale ()
+{
+  return &__global_locale;
+}
+
+/* Per REENT locale.  This is newlib-internal. */
+_ELIDABLE_INLINE struct _thr_locale_t *
+__get_locale_r (struct _reent *r)
+{
+  return r->_locale;
+}
+
+/* In POSIX terms the current locale is the locale used by all functions
+   using locale info without providing a locale as parameter (*_l functions).
+   The current locale is either the locale of the current thread, if the
+   thread called uselocale, or the global locale if not. */
+_ELIDABLE_INLINE struct _thr_locale_t *
+__get_current_locale ()
+{
+  return _REENT->_locale ?: &__global_locale;
+}
+
+#ifdef __cplusplus
+}
+#endif
 
 extern char *_PathLocale;
 
diff --git a/newlib/libc/locale/timelocal.c b/newlib/libc/locale/timelocal.c
index ca2f79b..eda776a 100644
--- a/newlib/libc/locale/timelocal.c
+++ b/newlib/libc/locale/timelocal.c
@@ -30,11 +30,7 @@
 #include <stddef.h>
 
 #include "ldpart.h"
-#include "timelocal.h"
-
-static struct lc_time_T _time_locale;
-static int _time_using_locale;
-static char *time_locale_buf;
+#include "setlocale.h"
 
 #define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
 
@@ -149,40 +145,56 @@ static const struct lc_time_T	_C_time_locale = {
 #endif
 };
 
-struct lc_time_T *
-__get_current_time_locale(void) {
-	return (_time_using_locale
-		? &_time_locale
-		: (struct lc_time_T *)&_C_time_locale);
-}
+#ifndef __CYGWIN__
+static struct lc_time_T _time_locale;
+static int _time_using_locale;
+static char *time_locale_buf;
+#endif
 
 int
-__time_load_locale(const char *name, void *f_wctomb, const char *charset) {
-
-	int	ret;
+__time_load_locale (struct _thr_locale_t *locale, const char *name,
+		    void *f_wctomb, const char *charset)
+{
+  int	ret;
+  struct lc_time_T ti;
+  char *bufp = NULL;
 
 #ifdef __CYGWIN__
-	extern int __set_lc_time_from_win (const char *,
-					   const struct lc_time_T *,
-					   struct lc_time_T *,
-					   char **, void *, const char *);
-	int old_time_using_locale = _time_using_locale;
-	_time_using_locale = 0;
-	ret = __set_lc_time_from_win (name, &_C_time_locale, &_time_locale,
-				      &time_locale_buf, f_wctomb, charset);
-	/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
-	if (ret < 0)
-	  _time_using_locale = old_time_using_locale;
-	else
-	  {
-	    _time_using_locale = ret;
-	    ret = 0;
-	  }
+  extern int __set_lc_time_from_win (const char *, const struct lc_time_T *,
+				     struct lc_time_T *, char **, void *,
+				     const char *);
+  ret = __set_lc_time_from_win (name, &_C_time_locale, &ti, &bufp,
+				f_wctomb, charset);
+  /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
+  if (ret >= 0)
+    {
+      struct lc_time_T *tip = NULL;
+
+      if (ret > 0)
+	{
+	  tip = (struct lc_time_T *) calloc (1, sizeof *tip);
+	  if (!tip)
+	    return -1;
+	  memcpy (tip, &ti, sizeof *tip);
+	}
+      locale->time = ret == 0 ? NULL : tip;
+      if (locale->time_buf)
+	free (locale->time_buf);
+      locale->time_buf = bufp;
+      ret = 0;
+    }
 #else
-	ret = __part_load_locale(name, &_time_using_locale,
-			time_locale_buf, "LC_TIME",
-			LCTIME_SIZE, LCTIME_SIZE,
-			(const char **)&_time_locale);
+  ret = __part_load_locale(name, &_time_using_locale,
+		  time_locale_buf, "LC_TIME",
+		  LCTIME_SIZE, LCTIME_SIZE,
+		  (const char **)&_time_locale);
 #endif
-	return (ret);
+  return (ret);
+}
+
+struct lc_time_T *
+__get_current_time_locale (void)
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->time ?: (struct lc_time_T *) &_C_time_locale;
 }
diff --git a/newlib/libc/locale/timelocal.h b/newlib/libc/locale/timelocal.h
index a0c1ef7..6004ad8 100644
--- a/newlib/libc/locale/timelocal.h
+++ b/newlib/libc/locale/timelocal.h
@@ -77,8 +77,9 @@ struct lc_time_T {
 #endif
 };
 
-struct lc_time_T *__get_current_time_locale(void);
-int	__time_load_locale(const char *, void *, const char *);
+struct lc_time_T *__get_current_time_locale (void);
+int __time_load_locale (struct _thr_locale_t *, const char *, void *,
+			const char *);
 
 __END_DECLS
 
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index d8df00e..acb3fab 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -68,6 +68,7 @@ __isinfd = isinf NOSIGFE
 __isinff = isinff NOSIGFE
 __isnand = isnan NOSIGFE
 __isnanf = isnanf NOSIGFE
+__locale_ctype_ptr NOSIGFE
 __locale_mb_cur_max NOSIGFE
 __main NOSIGFE
 __mempcpy = mempcpy NOSIGFE
diff --git a/winsup/cygwin/ctype.cc b/winsup/cygwin/ctype.cc
index fa8aad3..94de81e 100644
--- a/winsup/cygwin/ctype.cc
+++ b/winsup/cygwin/ctype.cc
@@ -1,6 +1,7 @@
 #include "winsup.h"
 extern "C" {
 #include <ctype.h>
+#include "../locale/setlocale.h"
 #include <stdlib.h>
 #include <wctype.h>
 
@@ -18,9 +19,10 @@ extern const char __ctype_cp[22][128 + 256];		/* Newlib */
 extern const char __ctype_iso[15][128 + 256];		/* Newlib */
 
 void
-__set_ctype (const char *charset)
+__set_ctype (struct _reent *reent, const char *charset)
 {
   int idx;
+  char *ctype_ptr = NULL;
 
   switch (*charset)
     {
@@ -36,8 +38,8 @@ __set_ctype (const char *charset)
 	  memcpy (_ctype_b, __ctype_iso[idx], 128);
 	  memcpy (_ctype_b + 256, __ctype_iso[idx] + 256, 128);
 	}
-      __ctype_ptr__ = (char *) (__ctype_iso[idx] + 127);
-      return;
+      ctype_ptr = (char *) __ctype_iso[idx];
+      break;
     case 'C':
       idx = __cp_index (charset + 2);
       if (idx < 0)
@@ -47,17 +49,24 @@ __set_ctype (const char *charset)
 	  memcpy (_ctype_b, __ctype_cp[idx], 128);
 	  memcpy (_ctype_b + 256, __ctype_cp[idx] + 256, 128);
 	}
-      __ctype_ptr__ = (char *) (__ctype_cp[idx] + 127);
-      return;
+      ctype_ptr = (char *) __ctype_cp[idx];
+      break;
     default:
       break;
     }
-  if (CYGWIN_VERSION_CHECK_FOR_OLD_CTYPE)
+  if (!ctype_ptr)
     {
-      memset (_ctype_b, 0, 128);
-      memset (_ctype_b + 256, 0, 128);
+      if (CYGWIN_VERSION_CHECK_FOR_OLD_CTYPE)
+	{
+	  memset (_ctype_b, 0, 128);
+	  memset (_ctype_b + 256, 0, 128);
+	}
+      ctype_ptr = (char *) _ctype_b;
     }
-  __ctype_ptr__ = (char *) _ctype_b + 127;
+  if (reent)
+    __get_locale_r (reent)->ctype_ptr = ctype_ptr + 127;
+  else
+    __ctype_ptr__ = ctype_ptr + 127;
 }
 
 } /* extern "C" */
diff --git a/winsup/cygwin/nlsfuncs.cc b/winsup/cygwin/nlsfuncs.cc
index 72e5f45..79ab3d1 100644
--- a/winsup/cygwin/nlsfuncs.cc
+++ b/winsup/cygwin/nlsfuncs.cc
@@ -17,11 +17,7 @@ details. */
 #include "cygheap.h"
 #include "tls_pbuf.h"
 /* Internal headers from newlib */
-#include "../locale/timelocal.h"
-#include "../locale/lctype.h"
-#include "../locale/lnumeric.h"
-#include "../locale/lmonetary.h"
-#include "../locale/lmessages.h"
+#include "../locale/setlocale.h"
 #include "lc_msg.h"
 #include "lc_era.h"
 
@@ -689,8 +685,6 @@ __set_lc_time_from_win (const char *name,
   if (tmp != new_lc_time_buf)
     rebase_locale_buf (_time_locale, _time_locale + 1, tmp,
 		       new_lc_time_buf, lc_time_ptr);
-  if (*lc_time_buf)
-    free (*lc_time_buf);
   *lc_time_buf = tmp;
   return 1;
 }
@@ -764,8 +758,6 @@ __set_lc_ctype_from_win (const char *name,
   if (tmp != new_lc_ctype_buf)
     rebase_locale_buf (_ctype_locale, _ctype_locale + 1, tmp,
 		       new_lc_ctype_buf, lc_ctype_ptr);
-  if (*lc_ctype_buf)
-    free (*lc_ctype_buf);
   *lc_ctype_buf = tmp;
   return 1;
 }
@@ -841,8 +833,6 @@ __set_lc_numeric_from_win (const char *name,
   if (tmp != new_lc_numeric_buf)
     rebase_locale_buf (_numeric_locale, _numeric_locale + 1, tmp,
 		       new_lc_numeric_buf, lc_numeric_ptr);
-  if (*lc_numeric_buf)
-    free (*lc_numeric_buf);
   *lc_numeric_buf = tmp;
   return 1;
 }
@@ -981,8 +971,6 @@ __set_lc_monetary_from_win (const char *name,
   if (tmp != new_lc_monetary_buf)
     rebase_locale_buf (_monetary_locale, _monetary_locale + 1, tmp,
 		       new_lc_monetary_buf, lc_monetary_ptr);
-  if (*lc_monetary_buf)
-    free (*lc_monetary_buf);
   *lc_monetary_buf = tmp;
   return 1;
 }
@@ -1083,36 +1071,59 @@ __set_lc_messages_from_win (const char *name,
       _messages_locale->wnostr = (const wchar_t *) wc;
       wcpcpy (wc, msg->nostr);
     }
-  /* Aftermath. */
-  if (*lc_messages_buf)
-    free (*lc_messages_buf);
   *lc_messages_buf = new_lc_messages_buf;
   return 1;
 }
 
-LCID collate_lcid = 0;
-static mbtowc_p collate_mbtowc = __ascii_mbtowc;
-char collate_charset[ENCODING_LEN + 1] = "ASCII";
+struct lc_collate_T
+{
+  LCID lcid;
+  mbtowc_p mbtowc;
+  char codeset[ENCODING_LEN + 1];
+};
 
 /* Called from newlib's setlocale() if category is LC_COLLATE.  Stores
    LC_COLLATE locale information.  This is subsequently accessed by the
    below functions strcoll, strxfrm, wcscoll, wcsxfrm. */
 extern "C" int
-__collate_load_locale (const char *name, mbtowc_p f_mbtowc, const char *charset)
+__collate_load_locale (struct _thr_locale_t *locale, const char *name,
+		       mbtowc_p f_mbtowc, const char *charset)
 {
   LCID lcid = __get_lcid_from_locale (name);
   if (lcid == (LCID) -1)
     return -1;
-  collate_lcid = lcid;
-  collate_mbtowc = f_mbtowc;
-  stpcpy (collate_charset, charset);
+  struct lc_collate_T *cop;
+  if (lcid)
+    {
+      cop = (struct lc_collate_T *) calloc (1, sizeof *cop);
+      if (!cop)
+	return -1;
+      cop->lcid = lcid;
+      cop->mbtowc = f_mbtowc;
+      stpcpy (cop->codeset, charset);
+    }
   return 0;
 }
 
+extern "C" LCID
+__get_current_collate_lcid ()
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->collate ? cur_locale->collate->lcid : 0;
+}
+
 extern "C" const char *
 __get_current_collate_codeset (void)
 {
-  return collate_charset;
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->collate ? cur_locale->collate->codeset : "ASCII";
+}
+
+static mbtowc_p
+__get_current_collate_mbtowc ()
+{
+  struct _thr_locale_t *cur_locale = __get_current_locale ();
+  return cur_locale->collate ? cur_locale->collate->mbtowc : __ascii_mbtowc;
 }
 
 /* We use the Windows functions for locale-specific string comparison and
@@ -1122,6 +1133,7 @@ extern "C" int
 wcscoll (const wchar_t *__restrict ws1, const wchar_t *__restrict ws2)
 {
   int ret;
+  LCID collate_lcid = __get_current_collate_lcid ();
 
   if (!collate_lcid)
     return wcscmp (ws1, ws2);
@@ -1138,11 +1150,14 @@ strcoll (const char *__restrict s1, const char *__restrict s2)
   wchar_t *ws1, *ws2;
   tmp_pathbuf tp;
   int ret;
+  LCID collate_lcid = __get_current_collate_lcid ();
 
   if (!collate_lcid)
     return strcmp (s1, s2);
   /* The ANSI version of CompareString uses the default charset of the lcid,
      so we must use the Unicode version. */
+  mbtowc_p collate_mbtowc = __get_current_collate_mbtowc ();
+  const char *collate_charset = __get_current_collate_codeset ();
   n1 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s1, 0) + 1;
   ws1 = (n1 > NT_MAX_PATH ? (wchar_t *) malloc (n1 * sizeof (wchar_t))
 			  : tp.w_get ());
@@ -1176,6 +1191,7 @@ extern "C" size_t
 wcsxfrm (wchar_t *__restrict ws1, const wchar_t *__restrict ws2, size_t wsn)
 {
   size_t ret;
+  LCID collate_lcid = __get_current_collate_lcid ();
 
   if (!collate_lcid)
     return wcslcpy (ws1, ws2, wsn);
@@ -1211,11 +1227,14 @@ strxfrm (char *__restrict s1, const char *__restrict s2, size_t sn)
   size_t n2;
   wchar_t *ws2;
   tmp_pathbuf tp;
+  LCID collate_lcid = __get_current_collate_lcid ();
 
   if (!collate_lcid)
     return strlcpy (s1, s2, sn);
   /* The ANSI version of LCMapString uses the default charset of the lcid,
      so we must use the Unicode version. */
+  mbtowc_p collate_mbtowc = __get_current_collate_mbtowc ();
+  const char *collate_charset = __get_current_collate_codeset ();
   n2 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s2, 0) + 1;
   ws2 = (n2 > NT_MAX_PATH ? (wchar_t *) malloc (n2 * sizeof (wchar_t))
 			  : tp.w_get ());
diff --git a/winsup/cygwin/regex/regcomp.c b/winsup/cygwin/regex/regcomp.c
index 554b43a..50d5dad 100644
--- a/winsup/cygwin/regex/regcomp.c
+++ b/winsup/cygwin/regex/regcomp.c
@@ -63,9 +63,8 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/regcomp.c,v 1.36 2007/06/11 03:05:54 delp
 #include "cname.h"
 
 #ifdef __CYGWIN__
-/* These are defined in nlsfuncs.cc. */
-extern LCID collate_lcid;
-extern char collate_charset[];
+/* Defined in nlsfuncs.cc. */
+extern LCID __get_current_collate_lcid ();
 #endif
 
 /*
@@ -832,7 +831,7 @@ p_b_term(struct parse *p, cset *cs)
 			CHadd(p, cs, start);
 		else {
 #ifdef __CYGWIN__
-			if (!collate_lcid) {
+			if (!__get_current_collate_lcid ()) {
 #else
 			if (__collate_load_error) {
 #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]