Back to index

glibc  2.9
Classes | Defines | Enumerations | Functions | Variables
localeinfo.h File Reference
#include <stddef.h>
#include <langinfo.h>
#include <limits.h>
#include <locale.h>
#include <time.h>
#include <stdint.h>
#include <sys/types.h>
#include <intl/loadinfo.h>
#include "categories.def"
#include <bits/libc-tsd.h>

Go to the source code of this file.

Classes

struct  locale_data
union  locale_data::locale_data_value
struct  era_entry
struct  lc_time_data
union  catnamestr_t
struct  locale_data.private
union  locale_data.private.__unnamed__
struct  catnamestr_t.__unnamed__

Defines

#define LIMAGIC(category)
#define IGNORE_CHAR   2
#define MAX_USAGE_COUNT   (UINT_MAX - 1)
#define UNDELETABLE   UINT_MAX
#define ERA_NAME_FORMAT_MEMBERS   4
#define ERA_M_NAME   0
#define ERA_M_FORMAT   1
#define ERA_W_NAME   2
#define ERA_W_FORMAT   3
#define _ISCTYPE(c, desc)   (((((const uint32_t *) (desc)) - 8)[(c) >> 5] >> ((c) & 0x1f)) & 1)
#define CATNAMEMF(line)   CATNAMEMF1 (line)
#define CATNAMEMF1(line)   str##line
#define DEFINE_CATEGORY(category, category_name, items, a)   char CATNAMEMF (__LINE__)[sizeof (category_name)];
#define _NL_CURRENT_LOCALE   (__libc_tsd_get (__locale_t, LOCALE))
#define _NL_CURRENT_DATA(category)   (_NL_CURRENT_LOCALE->__locales[category])
#define _NL_CURRENT(category, item)   (_NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].string)
#define _NL_CURRENT_WSTR(category, item)   ((wchar_t *) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].wstr)
#define _NL_CURRENT_WORD(category, item)   ((uint32_t) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].word)
#define _NL_CURRENT_DEFINE(category)   /* No per-category variable here. */

Enumerations

enum  coll_sort_rule {
  illegal_0__, sort_forward, sort_backward, illegal_3__,
  sort_position, sort_forward_position, sort_backward_position, sort_mask
}
enum  value_type {
  none, string, stringarray, byte,
  bytearray, word, stringlist, wordarray,
  wstring, wstringarray, wstringlist
}
enum  { __TOW_toupper = 0, __TOW_tolower = 1 }

Functions

 __libc_tsd_define (extern, __locale_t, LOCALE) extern const char _nl_default_locale_path[] attribute_hidden
struct locale_data_nl_find_locale (const char *locale_path, size_t locale_path_len, int category, const char **name) internal_function attribute_hidden
void _nl_load_locale (struct loaded_l10nfile *file, int category) internal_function attribute_hidden
void _nl_unload_locale (struct locale_data *locale) internal_function attribute_hidden
void _nl_remove_locale (int locale, struct locale_data *data) internal_function attribute_hidden
struct locale_data_nl_load_locale_from_archive (int category, const char **namep) internal_function attribute_hidden
void _nl_archive_subfreeres (void) attribute_hidden
void _nl_locale_subfreeres (void) attribute_hidden
struct locale_data_nl_intern_locale_data (int category, const void *data, size_t datasize) internal_function attribute_hidden
struct era_entry_nl_get_era_entry (const struct tm *tp, struct locale_data *lc_time) internal_function attribute_hidden
struct era_entry_nl_select_era_entry (int cnt, struct locale_data *lc_time) internal_function attribute_hidden
const char * _nl_get_alt_digit (unsigned int number, struct locale_data *lc_time) internal_function attribute_hidden
const wchar_t * _nl_get_walt_digit (unsigned int number, struct locale_data *lc_time) internal_function attribute_hidden
int _nl_parse_alt_digit (const char **strp, struct locale_data *lc_time) internal_function attribute_hidden
void _nl_postload_ctype (void)
void _nl_cleanup_time (struct locale_data *) internal_function attribute_hidden

Variables

union catnamestr_t attribute_hidden

Class Documentation

union locale_data::locale_data_value

Definition at line 81 of file localeinfo.h.

Class Members
const char * string
unsigned int word
const uint32_t * wstr
struct era_entry

Definition at line 129 of file localeinfo.h.

Class Members
int absolute_direction
uint32_t direction
const char * era_format
const char * era_name
const wchar_t * era_wformat
const wchar_t * era_wname
int32_t offset
int32_t start_date
int32_t stop_date
struct lc_time_data

Definition at line 147 of file localeinfo.h.

Collaboration diagram for lc_time_data:
Class Members
const char ** alt_digits
int alt_digits_initialized
int era_initialized
struct era_entry * eras
size_t num_eras
const wchar_t ** walt_digits
int walt_digits_initialized
union catnamestr_t

Definition at line 179 of file localeinfo.h.

Class Members
struct catnamestr_t __unnamed__
char str
union locale_data.private.__unnamed__

Definition at line 67 of file localeinfo.h.

Class Members
struct gconv_fcts * ctype
void * data
struct lc_time_data * time
struct catnamestr_t.__unnamed__

Define Documentation

#define _ISCTYPE (   c,
  desc 
)    (((((const uint32_t *) (desc)) - 8)[(c) >> 5] >> ((c) & 0x1f)) & 1)

Definition at line 173 of file localeinfo.h.

#define _NL_CURRENT (   category,
  item 
)    (_NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].string)
#define _NL_CURRENT_DATA (   category)    (_NL_CURRENT_LOCALE->__locales[category])
#define _NL_CURRENT_DEFINE (   category)    /* No per-category variable here. */
#define _NL_CURRENT_LOCALE   (__libc_tsd_get (__locale_t, LOCALE))

