Blame locale/setlocale.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <argz.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
#include "localeinfo.h"
Packit 6c4009
Packit 6c4009
#ifdef NL_CURRENT_INDIRECT
Packit 6c4009
Packit 6c4009
/* For each category declare a special external symbol
Packit 6c4009
   _nl_current_CATEGORY_used with a weak reference.
Packit 6c4009
   This symbol will is defined in lc-CATEGORY.c and will be linked in
Packit 6c4009
   if anything uses _nl_current_CATEGORY (also defined in that module).
Packit 6c4009
   Also use a weak reference for the _nl_current_CATEGORY thread variable.  */
Packit 6c4009
Packit 6c4009
# define DEFINE_CATEGORY(category, category_name, items, a) \
Packit 6c4009
    extern char _nl_current_##category##_used; \
Packit 6c4009
    weak_extern (_nl_current_##category##_used) \
Packit 6c4009
    weak_extern (_nl_current_##category)
Packit 6c4009
# include "categories.def"
Packit 6c4009
# undef	DEFINE_CATEGORY
Packit 6c4009
Packit 6c4009
/* Now define a table of flags based on those special weak symbols' values.
Packit 6c4009
   _nl_current_used[CATEGORY] will be zero if _nl_current_CATEGORY is not
Packit 6c4009
   linked in.  */
Packit 6c4009
static char *const _nl_current_used[] =
Packit 6c4009
  {
Packit 6c4009
# define DEFINE_CATEGORY(category, category_name, items, a) \
Packit 6c4009
    [category] = &_nl_current_##category##_used,
Packit 6c4009
# include "categories.def"
Packit 6c4009
# undef	DEFINE_CATEGORY
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
# define CATEGORY_USED(category)	(_nl_current_used[category] != 0)
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
Packit 6c4009
/* The shared library always loads all the categories,
Packit 6c4009
   and the current global settings are kept in _nl_global_locale.  */
Packit 6c4009
Packit 6c4009
# define CATEGORY_USED(category)	(1)
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Define an array of category names (also the environment variable names).  */
Packit 6c4009
const union catnamestr_t _nl_category_names attribute_hidden =
Packit 6c4009
  {
Packit 6c4009
    {
Packit 6c4009
#define DEFINE_CATEGORY(category, category_name, items, a) \
Packit 6c4009
      category_name,
Packit 6c4009
#include "categories.def"
Packit 6c4009
#undef DEFINE_CATEGORY
Packit 6c4009
    }
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
Packit 6c4009
  {
Packit 6c4009
#define DEFINE_CATEGORY(category, category_name, items, a) \
Packit 6c4009
    [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
Packit 6c4009
#include "categories.def"
Packit 6c4009
#undef DEFINE_CATEGORY
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* An array of their lengths, for convenience.  */
Packit 6c4009
const uint8_t _nl_category_name_sizes[] attribute_hidden =
Packit 6c4009
  {
Packit 6c4009
#define DEFINE_CATEGORY(category, category_name, items, a) \
Packit 6c4009
    [category] = sizeof (category_name) - 1,
Packit 6c4009
#include "categories.def"
Packit 6c4009
#undef	DEFINE_CATEGORY
Packit 6c4009
    [LC_ALL] = sizeof ("LC_ALL") - 1
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef NL_CURRENT_INDIRECT
Packit 6c4009
# define WEAK_POSTLOAD(postload) weak_extern (postload)
Packit 6c4009
#else
Packit 6c4009
# define WEAK_POSTLOAD(postload) /* Need strong refs in static linking.  */
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Declare the postload functions used below.  */
Packit 6c4009
#undef	NO_POSTLOAD
Packit 6c4009
#define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist.  */
Packit 6c4009
#define DEFINE_CATEGORY(category, category_name, items, postload) \
Packit 6c4009
extern void postload (void); WEAK_POSTLOAD (postload)
Packit 6c4009
#include "categories.def"
Packit 6c4009
#undef	DEFINE_CATEGORY
Packit 6c4009
#undef	NO_POSTLOAD
Packit 6c4009
Packit 6c4009
/* Define an array indexed by category of postload functions to call after
Packit 6c4009
   loading and installing that category's data.  */
Packit 6c4009
static void (*const _nl_category_postload[]) (void) =
Packit 6c4009
  {
Packit 6c4009
#define DEFINE_CATEGORY(category, category_name, items, postload) \
Packit 6c4009
    [category] = postload,
Packit 6c4009
#include "categories.def"
Packit 6c4009
#undef	DEFINE_CATEGORY
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Lock for protecting global data.  */
Packit 6c4009
__libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden)
Packit 6c4009
Packit 6c4009
/* Defined in loadmsgcat.c.  */
Packit 6c4009
extern int _nl_msg_cat_cntr;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Use this when we come along an error.  */
Packit 6c4009
#define ERROR_RETURN							      \
Packit 6c4009
  do {									      \
Packit 6c4009
    __set_errno (EINVAL);						      \
Packit 6c4009
    return NULL;							      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Construct a new composite name.  */
Packit 6c4009
static char *
Packit 6c4009
new_composite_name (int category, const char *newnames[__LC_LAST])
Packit 6c4009
{
Packit 6c4009
  size_t last_len = 0;
Packit 6c4009
  size_t cumlen = 0;
Packit 6c4009
  int i;
Packit 6c4009
  char *new, *p;
Packit 6c4009
  int same = 1;
Packit 6c4009
Packit 6c4009
  for (i = 0; i < __LC_LAST; ++i)
Packit 6c4009
    if (i != LC_ALL)
Packit 6c4009
      {
Packit 6c4009
	const char *name = (category == LC_ALL ? newnames[i] :
Packit 6c4009
			    category == i ? newnames[0] :
Packit 6c4009
			    _nl_global_locale.__names[i]);
Packit 6c4009
	last_len = strlen (name);
Packit 6c4009
	cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
Packit 6c4009
	if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0)
Packit 6c4009
	  same = 0;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  if (same)
Packit 6c4009
    {
Packit 6c4009
      /* All the categories use the same name.  */
Packit 6c4009
      if (strcmp (newnames[0], _nl_C_name) == 0
Packit 6c4009
	  || strcmp (newnames[0], _nl_POSIX_name) == 0)
Packit 6c4009
	return (char *) _nl_C_name;
Packit 6c4009
Packit 6c4009
      new = malloc (last_len + 1);
Packit 6c4009
Packit 6c4009
      return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  new = malloc (cumlen);
Packit 6c4009
  if (new == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
  p = new;
Packit 6c4009
  for (i = 0; i < __LC_LAST; ++i)
Packit 6c4009
    if (i != LC_ALL)
Packit 6c4009
      {
Packit 6c4009
	/* Add "CATEGORY=NAME;" to the string.  */
Packit 6c4009
	const char *name = (category == LC_ALL ? newnames[i] :
Packit 6c4009
			    category == i ? newnames[0] :
Packit 6c4009
			    _nl_global_locale.__names[i]);
Packit 6c4009
	p = __stpcpy (p, _nl_category_names.str + _nl_category_name_idxs[i]);
Packit 6c4009
	*p++ = '=';
Packit 6c4009
	p = __stpcpy (p, name);
Packit 6c4009
	*p++ = ';';
Packit 6c4009
      }
Packit 6c4009
  p[-1] = '\0';		/* Clobber the last ';'.  */
Packit 6c4009
  return new;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Put NAME in _nl_global_locale.__names.  */
Packit 6c4009
static void
Packit 6c4009
setname (int category, const char *name)
Packit 6c4009
{
Packit 6c4009
  if (_nl_global_locale.__names[category] == name)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (_nl_global_locale.__names[category] != _nl_C_name)
Packit 6c4009
    free ((char *) _nl_global_locale.__names[category]);
Packit 6c4009
Packit 6c4009
  _nl_global_locale.__names[category] = name;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Put DATA in *_nl_current[CATEGORY].  */
Packit 6c4009
static void
Packit 6c4009
setdata (int category, struct __locale_data *data)
Packit 6c4009
{
Packit 6c4009
  if (CATEGORY_USED (category))
Packit 6c4009
    {
Packit 6c4009
      _nl_global_locale.__locales[category] = data;
Packit 6c4009
      if (_nl_category_postload[category])
Packit 6c4009
	(*_nl_category_postload[category]) ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
setlocale (int category, const char *locale)
Packit 6c4009
{
Packit 6c4009
  char *locale_path;
Packit 6c4009
  size_t locale_path_len;
Packit 6c4009
  const char *locpath_var;
Packit 6c4009
  char *composite;
Packit 6c4009
Packit 6c4009
  /* Sanity check for CATEGORY argument.  */
Packit 6c4009
  if (__builtin_expect (category, 0) < 0
Packit 6c4009
      || __builtin_expect (category, 0) >= __LC_LAST)
Packit 6c4009
    ERROR_RETURN;
Packit 6c4009
Packit 6c4009
  /* Does user want name of current locale?  */
Packit 6c4009
  if (locale == NULL)
Packit 6c4009
    return (char *) _nl_global_locale.__names[category];
Packit 6c4009
Packit 6c4009
  /* Protect global data.  */
Packit 6c4009
  __libc_rwlock_wrlock (__libc_setlocale_lock);
Packit 6c4009
Packit 6c4009
  if (strcmp (locale, _nl_global_locale.__names[category]) == 0)
Packit 6c4009
    {
Packit 6c4009
      /* Changing to the same thing.  */
Packit 6c4009
      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
Packit 6c4009
      return (char *) _nl_global_locale.__names[category];
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We perhaps really have to load some data.  So we determine the
Packit 6c4009
     path in which to look for the data now.  The environment variable
Packit 6c4009
     `LOCPATH' must only be used when the binary has no SUID or SGID
Packit 6c4009
     bit set.  If using the default path, we tell _nl_find_locale
Packit 6c4009
     by passing null and it can check the canonical locale archive.  */
Packit 6c4009
  locale_path = NULL;
Packit 6c4009
  locale_path_len = 0;
Packit 6c4009
Packit 6c4009
  locpath_var = getenv ("LOCPATH");
Packit 6c4009
  if (locpath_var != NULL && locpath_var[0] != '\0')
Packit 6c4009
    {
Packit 6c4009
      if (__argz_create_sep (locpath_var, ':',
Packit 6c4009
			     &locale_path, &locale_path_len) != 0
Packit 6c4009
	  || __argz_add_sep (&locale_path, &locale_path_len,
Packit 6c4009
			     _nl_default_locale_path, ':') != 0)
Packit 6c4009
	{
Packit 6c4009
	  __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (category == LC_ALL)
Packit 6c4009
    {
Packit 6c4009
      /* The user wants to set all categories.  The desired locales
Packit 6c4009
	 for the individual categories can be selected by using a
Packit 6c4009
	 composite locale name.  This is a semi-colon separated list
Packit 6c4009
	 of entries of the form `CATEGORY=VALUE'.  */
Packit 6c4009
      const char *newnames[__LC_LAST];
Packit 6c4009
      struct __locale_data *newdata[__LC_LAST];
Packit 6c4009
      /* Copy of the locale argument, for in-place splitting.  */
Packit 6c4009
      char *locale_copy = NULL;
Packit 6c4009
Packit 6c4009
      /* Set all name pointers to the argument name.  */
Packit 6c4009
      for (category = 0; category < __LC_LAST; ++category)
Packit 6c4009
	if (category != LC_ALL)
Packit 6c4009
	  newnames[category] = (char *) locale;
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (strchr (locale, ';') != NULL))
Packit 6c4009
	{
Packit 6c4009
	  /* This is a composite name.  Make a copy and split it up.  */
Packit 6c4009
	  locale_copy = __strdup (locale);
Packit 6c4009
	  if (__glibc_unlikely (locale_copy == NULL))
Packit 6c4009
	    {
Packit 6c4009
	      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
	      return NULL;
Packit 6c4009
	    }
Packit 6c4009
	  char *np = locale_copy;
Packit 6c4009
	  char *cp;
Packit 6c4009
	  int cnt;
Packit 6c4009
Packit 6c4009
	  while ((cp = strchr (np, '=')) != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      for (cnt = 0; cnt < __LC_LAST; ++cnt)
Packit 6c4009
		if (cnt != LC_ALL
Packit 6c4009
		    && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
Packit 6c4009
		    && (memcmp (np, (_nl_category_names.str
Packit 6c4009
				     + _nl_category_name_idxs[cnt]), cp - np)
Packit 6c4009
			== 0))
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
	      if (cnt == __LC_LAST)
Packit 6c4009
		{
Packit 6c4009
		error_return:
Packit 6c4009
		  __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
		  free (locale_copy);
Packit 6c4009
Packit 6c4009
		  /* Bogus category name.  */
Packit 6c4009
		  ERROR_RETURN;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Found the category this clause sets.  */
Packit 6c4009
	      newnames[cnt] = ++cp;
Packit 6c4009
	      cp = strchr (cp, ';');
Packit 6c4009
	      if (cp != NULL)
Packit 6c4009
		{
Packit 6c4009
		  /* Examine the next clause.  */
Packit 6c4009
		  *cp = '\0';
Packit 6c4009
		  np = cp + 1;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		/* This was the last clause.  We are done.  */
Packit 6c4009
		break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  for (cnt = 0; cnt < __LC_LAST; ++cnt)
Packit 6c4009
	    if (cnt != LC_ALL && newnames[cnt] == locale)
Packit 6c4009
	      /* The composite name did not specify all categories.  */
Packit 6c4009
	      goto error_return;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Load the new data for each category.  */
Packit 6c4009
      while (category-- > 0)
Packit 6c4009
	if (category != LC_ALL)
Packit 6c4009
	  {
Packit 6c4009
	    newdata[category] = _nl_find_locale (locale_path, locale_path_len,
Packit 6c4009
						 category,
Packit 6c4009
						 &newnames[category]);
Packit 6c4009
Packit 6c4009
	    if (newdata[category] == NULL)
Packit 6c4009
	      {
Packit 6c4009
#ifdef NL_CURRENT_INDIRECT
Packit 6c4009
		if (newnames[category] == _nl_C_name)
Packit 6c4009
		  /* Null because it's the weak value of _nl_C_LC_FOO.  */
Packit 6c4009
		  continue;
Packit 6c4009
#endif
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    /* We must not simply free a global locale since we have
Packit 6c4009
	       no control over the usage.  So we mark it as
Packit 6c4009
	       un-deletable.  And yes, the 'if' is needed, the data
Packit 6c4009
	       might be in read-only memory.  */
Packit 6c4009
	    if (newdata[category]->usage_count != UNDELETABLE)
Packit 6c4009
	      newdata[category]->usage_count = UNDELETABLE;
Packit 6c4009
Packit 6c4009
	    /* Make a copy of locale name.  */
Packit 6c4009
	    if (newnames[category] != _nl_C_name)
Packit 6c4009
	      {
Packit 6c4009
		if (strcmp (newnames[category],
Packit 6c4009
			    _nl_global_locale.__names[category]) == 0)
Packit 6c4009
		  newnames[category] = _nl_global_locale.__names[category];
Packit 6c4009
		else
Packit 6c4009
		  {
Packit 6c4009
		    newnames[category] = __strdup (newnames[category]);
Packit 6c4009
		    if (newnames[category] == NULL)
Packit 6c4009
		      break;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
      /* Create new composite name.  */
Packit 6c4009
      composite = (category >= 0
Packit 6c4009
		   ? NULL : new_composite_name (LC_ALL, newnames));
Packit 6c4009
      if (composite != NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* Now we have loaded all the new data.  Put it in place.  */
Packit 6c4009
	  for (category = 0; category < __LC_LAST; ++category)
Packit 6c4009
	    if (category != LC_ALL)
Packit 6c4009
	      {
Packit 6c4009
		setdata (category, newdata[category]);
Packit 6c4009
		setname (category, newnames[category]);
Packit 6c4009
	      }
Packit 6c4009
	  setname (LC_ALL, composite);
Packit 6c4009
Packit 6c4009
	  /* We successfully loaded a new locale.  Let the message catalog
Packit 6c4009
	     functions know about this.  */
Packit 6c4009
	  ++_nl_msg_cat_cntr;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	for (++category; category < __LC_LAST; ++category)
Packit 6c4009
	  if (category != LC_ALL && newnames[category] != _nl_C_name
Packit 6c4009
	      && newnames[category] != _nl_global_locale.__names[category])
Packit 6c4009
	    free ((char *) newnames[category]);
Packit 6c4009
Packit 6c4009
      /* Critical section left.  */
Packit 6c4009
      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
Packit 6c4009
      /* Free the resources.  */
Packit 6c4009
      free (locale_path);
Packit 6c4009
      free (locale_copy);
Packit 6c4009
Packit 6c4009
      return composite;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      struct __locale_data *newdata = NULL;
Packit 6c4009
      const char *newname[1] = { locale };
Packit 6c4009
Packit 6c4009
      if (CATEGORY_USED (category))
Packit 6c4009
	{
Packit 6c4009
	  /* Only actually load the data if anything will use it.  */
Packit 6c4009
	  newdata = _nl_find_locale (locale_path, locale_path_len, category,
Packit 6c4009
				     &newname[0]);
Packit 6c4009
	  if (newdata == NULL)
Packit 6c4009
	    goto abort_single;
Packit 6c4009
Packit 6c4009
	  /* We must not simply free a global locale since we have no
Packit 6c4009
	     control over the usage.  So we mark it as un-deletable.
Packit 6c4009
Packit 6c4009
	     Note: do not remove the `if', it's necessary to cope with
Packit 6c4009
	     the builtin locale data.  */
Packit 6c4009
	  if (newdata->usage_count != UNDELETABLE)
Packit 6c4009
	    newdata->usage_count = UNDELETABLE;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Make a copy of locale name.  */
Packit 6c4009
      if (newname[0] != _nl_C_name)
Packit 6c4009
	{
Packit 6c4009
	  newname[0] = __strdup (newname[0]);
Packit 6c4009
	  if (newname[0] == NULL)
Packit 6c4009
	    goto abort_single;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Create new composite name.  */
Packit 6c4009
      composite = new_composite_name (category, newname);
Packit 6c4009
      if (composite == NULL)
Packit 6c4009
	{
Packit 6c4009
	  if (newname[0] != _nl_C_name)
Packit 6c4009
	    free ((char *) newname[0]);
Packit 6c4009
Packit 6c4009
	  /* Say that we don't have any data loaded.  */
Packit 6c4009
	abort_single:
Packit 6c4009
	  newname[0] = NULL;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (CATEGORY_USED (category))
Packit 6c4009
	    setdata (category, newdata);
Packit 6c4009
Packit 6c4009
	  setname (category, newname[0]);
Packit 6c4009
	  setname (LC_ALL, composite);
Packit 6c4009
Packit 6c4009
	  /* We successfully loaded a new locale.  Let the message catalog
Packit 6c4009
	     functions know about this.  */
Packit 6c4009
	  ++_nl_msg_cat_cntr;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Critical section left.  */
Packit 6c4009
      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit 6c4009
Packit 6c4009
      /* Free the resources (the locale path variable.  */
Packit 6c4009
      free (locale_path);
Packit 6c4009
Packit 6c4009
      return (char *) newname[0];
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (setlocale)
Packit 6c4009
Packit 6c4009
static void __libc_freeres_fn_section
Packit 6c4009
free_category (int category,
Packit 6c4009
	       struct __locale_data *here, struct __locale_data *c_data)
Packit 6c4009
{
Packit 6c4009
  struct loaded_l10nfile *runp = _nl_locale_file_list[category];
Packit 6c4009
Packit 6c4009
  /* If this category is already "C" don't do anything.  */
Packit 6c4009
  if (here != c_data)
Packit 6c4009
    {
Packit 6c4009
      /* We have to be prepared that sometime later we still
Packit 6c4009
	 might need the locale information.  */
Packit 6c4009
      setdata (category, c_data);
Packit 6c4009
      setname (category, _nl_C_name);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (runp != NULL)
Packit 6c4009
    {
Packit 6c4009
      struct loaded_l10nfile *curr = runp;
Packit 6c4009
      struct __locale_data *data = (struct __locale_data *) runp->data;
Packit 6c4009
Packit 6c4009
      if (data != NULL && data != c_data)
Packit 6c4009
	_nl_unload_locale (data);
Packit 6c4009
      runp = runp->next;
Packit 6c4009
      free ((char *) curr->filename);
Packit 6c4009
      free (curr);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This is called from iconv/gconv_db.c's free_mem, as locales must
Packit 6c4009
   be freed before freeing gconv steps arrays.  */
Packit 6c4009
void __libc_freeres_fn_section
Packit 6c4009
_nl_locale_subfreeres (void)
Packit 6c4009
{
Packit 6c4009
#ifdef NL_CURRENT_INDIRECT
Packit 6c4009
  /* We don't use the loop because we want to have individual weak
Packit 6c4009
     symbol references here.  */
Packit 6c4009
# define DEFINE_CATEGORY(category, category_name, items, a)		      \
Packit 6c4009
  if (CATEGORY_USED (category))						      \
Packit 6c4009
    {									      \
Packit 6c4009
      extern struct __locale_data _nl_C_##category;			      \
Packit 6c4009
      weak_extern (_nl_C_##category)					      \
Packit 6c4009
      free_category (category, *_nl_current_##category, &_nl_C_##category);   \
Packit 6c4009
    }
Packit 6c4009
# include "categories.def"
Packit 6c4009
# undef	DEFINE_CATEGORY
Packit 6c4009
#else
Packit 6c4009
  int category;
Packit 6c4009
Packit 6c4009
  for (category = 0; category < __LC_LAST; ++category)
Packit 6c4009
    if (category != LC_ALL)
Packit 6c4009
      free_category (category, _NL_CURRENT_DATA (category),
Packit 6c4009
		     _nl_C_locobj.__locales[category]);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  setname (LC_ALL, _nl_C_name);
Packit 6c4009
Packit 6c4009
  /* This frees the data structures associated with the locale archive.
Packit 6c4009
     The locales from the archive are not in the file list, so we have
Packit 6c4009
     not called _nl_unload_locale on them above.  */
Packit 6c4009
  _nl_archive_subfreeres ();
Packit 6c4009
}