summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-08-04 01:41:55 +0000
committerRoland McGrath <roland@gnu.org>2002-08-04 01:41:55 +0000
commit30c14c31ae6ac7c8db692fc23d0901e4d479f7af (patch)
tree25e403cd215f6d2ca484ae20a51ae41019ce19db
parent509d1b68421a9dc02605540615d241b48bf90a13 (diff)
downloadglibc-30c14c31ae6ac7c8db692fc23d0901e4d479f7af.tar.gz
glibc-30c14c31ae6ac7c8db692fc23d0901e4d479f7af.tar.xz
glibc-30c14c31ae6ac7c8db692fc23d0901e4d479f7af.zip
* locale/setlocale.c (_nl_current_names): Variable moved ...
	* locale/localename.c (_nl_current_names): ... here, new file.
	Make it global, with attribute_hidden.
	* locale/localeinfo.h: Declare it.
	* locale/Makefile (aux): Add localename.
	* locale/localename.c (__current_locale_name): New function.
	* include/locale.h (__current_locale_name): Declare it.
	* intl/dcigettext.c (guess_category_value): Use that instead of
	calling setlocale.

	* locale/locale.h [__USE_GNU] (locale_t): New type alias of __locale_t.
	[__USE_GNU] (newlocale, duplocale, freelocale, uselocale): New decls.
	[__USE_GNU] (LC_GLOBAL_LOCALE): New macro.
	* locale/newlocale.c: Add alias to __ name.
	* locale/duplocale.c: Likewise.
	* locale/freelocale.c: Likewise.
	* locale/uselocale.c: New file.
	* locale/Makefile (routines): Add it.
	* locale/Versions (libc: GLIBC_2.3): New set.
	Add newlocale, duplocale, freelocale, uselocale.
	(libc: GLIBC_PRIVATE): Add __uselocale.

	* locale/localeinfo.h [SHARED]
	(_NL_CURRENT_LOCALE): New macro, defined to fetch a tsd value.
	(_NL_CURRENT_DATA): Define using that.
	(_NL_CURRENT, _NL_CURRENT_WSTR, _NL_CURRENT_WORD): Define using that.
	(_NL_CURRENT_DEFINE): Define to empty.
	[! SHARED]: Decls of _nl_current_CATEGORY and _nl_current
	conditionalized on this.
	* locale/xlocale.c (NL_C_INTIIALIZER): New macro,
	taking initializer of _nl_C_locobj.
	[SHARED] (_nl_global_locale): New variable, using that initializer.
	(_nl_C_locobj): Use new macro for initialzier.
	* locale/setlocale.c [! SHARED] (_nl_current): Conditionalize on this.
	[! SHARED] (CATEGORY_USED): New macro.
	[SHARED] (CATEGORY_USED, _nl_C): New macros.
	(setdata, setlocale): Use that macro instead of examining _nl_current.
	(setdata): Set the slot in _nl_global_locale.
	Conditionalize setting of _nl_current on [! SHARED].
	* locale/findlocale.c [SHARED] (_nl_C): Define as a macro instead of
	declaration as an extern.
	* locale/newlocale.c (__newlocale): Use _nl_C_locobj instead of _nl_C.

	* include/locale.h: Use libc_hidden_proto for setlocale.
	* locale/setlocale.c: Add libc_hidden_def.

	* locale/setlocale.c (free_mem): Use _NL_CURRENT_DATA.
-rw-r--r--ChangeLog48
-rw-r--r--include/locale.h5
-rw-r--r--intl/dcigettext.c2
-rw-r--r--locale/Makefile4
-rw-r--r--locale/Versions7
-rw-r--r--locale/duplocale.c1
-rw-r--r--locale/findlocale.c4
-rw-r--r--locale/freelocale.c1
-rw-r--r--locale/locale.h21
-rw-r--r--locale/localeinfo.h67
-rw-r--r--locale/localename.c42
-rw-r--r--locale/newlocale.c12
-rw-r--r--locale/setlocale.c46
-rw-r--r--locale/uselocale.c52
-rw-r--r--locale/xlocale.c57
15 files changed, 305 insertions, 64 deletions
diff --git a/ChangeLog b/ChangeLog
index e69a58930c..3025aeab19 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,53 @@
 2002-08-03  Roland McGrath  <roland@redhat.com>
 
