Implement sem_open, sem_close, and sem_unlink
[kopensolaris-gnu/glibc.git] / locale / findlocale.c
index b1f9402..ea24170 100644 (file)
@@ -1,22 +1,23 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2001, 2002, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
    The GNU C Library is free software; you can redistribute it and/or
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
+   Lesser General Public License for more details.
 
 
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
 
 
+#include <assert.h>
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
 #endif
 
 #include "localeinfo.h"
 #endif
 
 #include "localeinfo.h"
-
-
-/* Constant data defined in setlocale.c.  */
-extern struct locale_data *const _nl_C[];
+#include "../iconv/gconv_charset.h"
+#include "../iconv/gconv_int.h"
+
+
+#ifdef NL_CURRENT_INDIRECT
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+extern struct locale_data _nl_C_##category; \
+weak_extern (_nl_C_##category)
+# include "categories.def"
+# undef        DEFINE_CATEGORY
+
+/* Array indexed by category of pointers to _nl_C_CATEGORY slots.
+   Elements are zero for categories whose data is never used.  */
+struct locale_data *const _nl_C[] attribute_hidden =
+  {
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+    [category] = &_nl_C_##category,
+# include "categories.def"
+# undef        DEFINE_CATEGORY
+  };
+#else
+# define _nl_C         (_nl_C_locobj.__locales)
+#endif
 
 
 /* For each category we keep a list of records for the locale files
    which are somehow addressed.  */
 
 
 /* For each category we keep a list of records for the locale files
    which are somehow addressed.  */
-static struct loaded_l10nfile *locale_file_list[__LC_LAST];
+struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST];
+
+const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR;
 
 
 struct locale_data *
 
 
 struct locale_data *
+internal_function
 _nl_find_locale (const char *locale_path, size_t locale_path_len,
                 int category, const char **name)
 {
 _nl_find_locale (const char *locale_path, size_t locale_path_len,
                 int category, const char **name)
 {
@@ -49,9 +72,6 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
   const char *territory;
   const char *codeset;
   const char *normalized_codeset;
   const char *territory;
   const char *codeset;
   const char *normalized_codeset;
-  const char *special;
-  const char *sponsor;
-  const char *revision;
   struct loaded_l10nfile *locale_file;
 
   if ((*name)[0] == '\0')
   struct loaded_l10nfile *locale_file;
 
   if ((*name)[0] == '\0')
@@ -60,7 +80,8 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
         variables.  */
       *name = getenv ("LC_ALL");
       if (*name == NULL || (*name)[0] == '\0')
         variables.  */
       *name = getenv ("LC_ALL");
       if (*name == NULL || (*name)[0] == '\0')
-       *name = getenv (_nl_category_names[category]);
+       *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')
        *name = getenv ("LANG");
     }
@@ -79,6 +100,19 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
       return _nl_C[category];
     }
 
       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.  */
   /* 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.  */
@@ -94,45 +128,37 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 
                language[_territory[.codeset]][@modifier]
 
 
                language[_territory[.codeset]][@modifier]
 
-     and six parts for the CEN syntax:
-
-       language[_territory][+audience][+special][,[sponsor][_revision]]
-
      Beside the first all of them are allowed to be missing.  If the
      full specified locale is not found, the less specific one are
      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 of according to
+     looked for.  The various part will be stripped off according to
      the following order:
      the following order:
-               (1) revision
-               (2) sponsor
-               (3) special
-               (4) codeset
-               (5) normalized codeset
-               (6) territory
-               (7) audience/modifier
+               (1) codeset
+               (2) normalized codeset
+               (3) territory
+               (4) modifier
    */
   mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
    */
   mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
-                          &codeset, &normalized_codeset, &special,
-                          &sponsor, &revision);
+                          &codeset, &normalized_codeset);
 
   /* If exactly this locale was already asked for we have an entry with
      the complete name.  */
 
   /* If exactly this locale was already asked for we have an entry with
      the complete name.  */
