Back to index

glibc  2.9
Defines | Functions | Variables
setlocale.c File Reference
#include <alloca.h>
#include <argz.h>
#include <errno.h>
#include <bits/libc-lock.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "localeinfo.h"
#include "categories.def"

Go to the source code of this file.

Defines

#define CATEGORY_USED(category)   (1)
#define DEFINE_CATEGORY(category, category_name, items, a)   category_name,
#define DEFINE_CATEGORY(category, category_name, items, a)   [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
#define DEFINE_CATEGORY(category, category_name, items, a)   [category] = sizeof (category_name) - 1,
#define WEAK_POSTLOAD(postload)   /* Need strong refs in static linking. */
#define NO_POSTLOAD   _nl_postload_ctype /* Harmless thing known to exist. */
#define DEFINE_CATEGORY(category, category_name, items, postload)   extern void postload (void); WEAK_POSTLOAD (postload)
#define DEFINE_CATEGORY(category, category_name, items, postload)   [category] = postload,
#define ERROR_RETURN

Functions

 __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden) extern int _nl_msg_cat_cntr
static char * new_composite_name (int category, const char *newnames[__LC_LAST])
static void setname (int category, const char *name)
static void setdata (int category, struct locale_data *data)
char * setlocale (int category, const char *locale)
 libc_hidden_def (setlocale)
void __libc_freeres_fn_section _nl_locale_subfreeres (void)

Variables

const uint8_t
_nl_category_name_idxs[__LC_LAST
attribute_hidden
static void(*const _nl_category_postload [])(void)

Define Documentation

#define CATEGORY_USED (   category)    (1)

Definition at line 64 of file setlocale.c.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  a 
)    category_name,

Definition at line 108 of file setlocale.c.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  a 
)    [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),

Definition at line 108 of file setlocale.c.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  a 
)    [category] = sizeof (category_name) - 1,

Definition at line 108 of file setlocale.c.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  postload 
)    extern void postload (void); WEAK_POSTLOAD (postload)

Definition at line 108 of file setlocale.c.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  postload 
)    [category] = postload,

Definition at line 108 of file setlocale.c.

#define ERROR_RETURN
Value:
do {                                                                 \
    __set_errno (EINVAL);                                            \
    return NULL;                                                     \
  } while (0)

Definition at line 133 of file setlocale.c.

#define NO_POSTLOAD   _nl_postload_ctype /* Harmless thing known to exist. */

Definition at line 107 of file setlocale.c.

#define WEAK_POSTLOAD (   postload)    /* Need strong refs in static linking. */

Definition at line 102 of file setlocale.c.


Function Documentation

__libc_rwlock_define_initialized ( __libc_setlocale_lock  attribute_hidden)

Here is the caller graph for this function:

Definition at line 497 of file setlocale.c.