+	* locale/setlocale.c (_nl_current_names): Variable moved ...
+	* locale/localename.c (_nl_current_names): ... here, new file.
+	Make it global, with attribute_hidden.
+	* locale/localeinfo.h: Declare it.
+	* locale/Makefile (aux): Add localename.
+	* locale/localename.c (__current_locale_name): New function.
+	* include/locale.h (__current_locale_name): Declare it.
+	* intl/dcigettext.c (guess_category_value): Use that instead of
+	calling setlocale.
+
+	* locale/locale.h [__USE_GNU] (locale_t): New type alias of __locale_t.
+	[__USE_GNU] (newlocale, duplocale, freelocale, uselocale): New decls.
+	[__USE_GNU] (LC_GLOBAL_LOCALE): New macro.
+	* locale/newlocale.c: Add alias to __ name.
+	* locale/duplocale.c: Likewise.
+	* locale/freelocale.c: Likewise.
+	* locale/uselocale.c: New file.
+	* locale/Makefile (routines): Add it.
+	* locale/Versions (libc: GLIBC_2.3): New set.
+	Add newlocale, duplocale, freelocale, uselocale.
+	(libc: GLIBC_PRIVATE): Add __uselocale.
+
+	* locale/localeinfo.h [SHARED]
+	(_NL_CURRENT_LOCALE): New macro, defined to fetch a tsd value.
+	(_NL_CURRENT_DATA): Define using that.
+	(_NL_CURRENT, _NL_CURRENT_WSTR, _NL_CURRENT_WORD): Define using that.
+	(_NL_CURRENT_DEFINE): Define to empty.
+	[! SHARED]: Decls of _nl_current_CATEGORY and _nl_current
+	conditionalized on this.
+	* locale/xlocale.c (NL_C_INTIIALIZER): New macro,
+	taking initializer of _nl_C_locobj.
+	[SHARED] (_nl_global_locale): New variable, using that initializer.
+	(_nl_C_locobj): Use new macro for initialzier.
+	* locale/setlocale.c [! SHARED] (_nl_current): Conditionalize on this.
+	[! SHARED] (CATEGORY_USED): New macro.
+	[SHARED] (CATEGORY_USED, _nl_C): New macros.
+	(setdata, setlocale): Use that macro instead of examining _nl_current.
+	(setdata): Set the slot in _nl_global_locale.
+	Conditionalize setting of _nl_current on [! SHARED].
+	* locale/findlocale.c [SHARED] (_nl_C): Define as a macro instead of
+	declaration as an extern.
+	* locale/newlocale.c (__newlocale): Use _nl_C_locobj instead of _nl_C.
+
+	* include/locale.h: Use libc_hidden_proto for setlocale.
+	* locale/setlocale.c: Add libc_hidden_def.
+
+	* locale/setlocale.c (free_mem): Use _NL_CURRENT_DATA.
+
 	* include/search.h: Use libc_hidden_proto for hsearch_r, lfind.
 	* misc/hsearch_r.c: Add libc_hidden_def.
 	* misc/lsearch.c: Likewise.
diff --git a/include/locale.h b/include/locale.h
index a79888139b..b339953a93 100644
--- a/include/locale.h
+++ b/include/locale.h
@@ -1,6 +1,8 @@
 #ifndef	_LOCALE_H
 #include <locale/locale.h>
 
+libc_hidden_proto (setlocale)
+
 /* This has to be changed whenever a new locale is defined.  */
 #define __LC_LAST	13
 
@@ -12,4 +14,7 @@ extern struct __locale_struct _nl_C_locobj attribute_hidden;
 /* Now define the internal interfaces.  */
 extern struct lconv *__localeconv (void);
 