-  locale_file = _nl_make_l10nflist (&locale_file_list[category],
+  locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                                    locale_path, locale_path_len, mask,
                                    language, territory, codeset,
                                    locale_path, locale_path_len, mask,
                                    language, territory, codeset,
-                                   normalized_codeset, modifier, special,
-                                   sponsor, revision,
-                                   _nl_category_names[category], NULL, 0);
+                                   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.  */
 
   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 (&locale_file_list[category],
+      locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                                        locale_path, locale_path_len, mask,
                                        language, territory, codeset,
                                        locale_path, locale_path_len, mask,
                                        language, territory, codeset,
-                                       normalized_codeset, modifier, special,
-                                       sponsor, revision,
-                                       _nl_category_names[category], NULL, 1);
+                                       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;
       if (locale_file == NULL)
        /* This means we are out of core.  */
        return NULL;
@@ -164,10 +190,58 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
        return 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.  */
   /* 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 (((struct locale_data *) locale_file->data)->name == NULL)
+  if (((const struct locale_data *) locale_file->data)->name == NULL)
     {
       char *cp, *endp;
 
     {
       char *cp, *endp;
 
@@ -180,12 +254,11 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
     }
 
   /* Determine whether the user wants transliteration or not.  */
     }
 
   /* Determine whether the user wants transliteration or not.  */
-  if ((modifier != NULL && __strcasecmp (modifier, "TRANSLIT") == 0)
-      || (special != NULL && __strcasecmp (special, "TRANSLIT") == 0))
+  if (modifier != NULL && __strcasecmp (modifier, "TRANSLIT") == 0)
     ((struct locale_data *) locale_file->data)->use_translit = 1;
 
   /* Increment the usage count.  */
     ((struct locale_data *) locale_file->data)->use_translit = 1;
 
   /* Increment the usage count.  */
-  if (((struct locale_data *) locale_file->data)->usage_count
+  if (((const struct locale_data *) locale_file->data)->usage_count
       < MAX_USAGE_COUNT)
     ++((struct locale_data *) locale_file->data)->usage_count;
 
       < MAX_USAGE_COUNT)
     ++((struct locale_data *) locale_file->data)->usage_count;
 
@@ -196,69 +269,28 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 /* Calling this function assumes the lock for handling global locale data
    is acquired.  */
 void
 /* Calling this function assumes the lock for handling global locale data
    is acquired.  */
 void
+internal_function
 _nl_remove_locale (int locale, struct locale_data *data)
 {
   if (--data->usage_count == 0)
     {
 _nl_remove_locale (int locale, struct locale_data *data)
 {
   if (--data->usage_count == 0)
     {
-      /* First search the entry in the list of loaded files.  */
-      struct loaded_l10nfile *ptr = 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;
-
-      /* Free the name.  */
-      free ((char *) data->name);
-
-#ifdef _POSIX_MAPPED_FILES
-      /* Really delete the data.  First delete the real data.  */
-      if (__builtin_expect (data->mmaped, 1))
+      if (data->alloc != ld_archive)
        {
        {
-         /* Try to unmap the area.  If this fails we mark the area as
-            permanent.  */
-         if (__munmap ((caddr_t) data->filedata, data->filesize) != 0)
-           {
-             data->usage_count = UNDELETABLE;
-             return;
-           }
+         /* 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;
        }
        }
-      else
-#endif /* _POSIX_MAPPED_FILES */
-       /* The memory was malloced.  */
-       free ((void *) data->filedata);
 
 
-      /* Now free the structure itself.  */
-      free (data);
+      /* This does the real work.  */
+      _nl_unload_locale (data);
     }
 }
     }
 }
-
-static void __attribute__ ((unused))
-free_mem (void)
-{
-  int category;
-
-  for (category = 0; category < __LC_LAST; ++category)
-    if (category != LC_ALL)
-      {
-       struct loaded_l10nfile *runp = locale_file_list[category];
-
-       while (runp != NULL)
-         {
-           struct loaded_l10nfile *here = runp;
-           struct locale_data *data = (struct locale_data *) runp->data;
-
-           if (data != NULL && data->usage_count != UNDELETABLE)
-             _nl_unload_locale (data);
-           runp = runp->next;
-           free ((char *) here->filename);
-           free (here);
-         }
-      }
-}
-text_set_element (__libc_subfreeres, free_mem);