/* Handle aliases for locale names.
- Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999, 2000-2001, 2003, 2005 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA. */
/* Tell glibc's <string.h> to provide a prototype for mempcpy().
#include <ctype.h>
#include <stdio.h>
+#if defined _LIBC || defined HAVE___FSETLOCKING
+# include <stdio_ext.h>
+#endif
#include <sys/types.h>
#ifdef __GNUC__
+# undef alloca
# define alloca __builtin_alloca
# define HAVE_ALLOCA 1
#else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
# else
-# ifdef _AIX
- #pragma alloca
+# if defined HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
# else
-# ifndef alloca
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca
char *alloca ();
+# endif
# endif
# endif
# endif
#endif
#include <stdlib.h>
-
#include <string.h>
-#if !HAVE_STRCHR && !defined _LIBC
-# ifndef strchr
-# define strchr index
-# endif
-#endif
#include "gettextP.h"
+#if ENABLE_RELOCATABLE
+# include "relocatable.h"
+#else
+# define relocate(pathname) (pathname)
+#endif
+
/* @@ end of prolog @@ */
#ifdef _LIBC
# define mempcpy __mempcpy
# endif
# define HAVE_MEMPCPY 1
+# define HAVE___FSETLOCKING 1
+#endif
-/* We need locking here since we can be called from different places. */
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
# include <bits/libc-lock.h>
-
-__libc_lock_define_initialized (static, lock);
+#else
+# include "lock.h"
#endif
#ifndef internal_function
# define internal_function
#endif
+/* Some optimizations for glibc. */
+#ifdef _LIBC
+# define FEOF(fp) feof_unlocked (fp)
+# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
+#else
+# define FEOF(fp) feof (fp)
+# define FGETS(buf, n, fp) fgets (buf, n, fp)
+#endif
+
/* For those losing systems which don't have `alloca' we have to add
some additional code emulating it. */
#ifdef HAVE_ALLOCA
# define freea(p) free (p)
#endif
-#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
+#if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
# undef fgets
# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
#endif
-#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
+#if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
# undef feof
# define feof(s) feof_unlocked (s)
#endif
+__libc_lock_define_initialized (static, lock)
+
+
struct alias_map
{
const char *alias;
};
-static char *string_space;
+#ifndef _LIBC
+# define libc_freeres_ptr(decl) decl
+#endif
+
+libc_freeres_ptr (static char *string_space);
static size_t string_space_act;
static size_t string_space_max;
-static struct alias_map *map;
+libc_freeres_ptr (static struct alias_map *map);
static size_t nmap;
static size_t maxmap;
/* Prototypes for local functions. */
-static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
+static size_t read_alias_file (const char *fname, int fname_len)
internal_function;
-static int extend_alias_table PARAMS ((void));
-static int alias_compare PARAMS ((const struct alias_map *map1,
- const struct alias_map *map2));
+static int extend_alias_table (void);
+static int alias_compare (const struct alias_map *map1,
+ const struct alias_map *map2);
const char *
-_nl_expand_alias (name)
- const char *name;
+_nl_expand_alias (const char *name)
{
- static const char *locale_alias_path = LOCALE_ALIAS_PATH;
+ static const char *locale_alias_path;
struct alias_map *retval;
const char *result = NULL;
size_t added;
-#ifdef _LIBC
__libc_lock_lock (lock);
-#endif
+
+ if (locale_alias_path == NULL)
+ locale_alias_path = LOCALE_ALIAS_PATH;
do
{
if (nmap > 0)
retval = (struct alias_map *) bsearch (&item, map, nmap,
sizeof (struct alias_map),
- (int (*) PARAMS ((const void *,
- const void *))
+ (int (*) (const void *,
+ const void *)
) alias_compare);
else
retval = NULL;
}
while (added != 0);
-#ifdef _LIBC
__libc_lock_unlock (lock);
-#endif
return result;
}
static size_t
internal_function
-read_alias_file (fname, fname_len)
- const char *fname;
- int fname_len;
+read_alias_file (const char *fname, int fname_len)
{
FILE *fp;
char *full_fname;
memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
#endif
- fp = fopen (full_fname, "r");
+#ifdef _LIBC
+ /* Note the file is opened with cancellation in the I/O functions
+ disabled. */
+ fp = fopen (relocate (full_fname), "rc");
+#else
+ fp = fopen (relocate (full_fname), "r");
+#endif
freea (full_fname);
if (fp == NULL)
return 0;
+#ifdef HAVE___FSETLOCKING
+ /* No threads present. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+#endif
+
added = 0;
- while (!feof (fp))
+ while (!FEOF (fp))
{
/* It is a reasonable approach to use a fix buffer here because
a) we are only interested in the first two fields
b) these fields must be usable as file names and so must not
be that long
- */
- char buf[BUFSIZ];
+ We avoid a multi-kilobyte buffer here since this would use up
+ stack space which we might not have if the program ran out of
+ memory. */
+ char buf[400];
char *alias;
char *value;
char *cp;
+ int complete_line;
- if (fgets (buf, sizeof buf, fp) == NULL)
+ if (FGETS (buf, sizeof buf, fp) == NULL)
/* EOF reached. */
break;
- /* Possibly not the whole line fits into the buffer. Ignore
- the rest of the line. */
- if (strchr (buf, '\n') == NULL)
- {
- char altbuf[BUFSIZ];
- do
- if (fgets (altbuf, sizeof altbuf, fp) == NULL)
- /* Make sure the inner loop will be left. The outer loop
- will exit at the `feof' test. */
- break;
- while (strchr (altbuf, '\n') == NULL);
- }
+ /* Determine whether the line is complete. */
+ complete_line = strchr (buf, '\n') != NULL;
cp = buf;
/* Ignore leading white space. */
if (cp[0] != '\0')
{
- size_t alias_len;
- size_t value_len;
-
value = cp++;
while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
++cp;
else if (cp[0] != '\0')
*cp++ = '\0';
- if (nmap >= maxmap)
- if (__builtin_expect (extend_alias_table (), 0))
- return added;
+#ifdef IN_LIBGLOCALE
+ /* glibc's locale.alias contains entries for ja_JP and ko_KR
+ that make it impossible to use a Japanese or Korean UTF-8
+ locale under the name "ja_JP" or "ko_KR". Ignore these
+ entries. */
+ if (strchr (alias, '_') == NULL)
+#endif
+ {
+ size_t alias_len;
+ size_t value_len;
- alias_len = strlen (alias) + 1;
- value_len = strlen (value) + 1;
+ if (nmap >= maxmap)
+ if (__builtin_expect (extend_alias_table (), 0))
+ goto out;
- if (string_space_act + alias_len + value_len > string_space_max)
- {
- /* Increase size of memory pool. */
- size_t new_size = (string_space_max
- + (alias_len + value_len > 1024
- ? alias_len + value_len : 1024));
- char *new_pool = (char *) realloc (string_space, new_size);
- if (new_pool == NULL)
- return added;
-
- if (__builtin_expect (string_space != new_pool, 0))
- {
- size_t i;
+ alias_len = strlen (alias) + 1;
+ value_len = strlen (value) + 1;
- for (i = 0; i < nmap; i++)
+ if (string_space_act + alias_len + value_len > string_space_max)
+ {
+ /* Increase size of memory pool. */
+ size_t new_size = (string_space_max
+ + (alias_len + value_len > 1024
+ ? alias_len + value_len : 1024));
+ char *new_pool = (char *) realloc (string_space, new_size);
+ if (new_pool == NULL)
+ goto out;
+
+ if (__builtin_expect (string_space != new_pool, 0))
{
- map[i].alias += new_pool - string_space;
- map[i].value += new_pool - string_space;
+ size_t i;
+
+ for (i = 0; i < nmap; i++)
+ {
+ map[i].alias += new_pool - string_space;
+ map[i].value += new_pool - string_space;
+ }
}
- }
- string_space = new_pool;
- string_space_max = new_size;
- }
+ string_space = new_pool;
+ string_space_max = new_size;
+ }
- map[nmap].alias = memcpy (&string_space[string_space_act],
- alias, alias_len);
- string_space_act += alias_len;
+ map[nmap].alias = memcpy (&string_space[string_space_act],
+ alias, alias_len);
+ string_space_act += alias_len;
- map[nmap].value = memcpy (&string_space[string_space_act],
- value, value_len);
- string_space_act += value_len;
+ map[nmap].value = memcpy (&string_space[string_space_act],
+ value, value_len);
+ string_space_act += value_len;
- ++nmap;
- ++added;
+ ++nmap;
+ ++added;
+ }
}
}
+
+ /* Possibly not the whole line fits into the buffer. Ignore
+ the rest of the line. */
+ if (! complete_line)
+ do
+ if (FGETS (buf, sizeof buf, fp) == NULL)
+ /* Make sure the inner loop will be left. The outer loop
+ will exit at the `feof' test. */
+ break;
+ while (strchr (buf, '\n') == NULL);
}
+ out:
/* Should we test for ferror()? I think we have to silently ignore
errors. --drepper */
fclose (fp);
if (added > 0)
qsort (map, nmap, sizeof (struct alias_map),
- (int (*) PARAMS ((const void *, const void *))) alias_compare);
+ (int (*) (const void *, const void *)) alias_compare);
return added;
}
}
-#ifdef _LIBC
-static void __attribute__ ((unused))
-free_mem (void)
-{
- if (string_space != NULL)
- free (string_space);
- if (map != NULL)
- free (map);
-}
-text_set_element (__libc_subfreeres, free_mem);
-#endif
-
-
static int
-alias_compare (map1, map2)
- const struct alias_map *map1;
- const struct alias_map *map2;
+alias_compare (const struct alias_map *map1, const struct alias_map *map2)
{
#if defined _LIBC || defined HAVE_STRCASECMP
return strcasecmp (map1->alias, map2->alias);