+/* Fetch the name of the current locale set in the given category.  */
+extern const char *__current_locale_name (int category) attribute_hidden;
+
 #endif
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index eb74ac2704..344736e9de 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -1059,7 +1059,7 @@ guess_category_value (category, categoryname)
      `LC_xxx', and `LANG'.  On some systems this can be done by the
      `setlocale' function itself.  */
 #ifdef _LIBC
-  retval = setlocale (category, NULL);
+  retval = __current_locale_name (category);
 #else
   retval = _nl_locale_name (category, categoryname);
 #endif
diff --git a/locale/Makefile b/locale/Makefile
index 3b3af99171..ebcf7bd668 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -37,12 +37,12 @@ distribute	= localeinfo.h categories.def iso-639.def iso-3166.def \
 			      3level.h charmap-dir.h locarchive.c)
 routines	= setlocale findlocale loadlocale localeconv nl_langinfo \
 		  nl_langinfo_l mb_cur_max \
-		  newlocale duplocale freelocale
+		  newlocale duplocale freelocale uselocale
 tests		= tst-C-locale
 categories	= ctype messages monetary numeric time paper name \
 		  address telephone measurement identification collate
 aux		= $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
-		  xlocale
+		  xlocale localename
 others		= localedef locale
 #others-static	= localedef locale
 install-bin	= localedef locale
diff --git a/locale/Versions b/locale/Versions
index 094a392fac..bb875f84a4 100644
--- a/locale/Versions
+++ b/locale/Versions
@@ -46,9 +46,16 @@ libc {
     # missing function from the experimental locale implementation
     __nl_langinfo_l;
   }
+  GLIBC_2.3 {
+    # the new "experimental" interface is now public
+    newlocale; duplocale; freelocale; uselocale;
+  }
   GLIBC_PRIVATE {
     # global variables
     __collate_element_hash; __collate_element_strings;
     __collate_symbol_classes; __collate_symbol_hash; __collate_symbol_strings;
+
+    # this internal name is used by libpthread
+    __uselocale;
   }
 }
diff --git a/locale/duplocale.c b/locale/duplocale.c
index efbacbb724..f8e8e7299e 100644
--- a/locale/duplocale.c
+++ b/locale/duplocale.c
@@ -61,3 +61,4 @@ __duplocale (__locale_t dataset)
 
   return result;
 }
+weak_alias (__duplocale, duplocale)
diff --git a/locale/findlocale.c b/locale/findlocale.c
index 004f93b725..75784bab9f 100644
--- a/locale/findlocale.c
+++ b/locale/findlocale.c
@@ -30,8 +30,12 @@
 #include "../iconv/gconv_charset.h"
 
 
+#ifndef SHARED
 /* Constant data defined in setlocale.c.  */
 extern struct locale_data *const _nl_C[] attribute_hidden;
+#else
+# define _nl_C		(_nl_C_locobj.__locales)
+#endif
 
 
 /* For each category we keep a list of records for the locale files
diff --git a/locale/freelocale.c b/locale/freelocale.c
index 282d83853a..de7e554c84 100644
--- a/locale/freelocale.c
+++ b/locale/freelocale.c
@@ -48,3 +48,4 @@ __freelocale (__locale_t dataset)
   /* It's done.  */
   __libc_lock_unlock (__libc_setlocale_lock);
 }
+weak_alias (__freelocale, freelocale)
diff --git a/locale/locale.h b/locale/locale.h
index 9133038178..34463fd55e 100644
--- a/locale/locale.h
+++ b/locale/locale.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,1995-1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,95-99,2000,01,02 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -140,6 +140,8 @@ extern struct lconv *localeconv (void) __THROW;
 /* Get locale datatype definition.  */
 # include <xlocale.h>
 
+typedef __locale_t locale_t;
+
 /* Return a reference to a data structure representing a set of locale
    datasets.  Unlike for the CATEGORY parameter for `setlocale' the
    CATEGORY_MASK parameter here uses a single bit for each category.