{
#ifdef NL_CURRENT_INDIRECT
  /* We don't use the loop because we want to have individual weak
     symbol references here.  */
# define DEFINE_CATEGORY(category, category_name, items, a)                 \
  if (CATEGORY_USED (category))                                             \
    {                                                                \
      extern struct locale_data _nl_C_##category;                           \
      weak_extern (_nl_C_##category)                                        \
      free_category (category, *_nl_current_##category, &_nl_C_##category);   \
    }
# include "categories.def"
# undef       DEFINE_CATEGORY
#else
  int category;

  for (category = 0; category < __LC_LAST; ++category)
    if (category != LC_ALL)
      free_category (category, _NL_CURRENT_DATA (category),
                   _nl_C_locobj.__locales[category]);
#endif

  setname (LC_ALL, _nl_C_name);

  /* This frees the data structures associated with the locale archive.
     The locales from the archive are not in the file list, so we have
     not called _nl_unload_locale on them above.  */
  _nl_archive_subfreeres ();
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 464 of file setlocale.c.

{
  struct loaded_l10nfile *runp = _nl_locale_file_list[category];

  /* If this category is already "C" don't do anything.  */
  if (here != c_data)
    {
      /* We have to be prepared that sometime later we still
        might need the locale information.  */
      setdata (category, c_data);
      setname (category, _nl_C_name);
    }

  while (runp != NULL)
    {
      struct loaded_l10nfile *curr = runp;
      struct locale_data *data = (struct locale_data *) runp->data;

      if (data != NULL && data != c_data)
       _nl_unload_locale (data);
      runp = runp->next;
      free ((char *) curr->filename);
      free (curr);
    }
}

Here is the call graph for this function:

static char* new_composite_name ( int  category,
const char *  newnames[__LC_LAST] 
) [static]

Definition at line 142 of file setlocale.c.

{
  size_t last_len = 0;
  size_t cumlen = 0;
  int i;
  char *new, *p;
  int same = 1;

  for (i = 0; i < __LC_LAST; ++i)
    if (i != LC_ALL)
      {
       const char *name = (category == LC_ALL ? newnames[i] :
                         category == i ? newnames[0] :
                         _nl_global_locale.__names[i]);
       last_len = strlen (name);
       cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
       if (i > 0 && same && strcmp (name, newnames[0]) != 0)
         same = 0;
      }

  if (same)
    {
      /* All the categories use the same name.  */
      if (strcmp (newnames[0], _nl_C_name) == 0
         || strcmp (newnames[0], _nl_POSIX_name) == 0)
       return (char *) _nl_C_name;

      new = malloc (last_len + 1);

      return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1);
    }

  new = malloc (cumlen);
  if (new == NULL)
    return NULL;
  p = new;
  for (i = 0; i < __LC_LAST; ++i)
    if (i != LC_ALL)
      {
       /* Add "CATEGORY=NAME;" to the string.  */
       const char *name = (category == LC_ALL ? newnames[i] :
                         category == i ? newnames[0] :
                         _nl_global_locale.__names[i]);
       p = __stpcpy (p, _nl_category_names.str + _nl_category_name_idxs[i]);
       *p++ = '=';
       p = __stpcpy (p, name);
       *p++ = ';';
      }
  p[-1] = '\0';             /* Clobber the last ';'.  */
  return new;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void setdata ( int  category,
struct locale_data data 
) [inline, static]

Definition at line 210 of file setlocale.c.

{
  if (CATEGORY_USED (category))
    {
      _nl_global_locale.__locales[category] = data;
      if (_nl_category_postload[category])
       (*_nl_category_postload[category]) ();
    }
}

Here is the caller graph for this function:

char* setlocale ( int  category,
const char *  locale 
)

Definition at line 221 of file setlocale.c.

{
  char *locale_path;
  size_t locale_path_len;
  const char *locpath_var;
  char *composite;

  /* Sanity check for CATEGORY argument.  */
  if (__builtin_expect (category, 0) < 0
      || __builtin_expect (category, 0) >= __LC_LAST)
    ERROR_RETURN;

  /* Does user want name of current locale?  */
  if (locale == NULL)
    return (char *) _nl_global_locale.__names[category];

  /* Protect global data.  */
  __libc_rwlock_wrlock (__libc_setlocale_lock);

  if (strcmp (locale, _nl_global_locale.__names[category]) == 0)
    {
      /* Changing to the same thing.  */
      __libc_rwlock_unlock (__libc_setlocale_lock);

      return (char *) _nl_global_locale.__names[category];
    }

  /* We perhaps really have to load some data.  So we determine the
     path in which to look for the data now.  The environment variable
     `LOCPATH' must only be used when the binary has no SUID or SGID
     bit set.  If using the default path, we tell _nl_find_locale
     by passing null and it can check the canonical locale archive.  */
  locale_path = NULL;
  locale_path_len = 0;

  locpath_var = getenv ("LOCPATH");
  if (locpath_var != NULL && locpath_var[0] != '\0')
    {
      if (__argz_create_sep (locpath_var, ':',
                          &locale_path, &locale_path_len) != 0
         || __argz_add_sep (&locale_path, &locale_path_len,
                          _nl_default_locale_path, ':') != 0)
       {
         __libc_rwlock_unlock (__libc_setlocale_lock);
         return NULL;
       }
    }

  if (category == LC_ALL)
    {
      /* The user wants to set all categories.  The desired locales
        for the individual categories can be selected by using a
        composite locale name.  This is a semi-colon separated list
        of entries of the form `CATEGORY=VALUE'.  */
      const char *newnames[__LC_LAST];
      struct locale_data *newdata[__LC_LAST];

      /* Set all name pointers to the argument name.  */
      for (category = 0; category < __LC_LAST; ++category)
       if (category != LC_ALL)
         newnames[category] = (char *) locale;

      if (__builtin_expect (strchr (locale, ';') != NULL, 0))
       {
         /* This is a composite name.  Make a copy and split it up.  */
         char *np = strdupa (locale);
         char *cp;
         int cnt;

         while ((cp = strchr (np, '=')) != NULL)
           {
             for (cnt = 0; cnt < __LC_LAST; ++cnt)
              if (cnt != LC_ALL
                  && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
                  && (memcmp (np, (_nl_category_names.str
                                 + _nl_category_name_idxs[cnt]), cp - np)
                     == 0))
                break;

             if (cnt == __LC_LAST)
              {
              error_return:
                __libc_rwlock_unlock (__libc_setlocale_lock);

                /* Bogus category name.  */
                ERROR_RETURN;
              }

             /* Found the category this clause sets.  */
             newnames[cnt] = ++cp;
             cp = strchr (cp, ';');
             if (cp != NULL)
              {
                /* Examine the next clause.  */
                *cp = '\0';
                np = cp + 1;
              }
             else
              /* This was the last clause.  We are done.  */
              break;
           }

         for (cnt = 0; cnt < __LC_LAST; ++cnt)
           if (cnt != LC_ALL && newnames[cnt] == locale)
             /* The composite name did not specify all categories.  */
             goto error_return;
       }

      /* Load the new data for each category.  */
      while (category-- > 0)
       if (category != LC_ALL)
         {
           newdata[category] = _nl_find_locale (locale_path, locale_path_len,
                                           category,
                                           &newnames[category]);

           if (newdata[category] == NULL)
             {
#ifdef NL_CURRENT_INDIRECT
              if (newnames[category] == _nl_C_name)
                /* Null because it's the weak value of _nl_C_LC_FOO.  */
                continue;
#endif
              break;
             }

           /* We must not simply free a global locale since we have
              no control over the usage.  So we mark it as
              un-deletable.  And yes, the 'if' is needed, the data
              might be in read-only memory.  */
           if (newdata[category]->usage_count != UNDELETABLE)
             newdata[category]->usage_count = UNDELETABLE;

           /* Make a copy of locale name.  */
           if (newnames[category] != _nl_C_name)
             {
              if (strcmp (newnames[category],
                         _nl_global_locale.__names[category]) == 0)
                newnames[category] = _nl_global_locale.__names[category];
              else
                {
                  newnames[category] = __strdup (newnames[category]);
                  if (newnames[category] == NULL)
                    break;
                }
             }
         }

      /* Create new composite name.  */
      composite = (category >= 0
                 ? NULL : new_composite_name (LC_ALL, newnames));
      if (composite != NULL)
       {
         /* Now we have loaded all the new data.  Put it in place.  */
         for (category = 0; category < __LC_LAST; ++category)
           if (category != LC_ALL)
             {
              setdata (category, newdata[category]);
              setname (category, newnames[category]);
             }
         setname (LC_ALL, composite);

         /* We successfully loaded a new locale.  Let the message catalog
            functions know about this.  */
         ++_nl_msg_cat_cntr;
       }
      else
       for (++category; category < __LC_LAST; ++category)
         if (category != LC_ALL && newnames[category] != _nl_C_name
             && newnames[category] != _nl_global_locale.__names[category])
           free ((char *) newnames[category]);

      /* Critical section left.  */
      __libc_rwlock_unlock (__libc_setlocale_lock);

      /* Free the resources (the locale path variable).  */
      free (locale_path);

      return composite;
    }
  else
    {
      struct locale_data *newdata = NULL;
      const char *newname[1] = { locale };

      if (CATEGORY_USED (category))
       {
         /* Only actually load the data if anything will use it.  */
         newdata = _nl_find_locale (locale_path, locale_path_len, category,
                                 &newname[0]);
         if (newdata == NULL)
           goto abort_single;

         /* We must not simply free a global locale since we have no
            control over the usage.  So we mark it as un-deletable.

            Note: do not remove the `if', it's necessary to copy with
            the builtin locale data.  */
         if (newdata->usage_count != UNDELETABLE)
           newdata->usage_count = UNDELETABLE;
       }

      /* Make a copy of locale name.  */
      if (newname[0] != _nl_C_name)
       {
         newname[0] = __strdup (newname[0]);
         if (newname[0] == NULL)
           goto abort_single;
       }

      /* Create new composite name.  */
      composite = new_composite_name (category, newname);
      if (composite == NULL)
       {
         if (newname[0] != _nl_C_name)
           free ((char *) newname[0]);

         /* Say that we don't have any data loaded.  */
       abort_single:
         newname[0] = NULL;
       }
      else
       {
         if (CATEGORY_USED (category))
           setdata (category, newdata);

         setname (category, newname[0]);
         setname (LC_ALL, composite);

         /* We successfully loaded a new locale.  Let the message catalog
            functions know about this.  */
         ++_nl_msg_cat_cntr;
       }

      /* Critical section left.  */
      __libc_rwlock_unlock (__libc_setlocale_lock);

      /* Free the resources (the locale path variable.  */
      free (locale_path);

      return (char *) newname[0];
    }
}

Here is the call graph for this function:

static void setname ( int  category,
const char *  name 
) [static]

Definition at line 197 of file setlocale.c.

{
  if (_nl_global_locale.__names[category] == name)
    return;

  if (_nl_global_locale.__names[category] != _nl_C_name)
    free ((char *) _nl_global_locale.__names[category]);

  _nl_global_locale.__names[category] = name;
}

Here is the caller graph for this function:


Variable Documentation

void(*const _nl_category_postload[])(void) [static]

Definition at line 116 of file setlocale.c.

const uint8_t _nl_category_name_sizes [] attribute_hidden

Definition at line 80 of file setlocale.c.