Definition at line 207 of file localeinfo.h.

#define _NL_CURRENT_WORD (   category,
  item 
)    ((uint32_t) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].word)
#define _NL_CURRENT_WSTR (   category,
  item 
)    ((wchar_t *) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].wstr)
#define CATNAMEMF (   line)    CATNAMEMF1 (line)

Definition at line 177 of file localeinfo.h.

#define CATNAMEMF1 (   line)    str##line

Definition at line 178 of file localeinfo.h.

#define DEFINE_CATEGORY (   category,
  category_name,
  items,
  a 
)    char CATNAMEMF (__LINE__)[sizeof (category_name)];

Definition at line 183 of file localeinfo.h.

#define ERA_M_FORMAT   1

Definition at line 123 of file localeinfo.h.

#define ERA_M_NAME   0

Definition at line 122 of file localeinfo.h.

#define ERA_NAME_FORMAT_MEMBERS   4

Definition at line 121 of file localeinfo.h.

#define ERA_W_FORMAT   3

Definition at line 125 of file localeinfo.h.

#define ERA_W_NAME   2

Definition at line 124 of file localeinfo.h.

#define IGNORE_CHAR   2

Definition at line 41 of file localeinfo.h.

#define LIMAGIC (   category)
Value:
(category == LC_COLLATE                                        \
   ? ((unsigned int) (0x20051014 ^ (category)))                       \
   : ((unsigned int) (0x20031115 ^ (category))))

Definition at line 35 of file localeinfo.h.

#define MAX_USAGE_COUNT   (UINT_MAX - 1)

Definition at line 45 of file localeinfo.h.

#define UNDELETABLE   UINT_MAX

Definition at line 46 of file localeinfo.h.


Enumeration Type Documentation

anonymous enum
Enumerator:
__TOW_toupper 
__TOW_tolower 

Definition at line 162 of file localeinfo.h.

Enumerator:
illegal_0__ 
sort_forward 
sort_backward 
illegal_3__ 
sort_position 
sort_forward_position 
sort_backward_position 
sort_mask 

Definition at line 91 of file localeinfo.h.

enum value_type
Enumerator:
none 
string 
stringarray 
byte 
bytearray 
word 
stringlist 
wordarray 
wstring 
wstringarray 
wstringlist 

Definition at line 104 of file localeinfo.h.


Function Documentation

__libc_tsd_define ( extern  ,
__locale_t  ,
LOCALE   
) const
void _nl_archive_subfreeres ( void  )

Definition at line 498 of file loadarchive.c.