@@ -148,14 +150,31 @@ extern struct lconv *localeconv (void) __THROW;
    record is replaced.  */
 extern __locale_t __newlocale (int __category_mask, __const char *__locale,
 			       __locale_t __base) __THROW;
+extern __locale_t newlocale (int __category_mask, __const char *__locale,
+			     __locale_t __base) __THROW;
 
 /* Return a duplicate of the set of locale in DATASET.  All usage
    counters are increased if necessary.  */
 extern __locale_t __duplocale (__locale_t __dataset) __THROW;
+extern __locale_t duplocale (__locale_t __dataset) __THROW;
 
 /* Free the data associated with a locale dataset previously returned
    by a call to `setlocale_r'.  */
 extern void __freelocale (__locale_t __dataset) __THROW;
+extern void freelocale (__locale_t __dataset) __THROW;
+
+/* Switch the current thread's locale to DATASET.
+   If DATASET is null, instead just return the current setting.
+   The special value LC_GLOBAL_LOCALE is the initial setting
+   for all threads and can also be installed any time, meaning
+   the thread uses the global settings controlled by `setlocale'.  */
+extern __locale_t __uselocale (__locale_t __dataset) __THROW;
+extern __locale_t uselocale (__locale_t __dataset) __THROW;
+
+/* This value can be passed to `uselocale' and may be returned by it.
+   Passing this value to any other function has undefined behavior.  */
+# define LC_GLOBAL_LOCALE	((__locale_t) -1L)
+
 #endif
 
 __END_DECLS
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index 3a43469c84..97471e9be5 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -138,18 +138,8 @@ enum
 #define _ISCTYPE(c, desc) \
   (((((const uint32_t *) (desc)) - 8)[(c) >> 5] >> ((c) & 0x1f)) & 1)
 
-
-/* For each category declare the variable for the current locale data.  */
-/* XXX _nl_current_LC_CTYPE and _nl_current_LC_COLLATE were exported
-   but where are they used?  */
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-extern struct locale_data *_nl_current_##category attribute_hidden;
-#include "categories.def"
-#undef	DEFINE_CATEGORY
-
 extern const char *const _nl_category_names[__LC_LAST] attribute_hidden;
 extern const size_t _nl_category_name_sizes[__LC_LAST] attribute_hidden;
-extern struct locale_data * *const _nl_current[__LC_LAST] attribute_hidden;
 
 /* Name of the standard locales.  */
 extern const char _nl_C_name[] attribute_hidden;
@@ -158,9 +148,25 @@ extern const char _nl_POSIX_name[] attribute_hidden;
 /* The standard codeset.  */
 extern const char _nl_C_codeset[] attribute_hidden;
 
+/* Name of current locale for each individual category.
+   Each is malloc'd unless it is _nl_C_name.  */
+extern const char *_nl_current_names[] attribute_hidden;
+
+#ifndef SHARED
+
+/* For each category declare the variable for the current locale data.  */
+/* XXX _nl_current_LC_CTYPE and _nl_current_LC_COLLATE were exported
+   but where are they used?  */
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+extern struct locale_data *_nl_current_##category attribute_hidden;
+#include "categories.def"
+#undef	DEFINE_CATEGORY
+extern struct locale_data * *const _nl_current[__LC_LAST] attribute_hidden;
+
 /* Return a pointer to the current `struct locale_data' for CATEGORY.  */
