Blame locale/setlocale.c

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