{
  struct locale_in_archive *lia;
  struct archmapped *am;

  /* Toss out our cached locales.  */
  lia = archloaded;
  while (lia != NULL)
    {
      int category;
      struct locale_in_archive *dead = lia;
      lia = lia->next;

      free (dead->name);
      for (category = 0; category < __LC_LAST; ++category)
       if (category != LC_ALL)
         {
           /* _nl_unload_locale just does this free for the archive case.  */
           if (dead->data[category]->private.cleanup)
             (*dead->data[category]->private.cleanup) (dead->data[category]);

           free (dead->data[category]);
         }
      free (dead);
    }
  archloaded = NULL;

  if (archmapped != NULL)
    {
      /* Now toss all the mapping windows, which we know nothing is using any
        more because we just tossed all the locales that point into them.  */

      assert (archmapped == &headmap);
      archmapped = NULL;
      (void) __munmap (headmap.ptr, headmap.len);
      am = headmap.next;
      while (am != NULL)
       {
         struct archmapped *dead = am;
         am = am->next;
         (void) __munmap (dead->ptr, dead->len);
         free (dead);
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _nl_cleanup_time ( struct locale_data )

Definition at line 24 of file lc-time-cleanup.c.

{
  struct lc_time_data *const data = locale->private.time;
  if (data != NULL)
    {
      locale->private.time = NULL;
      locale->private.cleanup = NULL;

      free (data->eras);
      free (data->alt_digits);
      free (data->walt_digits);

      free (data);
    }
}

Here is the caller graph for this function:

struct locale_data* _nl_find_locale ( const char *  locale_path,
size_t  locale_path_len,
int  category,
const char **  name 
) [read]

Definition at line 64 of file findlocale.c.

{
  int mask;
  /* Name of the locale for this category.  */
  char *loc_name;
  const char *language;
  const char *modifier;
  const char *territory;
  const char *codeset;
  const char *normalized_codeset;
  struct loaded_l10nfile *locale_file;

  if ((*name)[0] == '\0')
    {
      /* The user decides which locale to use by setting environment
        variables.  */
      *name = getenv ("LC_ALL");
      if (*name == NULL || (*name)[0] == '\0')
       *name = getenv (_nl_category_names.str
                     + _nl_category_name_idxs[category]);
      if (*name == NULL || (*name)[0] == '\0')
       *name = getenv ("LANG");
    }

  if (*name == NULL || (*name)[0] == '\0'
      || (__builtin_expect (__libc_enable_secure, 0)
         && strchr (*name, '/') != NULL))
    *name = (char *) _nl_C_name;

  if (__builtin_expect (strcmp (*name, _nl_C_name), 1) == 0
      || __builtin_expect (strcmp (*name, _nl_POSIX_name), 1) == 0)
    {
      /* We need not load anything.  The needed data is contained in
        the library itself.  */
      *name = (char *) _nl_C_name;
      return _nl_C[category];
    }

  /* We really have to load some data.  First we try the archive,
     but only if there was no LOCPATH environment variable specified.  */
  if (__builtin_expect (locale_path == NULL, 1))
    {
      struct locale_data *data = _nl_load_locale_from_archive (category, name);
      if (__builtin_expect (data != NULL, 1))
       return data;

      /* Nothing in the archive.  Set the default path to search below.  */
      locale_path = _nl_default_locale_path;
      locale_path_len = sizeof _nl_default_locale_path;
    }

  /* We really have to load some data.  First see whether the name is
     an alias.  Please note that this makes it impossible to have "C"
     or "POSIX" as aliases.  */
  loc_name = (char *) _nl_expand_alias (*name);
  if (loc_name == NULL)
    /* It is no alias.  */
    loc_name = (char *) *name;

  /* Make a writable copy of the locale name.  */
  loc_name = strdupa (loc_name);

  /* LOCALE can consist of up to four recognized parts for the XPG syntax:

              language[_territory[.codeset]][@modifier]

     Beside the first all of them are allowed to be missing.  If the
     full specified locale is not found, the less specific one are
     looked for.  The various part will be stripped off according to
     the following order:
              (1) codeset
              (2) normalized codeset
              (3) territory
              (4) modifier
   */
  mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
                        &codeset, &normalized_codeset);

  /* If exactly this locale was already asked for we have an entry with
     the complete name.  */
  locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                                locale_path, locale_path_len, mask,
                                language, territory, codeset,
                                normalized_codeset, modifier,
                                _nl_category_names.str
                                + _nl_category_name_idxs[category], 0);

  if (locale_file == NULL)
    {
      /* Find status record for addressed locale file.  We have to search
        through all directories in the locale path.  */
      locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                                   locale_path, locale_path_len, mask,
                                   language, territory, codeset,
                                   normalized_codeset, modifier,
                                   _nl_category_names.str
                                   + _nl_category_name_idxs[category], 1);
      if (locale_file == NULL)
       /* This means we are out of core.  */
       return NULL;
    }

  /* The space for normalized_codeset is dynamically allocated.  Free it.  */
  if (mask & XPG_NORM_CODESET)
    free ((void *) normalized_codeset);

  if (locale_file->decided == 0)
    _nl_load_locale (locale_file, category);

  if (locale_file->data == NULL)
    {
      int cnt;
      for (cnt = 0; locale_file->successor[cnt] != NULL; ++cnt)
       {
         if (locale_file->successor[cnt]->decided == 0)
           _nl_load_locale (locale_file->successor[cnt], category);
         if (locale_file->successor[cnt]->data != NULL)
           break;
       }
      /* Move the entry we found (or NULL) to the first place of
        successors.  */
      locale_file->successor[0] = locale_file->successor[cnt];
      locale_file = locale_file->successor[cnt];

      if (locale_file == NULL)
       return NULL;
    }

  /* The LC_CTYPE category allows to check whether a locale is really
     usable.  If the locale name contains a charset name and the
     charset name used in the locale (present in the LC_CTYPE data) is
     not the same (after resolving aliases etc) we reject the locale
     since using it would irritate users expecting the charset named
     in the locale name.  */
  if (codeset != NULL)
    {
      /* Get the codeset information from the locale file.  */
      static const int codeset_idx[] =
       {
         [__LC_CTYPE] = _NL_ITEM_INDEX (CODESET),
         [__LC_NUMERIC] = _NL_ITEM_INDEX (_NL_NUMERIC_CODESET),
         [__LC_TIME] = _NL_ITEM_INDEX (_NL_TIME_CODESET),
         [__LC_COLLATE] = _NL_ITEM_INDEX (_NL_COLLATE_CODESET),
         [__LC_MONETARY] = _NL_ITEM_INDEX (_NL_MONETARY_CODESET),
         [__LC_MESSAGES] = _NL_ITEM_INDEX (_NL_MESSAGES_CODESET),
         [__LC_PAPER] = _NL_ITEM_INDEX (_NL_PAPER_CODESET),
         [__LC_NAME] = _NL_ITEM_INDEX (_NL_NAME_CODESET),
         [__LC_ADDRESS] = _NL_ITEM_INDEX (_NL_ADDRESS_CODESET),
         [__LC_TELEPHONE] = _NL_ITEM_INDEX (_NL_TELEPHONE_CODESET),
         [__LC_MEASUREMENT] = _NL_ITEM_INDEX (_NL_MEASUREMENT_CODESET),
         [__LC_IDENTIFICATION] = _NL_ITEM_INDEX (_NL_IDENTIFICATION_CODESET)
       };
      const struct locale_data *data;
      const char *locale_codeset;
      char *clocale_codeset;
      char *ccodeset;

      data = (const struct locale_data *) locale_file->data;
      locale_codeset =
       (const char *) data->values[codeset_idx[category]].string;
      assert (locale_codeset != NULL);
      /* Note the length of the allocated memory: +3 for up to two slashes
        and the NUL byte.  */
      clocale_codeset = (char *) alloca (strlen (locale_codeset) + 3);
      strip (clocale_codeset, locale_codeset);

      ccodeset = (char *) alloca (strlen (codeset) + 3);
      strip (ccodeset, codeset);

      if (__gconv_compare_alias (upstr (ccodeset, ccodeset),
                             upstr (clocale_codeset,
                                   clocale_codeset)) != 0)
       /* The codesets are not identical, don't use the locale.  */
       return NULL;
    }

  /* Determine the locale name for which loading succeeded.  This
     information comes from the file name.  The form is
     <path>/<locale>/LC_foo.  We must extract the <locale> part.  */
  if (((const struct locale_data *) locale_file->data)->name == NULL)
    {
      char *cp, *endp;

      endp = strrchr (locale_file->filename, '/');
      cp = endp - 1;
      while (cp[-1] != '/')
       --cp;
      ((struct locale_data *) locale_file->data)->name = __strndup (cp,
                                                            endp - cp);
    }

  /* Determine whether the user wants transliteration or not.  */
  if (modifier != NULL && __strcasecmp (modifier, "TRANSLIT") == 0)
    ((struct locale_data *) locale_file->data)->use_translit = 1;

  /* Increment the usage count.  */
  if (((const struct locale_data *) locale_file->data)->usage_count
      < MAX_USAGE_COUNT)
    ++((struct locale_data *) locale_file->data)->usage_count;

  return (struct locale_data *) locale_file->data;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* _nl_get_alt_digit ( unsigned int  number,
struct locale_data lc_time 
)

Definition at line 73 of file alt_digit.c.

{
  const char *result;

  if (number >= 100 || CURRENT (ALT_DIGITS)[0] == '\0')
    return NULL;

  __libc_rwlock_wrlock (__libc_setlocale_lock);

  if (current->private.time == NULL
      || ! current->private.time->alt_digits_initialized)
    _nl_init_alt_digit (current);

  result = ((current->private.time != NULL
            && current->private.time->alt_digits != NULL)
           ? current->private.time->alt_digits[number]
           : NULL);

  __libc_rwlock_unlock (__libc_setlocale_lock);

  return result;
}
struct era_entry* _nl_get_era_entry ( const struct tm tp,
struct locale_data lc_time 
) [read]

Definition at line 143 of file era.c.

{
  if (current->private.time == NULL || !current->private.time->era_initialized)
    _nl_init_era_entries (current);

  if (current->private.time != NULL)
    {
      /* Now compare date with the available eras.  */
      const int32_t tdate[3] = { tp->tm_year, tp->tm_mon, tp->tm_mday };
      size_t cnt;
      for (cnt = 0; cnt < current->private.time->num_eras; ++cnt)
       if ((ERA_DATE_CMP (current->private.time->eras[cnt].start_date, tdate)
            && ERA_DATE_CMP (tdate,
                           current->private.time->eras[cnt].stop_date))
           || (ERA_DATE_CMP (current->private.time->eras[cnt].stop_date,
                           tdate)
              && ERA_DATE_CMP (tdate,
                             current->private.time->eras[cnt].start_date)))
         return &current->private.time->eras[cnt];
    }

  return NULL;
}
const wchar_t* _nl_get_walt_digit ( unsigned int  number,
struct locale_data lc_time 
)

Definition at line 99 of file alt_digit.c.

{
  const wchar_t *result = NULL;
  struct lc_time_data *data;

  if (number >= 100 || CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
    return NULL;

  __libc_rwlock_wrlock (__libc_setlocale_lock);

  if (current->private.time == NULL)
    {
      current->private.time = malloc (sizeof *current->private.time);
      if (current->private.time == NULL)
       goto out;
      memset (current->private.time, 0, sizeof *current->private.time);
      current->private.cleanup = &_nl_cleanup_time;
    }
  data = current->private.time;

  if (! data->walt_digits_initialized)
    {
      const wchar_t *ptr = CURRENT_WSTR (_NL_WALT_DIGITS);
      size_t cnt;

      data->walt_digits_initialized = 1;

      if (ptr != NULL)
       {
         data->walt_digits = malloc (100 * sizeof (const uint32_t *));
         if (data->walt_digits != NULL)
           for (cnt = 0; cnt < 100; ++cnt)
             {
              data->walt_digits[cnt] = ptr;

              /* Skip digit format. */
              ptr = wcschr (ptr, L'\0') + 1;
             }
       }
    }

  if (data->walt_digits != NULL)
    result = data->walt_digits[number];

 out:
  __libc_rwlock_unlock (__libc_setlocale_lock);

  return (wchar_t *) result;
}

Here is the call graph for this function:

struct locale_data* _nl_intern_locale_data ( int  category,
const void *  data,
size_t  datasize 
) [read]

Definition at line 66 of file loadlocale.c.

{
  const struct
    {
      unsigned int magic;
      unsigned int nstrings;
      unsigned int strindex[0];
    } *const filedata = data;
  struct locale_data *newdata;
  size_t cnt;

  if (__builtin_expect (datasize < sizeof *filedata, 0)
      || __builtin_expect (filedata->magic != LIMAGIC (category), 0))
    {
      /* Bad data file.  */
      __set_errno (EINVAL);
      return NULL;
    }

  if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category],
                     0)
      || (__builtin_expect (sizeof *filedata
                         + filedata->nstrings * sizeof (unsigned int)
                         >= datasize, 0)))
    {
      /* Insufficient data.  */
      __set_errno (EINVAL);
      return NULL;
    }

  newdata = malloc (sizeof *newdata
                  + filedata->nstrings * sizeof (union locale_data_value));
  if (newdata == NULL)
    return NULL;

  newdata->filedata = (void *) filedata;
  newdata->filesize = datasize;
  newdata->private.data = NULL;
  newdata->private.cleanup = NULL;
  newdata->usage_count = 0;
  newdata->use_translit = 0;
  newdata->nstrings = filedata->nstrings;
  for (cnt = 0; cnt < newdata->nstrings; ++cnt)
    {
      size_t idx = filedata->strindex[cnt];
      if (__builtin_expect (idx > (size_t) newdata->filesize, 0))
       {
       puntdata:
         free (newdata);
         __set_errno (EINVAL);
         return NULL;
       }

      /* Determine the type.  There is one special case: the LC_CTYPE
        category can have more elements than there are in the
        _nl_value_type_LC_XYZ array.  There are all pointers.  */
      switch (category)
       {
#define CATTEST(cat) \
       case LC_##cat:                                                       \
         assert (cnt < (sizeof (_nl_value_type_LC_##cat)                    \
                      / sizeof (_nl_value_type_LC_##cat[0])));       \
         break
         CATTEST (NUMERIC);
         CATTEST (TIME);
         CATTEST (COLLATE);
         CATTEST (MONETARY);
         CATTEST (MESSAGES);
         CATTEST (PAPER);
         CATTEST (NAME);
         CATTEST (ADDRESS);
         CATTEST (TELEPHONE);
         CATTEST (MEASUREMENT);
         CATTEST (IDENTIFICATION);
       default:
         assert (category == LC_CTYPE);
         break;
       }

      if ((category == LC_CTYPE
          && cnt >= (sizeof (_nl_value_type_LC_CTYPE)
                    / sizeof (_nl_value_type_LC_CTYPE[0])))
         || __builtin_expect (_nl_value_types[category][cnt] != word, 1))
       newdata->values[cnt].string = newdata->filedata + idx;
      else
       {
         if (idx % __alignof__ (u_int32_t) != 0)
           goto puntdata;
         newdata->values[cnt].word =
           *((const u_int32_t *) (newdata->filedata + idx));
       }
    }

  return newdata;
}

Here is the caller graph for this function:

void _nl_load_locale ( struct loaded_l10nfile file,
int  category 
)

Definition at line 164 of file loadlocale.c.

{
  int fd;
  void *filedata;
  struct stat64 st;
  struct locale_data *newdata;
  int save_err;
  int alloc = ld_mapped;

  file->decided = 1;
  file->data = NULL;

  fd = open_not_cancel_2 (file->filename, O_RDONLY);
  if (__builtin_expect (fd, 0) < 0)
    /* Cannot open the file.  */
    return;

  if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
    {
    puntfd:
      close_not_cancel_no_status (fd);
      return;
    }
  if (__builtin_expect (S_ISDIR (st.st_mode), 0))
    {
      /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
           instead.  */
      char *newp;
      size_t filenamelen;

      close_not_cancel_no_status (fd);

      filenamelen = strlen (file->filename);
      newp = (char *) alloca (filenamelen
                           + 5 + _nl_category_name_sizes[category] + 1);
      __mempcpy (__mempcpy (__mempcpy (newp, file->filename, filenamelen),
                         "/SYS_", 5),
               _nl_category_names.str + _nl_category_name_idxs[category],
               _nl_category_name_sizes[category] + 1);

      fd = open_not_cancel_2 (newp, O_RDONLY);
      if (__builtin_expect (fd, 0) < 0)
       return;

      if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
       goto puntfd;
    }

  /* Map in the file's data.  */
  save_err = errno;
#ifdef _POSIX_MAPPED_FILES
# ifndef MAP_COPY
  /* Linux seems to lack read-only copy-on-write.  */
#  define MAP_COPY MAP_PRIVATE
# endif
# ifndef MAP_FILE
  /* Some systems do not have this flag; it is superfluous.  */
#  define MAP_FILE 0
# endif
  filedata = __mmap ((caddr_t) 0, st.st_size,
                   PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
  if (__builtin_expect (filedata == MAP_FAILED, 0))
    {
      if (__builtin_expect (errno, ENOSYS) == ENOSYS)
       {
#endif /* _POSIX_MAPPED_FILES */
         /* No mmap; allocate a buffer and read from the file.  */
         alloc = ld_malloced;
         filedata = malloc (st.st_size);
         if (filedata != NULL)
           {
             off_t to_read = st.st_size;
             ssize_t nread;
             char *p = (char *) filedata;
             while (to_read > 0)
              {
                nread = read_not_cancel (fd, p, to_read);
                if (__builtin_expect (nread, 1) <= 0)
                  {
                    free (filedata);
                    if (nread == 0)
                     __set_errno (EINVAL); /* Bizarreness going on.  */
                    goto puntfd;
                  }
                p += nread;
                to_read -= nread;
              }
             __set_errno (save_err);
           }
#ifdef _POSIX_MAPPED_FILES
       }
    }
#endif /* _POSIX_MAPPED_FILES */

  /* We have mapped the data, so we no longer need the descriptor.  */
  close_not_cancel_no_status (fd);

  if (__builtin_expect (filedata == NULL, 0))
    /* We failed to map or read the data.  */
    return;

  newdata = _nl_intern_locale_data (category, filedata, st.st_size);
  if (__builtin_expect (newdata == NULL, 0))
    /* Bad data.  */
    {
#ifdef _POSIX_MAPPED_FILES
      if (alloc == ld_mapped)
       __munmap ((caddr_t) filedata, st.st_size);
#endif
      return;
    }

  /* _nl_intern_locale_data leaves us these fields to initialize.  */
  newdata->name = NULL;     /* This will be filled if necessary in findlocale.c. */
  newdata->alloc = alloc;

  file->data = newdata;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct locale_data* _nl_load_locale_from_archive ( int  category,
const char **  namep 
) [read]

Definition at line 134 of file loadarchive.c.

{
  const char *name = *namep;
  struct
  {
    void *addr;
    size_t len;
  } results[__LC_LAST];
  struct locale_in_archive *lia;
  struct locarhead *head;
  struct namehashent *namehashtab;
  struct locrecent *locrec;
  struct archmapped *mapped;
  struct archmapped *last;
  unsigned long int hval;
  size_t idx;
  size_t incr;
  struct range ranges[__LC_LAST - 1];
  int nranges;
  int cnt;
  size_t ps = __sysconf (_SC_PAGE_SIZE);
  int fd = -1;

  /* Check if we have already loaded this locale from the archive.
     If we previously loaded the locale but found bogons in the data,
     then we will have stored a null pointer to return here.  */
  for (lia = archloaded; lia != NULL; lia = lia->next)
    if (name == lia->name || !strcmp (name, lia->name))
      {
       *namep = lia->name;
       return lia->data[category];
      }

  {
    /* If the name contains a codeset, then we normalize the name before
       doing the lookup.  */
    const char *p = strchr (name, '.');
    if (p != NULL && p[1] != '@' && p[1] != '\0')
      {
       const char *rest = __strchrnul (++p, '@');
       const char *normalized_codeset = _nl_normalize_codeset (p, rest - p);
       if (normalized_codeset == NULL)    /* malloc failure */
         return NULL;
       if (strncmp (normalized_codeset, p, rest - p) != 0
           || normalized_codeset[rest - p] != '\0')
         {
           /* There is a normalized codeset name that is different from
              what was specified; reconstruct a new locale name using it.  */
           size_t normlen = strlen (normalized_codeset);
           size_t restlen = strlen (rest) + 1;
           char *newname = alloca (p - name + normlen + restlen);
           memcpy (__mempcpy (__mempcpy (newname, name, p - name),
                            normalized_codeset, normlen),
                  rest, restlen);
           name = newname;
         }
       free ((char *) normalized_codeset);
      }
  }

  /* Make sure the archive is loaded.  */
  if (archmapped == NULL)
    {
      void *result;
      size_t headsize, mapsize;

      /* We do this early as a sign that we have tried to open the archive.
        If headmap.ptr remains null, that's an indication that we tried
        and failed, so we won't try again.  */
      archmapped = &headmap;

      /* The archive has never been opened.  */
      fd = open_not_cancel_2 (archfname, O_RDONLY|O_LARGEFILE);
      if (fd < 0)
       /* Cannot open the archive, for whatever reason.  */
       return NULL;

      if (__fxstat64 (_STAT_VER, fd, &archive_stat) == -1)
       {
         /* stat failed, very strange.  */
       close_and_out:
         if (fd >= 0)
           close_not_cancel_no_status (fd);
         return NULL;
       }


      /* Map an initial window probably large enough to cover the header
        and the first locale's data.  With a large address space, we can
        just map the whole file and be sure everything is covered.  */

      mapsize = (sizeof (void *) > 4 ? archive_stat.st_size
               : MIN (archive_stat.st_size, ARCHIVE_MAPPING_WINDOW));

      result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
      if (result == MAP_FAILED)
       goto close_and_out;

      /* Check whether the file is large enough for the sizes given in
        the header.  Theoretically an archive could be so large that
        just the header fails to fit in our initial mapping window.  */
      headsize = calculate_head_size ((const struct locarhead *) result);
      if (headsize > mapsize)
       {
         (void) __munmap (result, mapsize);
         if (sizeof (void *) > 4 || headsize > archive_stat.st_size)
           /* The file is not big enough for the header.  Bogus.  */
           goto close_and_out;

         /* Freakishly long header.  */
         /* XXX could use mremap when available */
         mapsize = (headsize + ps - 1) & ~(ps - 1);
         result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY,
                          fd, 0);
         if (result == MAP_FAILED)
           goto close_and_out;
       }

      if (sizeof (void *) > 4 || mapsize >= archive_stat.st_size)
       {
         /* We've mapped the whole file already, so we can be
            sure we won't need this file descriptor later.  */
         close_not_cancel_no_status (fd);
         fd = -1;
       }

      headmap.ptr = result;
      /* headmap.from already initialized to zero.  */
      headmap.len = mapsize;
    }

  /* If there is no archive or it cannot be loaded for some reason fail.  */
  if (__builtin_expect (headmap.ptr == NULL, 0))
    goto close_and_out;

  /* We have the archive available.  To find the name we first have to
     determine its hash value.  */
  hval = compute_hashval (name, strlen (name));

  head = headmap.ptr;
  namehashtab = (struct namehashent *) ((char *) head
                                   + head->namehash_offset);

  idx = hval % head->namehash_size;
  incr = 1 + hval % (head->namehash_size - 2);

  /* If the name_offset field is zero this means this is a
     deleted entry and therefore no entry can be found.  */
  while (1)
    {
      if (namehashtab[idx].name_offset == 0)
       /* Not found.  */
       goto close_and_out;

      if (namehashtab[idx].hashval == hval
         && strcmp (name, headmap.ptr + namehashtab[idx].name_offset) == 0)
       /* Found the entry.  */
       break;

      idx += incr;
      if (idx >= head->namehash_size)
       idx -= head->namehash_size;
    }

  /* We found an entry.  It might be a placeholder for a removed one.  */
  if (namehashtab[idx].locrec_offset == 0)
    goto close_and_out;

  locrec = (struct locrecent *) (headmap.ptr + namehashtab[idx].locrec_offset);

  if (sizeof (void *) > 4 /* || headmap.len == archive_stat.st_size */)
    {
      /* We already have the whole locale archive mapped in.  */
      assert (headmap.len == archive_stat.st_size);
      for (cnt = 0; cnt < __LC_LAST; ++cnt)
       if (cnt != LC_ALL)
         {
           if (locrec->record[cnt].offset + locrec->record[cnt].len
              > headmap.len)
             /* The archive locrectab contains bogus offsets.  */
             goto close_and_out;
           results[cnt].addr = headmap.ptr + locrec->record[cnt].offset;
           results[cnt].len = locrec->record[cnt].len;
         }
    }
  else
    {
      /* Get the offsets of the data files and sort them.  */
      for (cnt = nranges = 0; cnt < __LC_LAST; ++cnt)
       if (cnt != LC_ALL)
         {
           ranges[nranges].from = locrec->record[cnt].offset;
           ranges[nranges].len = locrec->record[cnt].len;
           ranges[nranges].category = cnt;
           ranges[nranges].result = NULL;

           ++nranges;
         }

      qsort (ranges, nranges, sizeof (ranges[0]), rangecmp);

      /* The information about mmap'd blocks is kept in a list.
        Skip over the blocks which are before the data we need.  */
      last = mapped = archmapped;
      for (cnt = 0; cnt < nranges; ++cnt)
       {
         int upper;
         size_t from;
         size_t to;
         void *addr;
         struct archmapped *newp;

         /* Determine whether the appropriate page is already mapped.  */
         while (mapped != NULL
               && (mapped->from + mapped->len
                   <= ranges[cnt].from + ranges[cnt].len))
           {
             last = mapped;
             mapped = mapped->next;
           }

         /* Do we have a match?  */
         if (mapped != NULL
             && mapped->from <= ranges[cnt].from
             && (ranges[cnt].from + ranges[cnt].len
                <= mapped->from + mapped->len))
           {
             /* Yep, already loaded.  */
             results[ranges[cnt].category].addr = ((char *) mapped->ptr
                                              + ranges[cnt].from
                                              - mapped->from);
             results[ranges[cnt].category].len = ranges[cnt].len;
             continue;
           }

         /* Map the range with the locale data from the file.  We will
            try to cover as much of the locale as possible.  I.e., if the
            next category (next as in "next offset") is on the current or
            immediately following page we use it as well.  */
         assert (powerof2 (ps));
         from = ranges[cnt].from & ~(ps - 1);
         upper = cnt;
         do
           {
             to = ranges[upper].from + ranges[upper].len;
             if (to > (size_t) archive_stat.st_size)
              /* The archive locrectab contains bogus offsets.  */
              goto close_and_out;
             to = (to + ps - 1) & ~(ps - 1);

             /* If a range is already mmaped in, stop.   */
             if (mapped != NULL && ranges[upper].from >= mapped->from)
              break;

             ++upper;
           }
         /* Loop while still in contiguous pages. */
         while (upper < nranges && ranges[upper].from < to + ps);

         /* Open the file if it hasn't happened yet.  */
         if (fd == -1)
           {
             struct stat64 st;
             fd = open_not_cancel_2 (archfname, O_RDONLY|O_LARGEFILE);
             if (fd == -1)
              /* Cannot open the archive, for whatever reason.  */
              return NULL;
             /* Now verify we think this is really the same archive file
               we opened before.  If it has been changed we cannot trust
               the header we read previously.  */
             if (__fxstat64 (_STAT_VER, fd, &st) < 0
                || st.st_size != archive_stat.st_size
                || st.st_mtime != archive_stat.st_mtime
                || st.st_dev != archive_stat.st_dev
                || st.st_ino != archive_stat.st_ino)
              goto close_and_out;
           }

         /* Map the range from the archive.  */
         addr = __mmap64 (NULL, to - from, PROT_READ, MAP_FILE|MAP_COPY,
                        fd, from);
         if (addr == MAP_FAILED)
           goto close_and_out;

         /* Allocate a record for this mapping.  */
         newp = (struct archmapped *) malloc (sizeof (struct archmapped));
         if (newp == NULL)
           {
             (void) __munmap (addr, to - from);
             goto close_and_out;
           }

         /* And queue it.  */
         newp->ptr = addr;
         newp->from = from;
         newp->len = to - from;
         assert (last->next == mapped);
         newp->next = mapped;
         last->next = newp;
         last = newp;

         /* Determine the load addresses for the category data.  */
         do
           {
             assert (ranges[cnt].from >= from);
             results[ranges[cnt].category].addr = ((char *) addr
                                              + ranges[cnt].from - from);
             results[ranges[cnt].category].len = ranges[cnt].len;
           }
         while (++cnt < upper);
         --cnt;             /* The 'for' will increase 'cnt' again.  */
       }
    }

  /* We don't need the file descriptor any longer.  */
  if (fd >= 0)
    close_not_cancel_no_status (fd);
  fd = -1;

  /* We succeeded in mapping all the necessary regions of the archive.
     Now we need the expected data structures to point into the data.  */

  lia = malloc (sizeof *lia);
  if (__builtin_expect (lia == NULL, 0))
    return NULL;

  lia->name = strdup (*namep);
  if (__builtin_expect (lia->name == NULL, 0))
    {
      free (lia);
      return NULL;
    }

  lia->next = archloaded;
  archloaded = lia;

  for (cnt = 0; cnt < __LC_LAST; ++cnt)
    if (cnt != LC_ALL)
      {
       lia->data[cnt] = _nl_intern_locale_data (cnt,
                                           results[cnt].addr,
                                           results[cnt].len);
       if (__builtin_expect (lia->data[cnt] != NULL, 1))
         {
           /* _nl_intern_locale_data leaves us these fields to initialize.  */
           lia->data[cnt]->alloc = ld_archive;
           lia->data[cnt]->name = lia->name;

           /* We do this instead of bumping the count each time we return
              this data because the mappings stay around forever anyway
              and we might as well hold on to a little more memory and not
              have to rebuild it on the next lookup of the same thing.
              If we were to maintain the usage_count normally and let the
              structures be freed, we would have to remove the elements
              from archloaded too.  */
           lia->data[cnt]->usage_count = UNDELETABLE;
         }
      }

  *namep = lia->name;
  return lia->data[category];
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _nl_locale_subfreeres ( void  )

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:

int _nl_parse_alt_digit ( const char **  strp,
struct locale_data lc_time 
)

Definition at line 152 of file alt_digit.c.

{
  const char *str = *strp;
  int result = -1;
  size_t cnt;
  size_t maxlen = 0;

  if (CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
    return result;

  __libc_rwlock_wrlock (__libc_setlocale_lock);

  if (current->private.time == NULL
      || ! current->private.time->alt_digits_initialized)
    _nl_init_alt_digit (current);

  if (current->private.time != NULL &&
      current->private.time->alt_digits != NULL)
    /* Matching is not unambiguous.  The alternative digits could be like
       I, II, III, ... and the first one is a substring of the second
       and third.  Therefore we must keep on searching until we found
       the longest possible match.  Note that this is not specified in
       the standard.  */
    for (cnt = 0; cnt < 100; ++cnt)
      {
       const char *const dig = current->private.time->alt_digits[cnt];
       size_t len = strlen (dig);

       if (len > maxlen && strncmp (dig, str, len) == 0)
         {
           maxlen = len;
           result = (int) cnt;
         }
      }

  __libc_rwlock_unlock (__libc_setlocale_lock);

  if (result != -1)
    *strp += maxlen;

  return result;
}

Here is the call graph for this function:

void _nl_postload_ctype ( void  )

Definition at line 34 of file lc-ctype.c.

{
#define current(type,x,offset) \
  ((const type *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_##x) + offset)

  const union locale_data_value *const ctypes
    = _nl_global_locale.__locales[LC_CTYPE]->values;

/* These thread-local variables are defined in ctype-info.c.
   The declarations here must match those in localeinfo.h.

   These point into arrays of 384, so they can be indexed by any `unsigned
   char' value [0,255]; by EOF (-1); or by any `signed char' value
   [-128,-1).  ISO C requires that the ctype functions work for `unsigned
   char' values and for EOF; we also support negative `signed char' values
   for broken old programs.  The case conversion arrays are of `int's
   rather than `unsigned char's because tolower (EOF) must be EOF, which
   doesn't fit into an `unsigned char'.  But today more important is that
   the arrays are also used for multi-byte character sets.

   First we update the special members of _nl_global_locale as newlocale
   would.  This is necessary for uselocale (LC_GLOBAL_LOCALE) to find these
   values properly.  */

  _nl_global_locale.__ctype_b = (const unsigned short int *)
    ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
  _nl_global_locale.__ctype_tolower = (const int *)
    ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
  _nl_global_locale.__ctype_toupper = (const int *)
    ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;

  /* Next we must set the thread-local caches if and only if this thread is
     in fact using the global locale.  */
  if (_NL_CURRENT_LOCALE == &_nl_global_locale)
    {
      __libc_tsd_set (const uint16_t *, CTYPE_B,
                    (void *) _nl_global_locale.__ctype_b);
      __libc_tsd_set (const int32_t *, CTYPE_TOUPPER,
                    (void *) _nl_global_locale.__ctype_toupper);
      __libc_tsd_set (const int32_t *, CTYPE_TOLOWER,
                    (void *) _nl_global_locale.__ctype_tolower);
    }

#include <shlib-compat.h>
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
  /* We must use the exported names to access these so we are sure to
     be accessing the main executable's copy if it has COPY relocs.  */

  extern __const unsigned short int *__ctype_b; /* Characteristics.  */
  extern __const __int32_t *__ctype_tolower; /* Case conversions.  */
  extern __const __int32_t *__ctype_toupper; /* Case conversions.  */

  extern const uint32_t *__ctype32_b;
  extern const uint32_t *__ctype32_toupper;
  extern const uint32_t *__ctype32_tolower;

  /* We need the .symver declarations these macros generate so that
     our references are explicitly bound to the versioned symbol names
     rather than the unadorned names that are not exported.  When the
     linker sees these bound to local symbols (as the unexported names are)
     then it doesn't generate a proper relocation to the global symbols.
     We need those relocations so that a versioned definition with a COPY
     reloc in an executable will override the libc.so definition.  */

compat_symbol (libc, __ctype_b, __ctype_b, GLIBC_2_0);
compat_symbol (libc, __ctype_tolower, __ctype_tolower, GLIBC_2_0);
compat_symbol (libc, __ctype_toupper, __ctype_toupper, GLIBC_2_0);
compat_symbol (libc, __ctype32_b, __ctype32_b, GLIBC_2_0);
compat_symbol (libc, __ctype32_tolower, __ctype32_tolower, GLIBC_2_2);
compat_symbol (libc, __ctype32_toupper, __ctype32_toupper, GLIBC_2_2);

  __ctype_b = current (uint16_t, CLASS, 128);
  __ctype_toupper = current (int32_t, TOUPPER, 128);
  __ctype_tolower = current (int32_t, TOLOWER, 128);
  __ctype32_b = current (uint32_t, CLASS32, 0);
  __ctype32_toupper = current (uint32_t, TOUPPER32, 0);
  __ctype32_tolower = current (uint32_t, TOLOWER32, 0);
#endif
}
void _nl_remove_locale ( int  locale,
struct locale_data data 
)

Definition at line 273 of file findlocale.c.

{
  if (--data->usage_count == 0)
    {
      if (data->alloc != ld_archive)
       {
         /* First search the entry in the list of loaded files.  */
         struct loaded_l10nfile *ptr = _nl_locale_file_list[locale];

         /* Search for the entry.  It must be in the list.  Otherwise it
            is a bug and we crash badly.  */
         while ((struct locale_data *) ptr->data != data)
           ptr = ptr->next;

         /* Mark the data as not available anymore.  So when the data has
            to be used again it is reloaded.  */
         ptr->decided = 0;
         ptr->data = NULL;
       }

      /* This does the real work.  */
      _nl_unload_locale (data);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct era_entry* _nl_select_era_entry ( int  cnt,
struct locale_data lc_time 
) [read]

Definition at line 170 of file era.c.

{
  if (current->private.time == NULL || !current->private.time->era_initialized)
    _nl_init_era_entries (current);

  return (current->private.time == NULL
         ? NULL : &current->private.time->eras[cnt]);
}
void _nl_unload_locale ( struct locale_data locale)

Definition at line 285 of file loadlocale.c.

{
  if (locale->private.cleanup)
    (*locale->private.cleanup) (locale);

  switch (__builtin_expect (locale->alloc, ld_mapped))
    {
    case ld_malloced:
      free ((void *) locale->filedata);
      break;
    case ld_mapped:
#ifdef _POSIX_MAPPED_FILES
      __munmap ((caddr_t) locale->filedata, locale->filesize);
      break;
#endif
    case ld_archive:        /* Nothing to do.  */
      break;
    }

  if (__builtin_expect (locale->alloc, ld_mapped) != ld_archive)
    free ((char *) locale->name);

  free (locale);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 190 of file localeinfo.h.