-#define _NL_CURRENT_DATA(category)	\
-  ((const struct locale_data *) _nl_current_##category)
+#define _NL_CURRENT_DATA(category)	_nl_current_##category
+/* Hackety hack, don't talk back.  */
+#define _nl_current_category		(*_nl_current[category])
 
 /* Extract the current CATEGORY locale's string for ITEM.  */
 #define _NL_CURRENT(category, item) \
@@ -179,6 +185,43 @@ extern const char _nl_C_codeset[] attribute_hidden;
   extern struct locale_data _nl_C_##category attribute_hidden; \
   struct locale_data *_nl_current_##category = &_nl_C_##category
 
+#else
+
+/* All categories are always loaded in the shared library, so there is no
+   point in having lots of separate symbols for linking.  */
+
+# include <bits/libc-tsd.h>
+
+__libc_tsd_define (extern, LOCALE)
+
+extern struct __locale_struct _nl_global_locale attribute_hidden;
+
+# define _NL_CURRENT_LOCALE \
+  ((__locale_t) __libc_tsd_get (LOCALE))
+
+/* Return a pointer to the current `struct locale_data' for CATEGORY.  */
+# define _NL_CURRENT_DATA(category) \
+  (_NL_CURRENT_LOCALE->__locales[category])
+
+/* Extract the current CATEGORY locale's string for ITEM.  */
+# define _NL_CURRENT(category, item) \
+  (_NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].string)
+
+/* Extract the current CATEGORY locale's string for ITEM.  */
+# define _NL_CURRENT_WSTR(category, item) \
+  ((wchar_t *) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].wstr)
+
+/* Extract the current CATEGORY locale's word for ITEM.  */
+# define _NL_CURRENT_WORD(category, item) \
+  (_NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].word)
+
+/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY.  */
+# define _NL_CURRENT_DEFINE(category) \
+  /* No per-category variable here. */
+
+#endif
+
+
 /* Load the locale data for CATEGORY from the file specified by *NAME.
    If *NAME is "", use environment variables as specified by POSIX,
    and fill in *NAME with the actual name used.  The directories
diff --git a/locale/localename.c b/locale/localename.c
new file mode 100644
index 0000000000..045cc712d2
--- /dev/null
+++ b/locale/localename.c
@@ -0,0 +1,42 @@
+/* current locale setting names
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "localeinfo.h"
+
+/* Name of current locale for each individual category.
+   Each is malloc'd unless it is _nl_C_name.  */
+const char *_nl_current_names[] attribute_hidden =
+  {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+    [category] = _nl_C_name,
+#include "categories.def"
+#undef	DEFINE_CATEGORY
+    [LC_ALL] = _nl_C_name		/* For LC_ALL.  */
+  };
+
+const char *
+attribute_hidden
+__current_locale_name (int category)
+{
+#if 0
+  return _NL_CURRENT_DATA (category)->name;
+#else
+  return _nl_current_names[category];
+#endif
+}
diff --git a/locale/newlocale.c b/locale/newlocale.c
index 6306ba2a8a..1442f86e81 100644
--- a/locale/newlocale.c
+++ b/locale/newlocale.c
@@ -26,9 +26,6 @@
 #include "localeinfo.h"
 
 
-/* Constant data defined in setlocale.c.  */
-extern struct locale_data *const _nl_C[] attribute_hidden;
-
 /* Use this when we come along an error.  */
 #define ERROR_RETURN							      \
   do {									      \
@@ -65,12 +62,8 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
   if (base != NULL)
     result = *base;
   else
-    {
-      /* Fill with pointers to C locale data.  */
-      for (cnt = 0; cnt < __LC_LAST; ++cnt)
-	if (cnt != LC_ALL)
-	  result.__locales[cnt] = _nl_C[cnt];
-    }
+    /* Fill with pointers to C locale data.  */
+    result = _nl_C_locobj;
 
   /* If no category is to be set we return BASE if available or a
      dataset using the C locale data.  */
@@ -184,3 +177,4 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
 
   return result_ptr;
 }
+weak_alias (__newlocale, newlocale)
diff --git a/locale/setlocale.c b/locale/setlocale.c
index 87573024d3..50963d152c 100644
--- a/locale/setlocale.c
+++ b/locale/setlocale.c
@@ -27,6 +27,8 @@
 
 #include "localeinfo.h"
 
+#ifndef SHARED
+
 /* For each category declare two external variables (with weak references):
      extern const struct locale_data *_nl_current_CATEGORY;
    This points to the current locale's in-core data for CATEGORY.
@@ -35,6 +37,8 @@
    Both are weak references; if &_nl_current_CATEGORY is zero,
    then nothing is using the locale data.  */
 #define DEFINE_CATEGORY(category, category_name, items, a) \
