-/* Handle aliases for locale names
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+/* Handle aliases for locale names.
+ Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ 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
+ by the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
-
- You should have received a copy of the GNU 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, USA. */
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#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
-#if defined STDC_HEADERS || defined _LIBC
-# include <stdlib.h>
-#else
-char *getenv ();
-# ifdef HAVE_MALLOC_H
-# include <malloc.h>
-# else
-void free ();
-# endif
-#endif
+#include <stdlib.h>
+#include <string.h>
-#if defined HAVE_STRING_H || defined _LIBC
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-# endif
-# include <string.h>
+#include "gettextP.h"
+
+#if ENABLE_RELOCATABLE
+# include "relocatable.h"
#else
-# include <strings.h>
-# ifndef memcpy
-# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
-# endif
-#endif
-#if !HAVE_STRCHR && !defined _LIBC
-# ifndef strchr
-# define strchr index
-# endif
+# define relocate(pathname) (pathname)
#endif
-#include "gettext.h"
-#include "gettextP.h"
-
/* @@ end of prolog @@ */
#ifdef _LIBC
because some ANSI C functions will require linking with this object
file and the name space must not be polluted. */
# define strcasecmp __strcasecmp
+
+# ifndef mempcpy
+# define mempcpy __mempcpy
+# endif
+# define HAVE_MEMPCPY 1
+# define HAVE___FSETLOCKING 1
+
+/* We need locking here since we can be called from different places. */
+# include <bits/libc-lock.h>
+
+__libc_lock_define_initialized (static, lock);
#endif
+#ifndef internal_function
+# define internal_function
+#endif
-/* For those loosing systems which don't have `alloca' we have to add
+/* 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
-/* Nothing has to be done. */
-# define ADD_BLOCK(list, address) /* nothing */
-# define FREE_BLOCKS(list) /* nothing */
+# define freea(p) /* nothing */
#else
-struct block_list
-{
- void *address;
- struct block_list *next;
-};
-# define ADD_BLOCK(list, addr) \
- do { \
- struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
- /* If we cannot get a free block we cannot add the new element to \
- the list. */ \
- if (newp != NULL) { \
- newp->address = (addr); \
- newp->next = (list); \
- (list) = newp; \
- } \
- } while (0)
-# define FREE_BLOCKS(list) \
- do { \
- while (list != NULL) { \
- struct block_list *old = list; \
- list = list->next; \
- free (old); \
- } \
- } while (0)
-# undef alloca
-# define alloca(size) (malloc (size))
-#endif /* have alloca */
+# define alloca(n) malloc (n)
+# define freea(p) free (p)
+#endif
+
+#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
+# undef fgets
+# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
+#endif
+#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
+# undef feof
+# define feof(s) feof_unlocked (s)
+#endif
struct alias_map
};
-static struct alias_map *map;
-static size_t nmap = 0;
-static size_t maxmap = 0;
+#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;
+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 void extend_alias_table PARAMS ((void));
+static size_t read_alias_file PARAMS ((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));
_nl_expand_alias (name)
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
{
struct alias_map item;
/* We really found an alias. Return the value. */
if (retval != NULL)
- return retval->value;
+ {
+ result = retval->value;
+ break;
+ }
/* Perhaps we can find another alias file. */
added = 0;
{
const char *start;
- while (locale_alias_path[0] == ':')
+ while (locale_alias_path[0] == PATH_SEPARATOR)
++locale_alias_path;
start = locale_alias_path;
- while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
+ while (locale_alias_path[0] != '\0'
+ && locale_alias_path[0] != PATH_SEPARATOR)
++locale_alias_path;
if (start < locale_alias_path)
}
while (added != 0);
- return NULL;
+#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;
{
-#ifndef HAVE_ALLOCA
- struct block_list *block_list = NULL;
-#endif
FILE *fp;
char *full_fname;
size_t added;
static const char aliasfile[] = "/locale.alias";
full_fname = (char *) alloca (fname_len + sizeof aliasfile);
- ADD_BLOCK (block_list, full_fname);
+#ifdef HAVE_MEMPCPY
+ mempcpy (mempcpy (full_fname, fname, fname_len),
+ aliasfile, sizeof aliasfile);
+#else
memcpy (full_fname, fname, fname_len);
memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
+#endif
- fp = fopen (full_fname, "r");
+ fp = fopen (relocate (full_fname), "r");
+ freea (full_fname);
if (fp == NULL)
- {
- FREE_BLOCKS (block_list);
- return 0;
- }
+ 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;
- if (fgets (buf, BUFSIZ, fp) == NULL)
+ if (FGETS (buf, sizeof buf, fp) == NULL)
/* EOF reached. */
break;
cp = buf;
/* Ignore leading white space. */
- while (isspace (cp[0]))
+ while (isspace ((unsigned char) cp[0]))
++cp;
/* A leading '#' signals a comment line. */
if (cp[0] != '\0' && cp[0] != '#')
{
alias = cp++;
- while (cp[0] != '\0' && !isspace (cp[0]))
+ while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
++cp;
/* Terminate alias name. */
if (cp[0] != '\0')
*cp++ = '\0';
/* Now look for the beginning of the value. */
- while (isspace (cp[0]))
+ while (isspace ((unsigned char) cp[0]))
++cp;
if (cp[0] != '\0')
{
- char *tp;
- size_t len;
+ size_t alias_len;
+ size_t value_len;
value = cp++;
- while (cp[0] != '\0' && !isspace (cp[0]))
+ while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
++cp;
/* Terminate value. */
if (cp[0] == '\n')
*cp++ = '\0';
if (nmap >= maxmap)
- extend_alias_table ();
-
- /* We cannot depend on strdup available in the libc. Sigh! */
- len = strlen (alias) + 1;
- tp = (char *) malloc (len);
- if (tp == NULL)
- {
- FREE_BLOCKS (block_list);
+ if (__builtin_expect (extend_alias_table (), 0))
return added;
- }
- memcpy (tp, alias, len);
- map[nmap].alias = tp;
- len = strlen (value) + 1;
- tp = (char *) malloc (len);
- if (tp == NULL)
+ alias_len = strlen (alias) + 1;
+ value_len = strlen (value) + 1;
+
+ if (string_space_act + alias_len + value_len > string_space_max)
{
- FREE_BLOCKS (block_list);
- return added;
+ /* 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;
+
+ 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;
}
- memcpy (tp, value, len);
- map[nmap].value = tp;
+
+ 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;
++nmap;
++added;
/* Possibly not the whole line fits into the buffer. Ignore
the rest of the line. */
- while (strchr (cp, '\n') == NULL)
- {
- cp = buf;
- if (fgets (buf, BUFSIZ, fp) == NULL)
- /* Make sure the inner loop will be left. The outer loop
- will exit at the `feof' test. */
- *cp = '\n';
- }
+ while (strchr (buf, '\n') == NULL)
+ 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;
}
/* Should we test for ferror()? I think we have to silently ignore
qsort (map, nmap, sizeof (struct alias_map),
(int (*) PARAMS ((const void *, const void *))) alias_compare);
- FREE_BLOCKS (block_list);
return added;
}
-static void
+static int
extend_alias_table ()
{
size_t new_size;
struct alias_map *new_map;
new_size = maxmap == 0 ? 100 : 2 * maxmap;
- new_map = (struct alias_map *) malloc (new_size
- * sizeof (struct alias_map));
+ new_map = (struct alias_map *) realloc (map, (new_size
+ * sizeof (struct alias_map)));
if (new_map == NULL)
/* Simply don't extend: we don't have any more core. */
- return;
-
- memcpy (new_map, map, nmap * sizeof (struct alias_map));
-
- if (maxmap != 0)
- free (map);
+ return -1;
map = new_map;
maxmap = new_size;
+ return 0;
}