Update build system to Autoconf 2.58, Automake 1.7, gettext 0.12.1.
[pspp-builds.git] / intl / localealias.c
index 64e8ca78fa9d34ea896d8614fb7d6fe0386e9d84..7c4ce58f2a67ee15e50113a77d1a68dc6452b4c1 100644 (file)
@@ -1,20 +1,27 @@
-/* Handle aliases for locale names
-   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
-   Written by Ulrich Drepper <drepper@gnu.org>, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   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
@@ -79,43 +75,49 @@ void free ();
    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
@@ -125,14 +127,22 @@ 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));
 
@@ -141,10 +151,18 @@ const char *
 _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;
@@ -162,7 +180,10 @@ _nl_expand_alias (name)
 
       /* 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;
@@ -170,11 +191,12 @@ _nl_expand_alias (name)
        {
          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)
@@ -183,78 +205,89 @@ _nl_expand_alias (name)
     }
   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')
@@ -269,28 +302,44 @@ read_alias_file (fname, fname_len)
                *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;
@@ -299,14 +348,11 @@ read_alias_file (fname, fname_len)
 
       /* 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
@@ -317,31 +363,26 @@ read_alias_file (fname, fname_len)
     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;
 }