+weak_extern (_nl_current_##category)					      \
+weak_extern (_nl_C_##category)						      \
 extern struct locale_data *_nl_current_##category;			      \
 extern struct locale_data _nl_C_##category;
 #include "categories.def"
@@ -63,6 +67,19 @@ struct locale_data *const _nl_C[] attribute_hidden =
 #undef	DEFINE_CATEGORY
   };
 
+# define CATEGORY_USED(category)	(_nl_current[category] != NULL)
+
+#else
+
+/* The shared library always loads all the categories,
+   and the current global settings are kept in _nl_global_locale.  */
+
+# define _nl_C		(_nl_C_locobj.__locales)
+
+# define CATEGORY_USED(category)	(1)
+
+#endif
+
 
 /* Define an array of category names (also the environment variable names),
    indexed by integral category.  */
@@ -105,18 +122,6 @@ static void (*const _nl_category_postload[]) (void) =
   };
 
 
-/* Name of current locale for each individual category.
-   Each is malloc'd unless it is nl_C_name.  */
-static const char *_nl_current_names[] =
-  {
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-    [category] = _nl_C_name,
-#include "categories.def"
-#undef	DEFINE_CATEGORY
-    [LC_ALL] = _nl_C_name		/* For LC_ALL.  */
-  };
-
-
 /* Lock for protecting global data.  */
 __libc_lock_define_initialized (, __libc_setlocale_lock attribute_hidden)
 
@@ -200,20 +205,24 @@ setname (int category, const char *name)
   _nl_current_names[category] = name;
 }
 
-
 /* Put DATA in *_nl_current[CATEGORY].  */
 static inline void
 setdata (int category, struct locale_data *data)
 {
-  if (_nl_current[category] != NULL)
+  if (CATEGORY_USED (category))
     {
+#ifdef SHARED
+      _nl_global_locale.__locales[category] = data;
+#endif
+#ifndef SHARED
+# warning when uselocale exists it will need the line above too
       *_nl_current[category] = data;
+#endif
       if (_nl_category_postload[category])
 	(*_nl_category_postload[category]) ();
     }
 }
 
-
 char *
 setlocale (int category, const char *locale)
 {
@@ -371,7 +380,7 @@ setlocale (int category, const char *locale)
       /* Protect global data.  */
       __libc_lock_lock (__libc_setlocale_lock);
 
-      if (_nl_current[category] != NULL)
+      if (CATEGORY_USED (category))
 	{
 	  /* Only actually load the data if anything will use it.  */
 	  newdata = _nl_find_locale (locale_path, locale_path_len, category,
@@ -409,7 +418,7 @@ setlocale (int category, const char *locale)
 	}
       else
 	{
-	  if (_nl_current[category] != NULL)
+	  if (CATEGORY_USED (category))
 	    setdata (category, newdata);
 
 	  setname (category, newname[0]);
@@ -429,6 +438,7 @@ setlocale (int category, const char *locale)
       return (char *) newname[0];
     }
 }
+libc_hidden_def (setlocale)
 
 static void __attribute__ ((unused))
 free_mem (void)
@@ -438,7 +448,7 @@ free_mem (void)
   for (category = 0; category < __LC_LAST; ++category)
     if (category != LC_ALL)
       {
-	struct locale_data *here = *_nl_current[category];
+	struct locale_data *here = _NL_CURRENT_DATA (category);
 	struct loaded_l10nfile *runp = _nl_locale_file_list[category];
 
 	/* If this category is already "C" don't do anything.  */
diff --git a/locale/uselocale.c b/locale/uselocale.c
new file mode 100644
index 0000000000..1e819381de
--- /dev/null
+++ b/locale/uselocale.c
@@ -0,0 +1,52 @@
+/* uselocale -- fetch and set the current per-thread locale
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <locale.h>
+#include "localeinfo.h"
+
+#ifdef SHARED
+
+/* Switch the current thread's locale to DATASET.
+   If DATASET is null, instead just return the current setting.
+   The special value LC_GLOBAL_LOCALE is the initial setting
+   for all threads, and means the thread uses the global
+   setting controlled by `setlocale'.  */
+locale_t
+__uselocale (locale_t newloc)
+{
+  if (newloc == NULL)
+    {
+      locale_t loc = __libc_tsd_get (LOCALE);
+      return loc == &_nl_global_locale ? LC_GLOBAL_LOCALE : loc;
+    }
+  if (newloc == LC_GLOBAL_LOCALE)
+    {
+      __libc_tsd_set (LOCALE, &_nl_global_locale);
+      return LC_GLOBAL_LOCALE;
+    }
+  __libc_tsd_set (LOCALE, newloc);
+  return newloc;
+}
+weak_alias (__uselocale, uselocale)
+
+#else
+
+# warning uselocale not implemented for static linking yet
+
+#endif
diff --git a/locale/xlocale.c b/locale/xlocale.c
index 79ec548473..daea563ff1 100644
--- a/locale/xlocale.c
+++ b/locale/xlocale.c
@@ -32,24 +32,39 @@ extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
 extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
 
 
-struct __locale_struct _nl_C_locobj attribute_hidden =
-  {
-    .__locales =
-    {
-      [LC_CTYPE] = &_nl_C_LC_CTYPE,
-      [LC_NUMERIC] = &_nl_C_LC_NUMERIC,
-      [LC_TIME] = &_nl_C_LC_TIME,
-      [LC_COLLATE] = &_nl_C_LC_COLLATE,
-      [LC_MONETARY] = &_nl_C_LC_MONETARY,
-      [LC_MESSAGES] = &_nl_C_LC_MESSAGES,
-      [LC_PAPER] = &_nl_C_LC_PAPER,
-      [LC_NAME] = &_nl_C_LC_NAME,
-      [LC_ADDRESS] = &_nl_C_LC_ADDRESS,
-      [LC_TELEPHONE] = &_nl_C_LC_TELEPHONE,
-      [LC_MEASUREMENT] = &_nl_C_LC_MEASUREMENT,
-      [LC_IDENTIFICATION] = &_nl_C_LC_IDENTIFICATION
-    },
-    .__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128,
-    .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
-    .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
-  };
+#define NL_C_INITIALIZER						      \
+  {									      \
+    .__locales =							      \
+    {									      \
+      [LC_CTYPE] = &_nl_C_LC_CTYPE,					      \
+      [LC_NUMERIC] = &_nl_C_LC_NUMERIC,					      \
+      [LC_TIME] = &_nl_C_LC_TIME,					      \
+      [LC_COLLATE] = &_nl_C_LC_COLLATE,					      \
+      [LC_MONETARY] = &_nl_C_LC_MONETARY,				      \
+      [LC_MESSAGES] = &_nl_C_LC_MESSAGES,				      \
+      [LC_PAPER] = &_nl_C_LC_PAPER,					      \
+      [LC_NAME] = &_nl_C_LC_NAME,					      \
+      [LC_ADDRESS] = &_nl_C_LC_ADDRESS,					      \
+      [LC_TELEPHONE] = &_nl_C_LC_TELEPHONE,				      \
+      [LC_MEASUREMENT] = &_nl_C_LC_MEASUREMENT,				      \
+      [LC_IDENTIFICATION] = &_nl_C_LC_IDENTIFICATION			      \
+    },									      \
+    .__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128,     \
+    .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,	      \
+    .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128	      \
+  }
+
+struct __locale_struct _nl_C_locobj attribute_hidden = NL_C_INITIALIZER;
+
+#ifdef SHARED
+struct __locale_struct _nl_global_locale attribute_hidden = NL_C_INITIALIZER;
+
+# if USE_TLS && HAVE___THREAD
+/* The tsd macros don't permit an initializer.  */
+__thread void *__libc_tsd_LOCALE = &_nl_global_locale;
+# else
+__libc_tsd_define (, LOCALE)
+void *__libc_tsd_LOCALE_data = &_nl_global_locale;
+# endif
+
+#endif