(root)/
gcc-13.2.0/
intl/
localealias.c
       1  /* Handle aliases for locale names.
       2     Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify it
       5     under the terms of the GNU Library General Public License as published
       6     by the Free Software Foundation; either version 2, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Library General Public License for more details.
      13  
      14     You should have received a copy of the GNU Library General Public
      15     License along with this program; if not, write to the Free Software
      16     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
      17     USA.  */
      18  
      19  /* Tell glibc's <string.h> to provide a prototype for mempcpy().
      20     This must come before <config.h> because <config.h> may include
      21     <features.h>, and once <features.h> has been included, it's too late.  */
      22  #ifndef _GNU_SOURCE
      23  # define _GNU_SOURCE    1
      24  #endif
      25  
      26  #ifdef HAVE_CONFIG_H
      27  # include <config.h>
      28  #endif
      29  
      30  #include <ctype.h>
      31  #include <stdio.h>
      32  #if defined _LIBC || defined HAVE___FSETLOCKING
      33  # include <stdio_ext.h>
      34  #endif
      35  #include <sys/types.h>
      36  
      37  #ifdef __GNUC__
      38  # undef alloca
      39  # define alloca __builtin_alloca
      40  # define HAVE_ALLOCA 1
      41  #else
      42  # ifdef _MSC_VER
      43  #  include <malloc.h>
      44  #  define alloca _alloca
      45  # else
      46  #  if defined HAVE_ALLOCA_H || defined _LIBC
      47  #   include <alloca.h>
      48  #  else
      49  #   ifdef _AIX
      50   #pragma alloca
      51  #   else
      52  #    ifndef alloca
      53  char *alloca ();
      54  #    endif
      55  #   endif
      56  #  endif
      57  # endif
      58  #endif
      59  
      60  #include <stdlib.h>
      61  #include <string.h>
      62  
      63  #include "gettextP.h"
      64  
      65  #if ENABLE_RELOCATABLE
      66  # include "relocatable.h"
      67  #else
      68  # define relocate(pathname) (pathname)
      69  #endif
      70  
      71  /* @@ end of prolog @@ */
      72  
      73  #ifdef _LIBC
      74  /* Rename the non ANSI C functions.  This is required by the standard
      75     because some ANSI C functions will require linking with this object
      76     file and the name space must not be polluted.  */
      77  # define strcasecmp __strcasecmp
      78  
      79  # ifndef mempcpy
      80  #  define mempcpy __mempcpy
      81  # endif
      82  # define HAVE_MEMPCPY	1
      83  # define HAVE___FSETLOCKING	1
      84  
      85  /* We need locking here since we can be called from different places.  */
      86  # include <bits/libc-lock.h>
      87  
      88  __libc_lock_define_initialized (static, lock);
      89  #endif
      90  
      91  #ifndef internal_function
      92  # define internal_function
      93  #endif
      94  
      95  /* Some optimizations for glibc.  */
      96  #ifdef _LIBC
      97  # define FEOF(fp)		feof_unlocked (fp)
      98  # define FGETS(buf, n, fp)	fgets_unlocked (buf, n, fp)
      99  #else
     100  # define FEOF(fp)		feof (fp)
     101  # define FGETS(buf, n, fp)	fgets (buf, n, fp)
     102  #endif
     103  
     104  /* For those losing systems which don't have `alloca' we have to add
     105     some additional code emulating it.  */
     106  #ifdef HAVE_ALLOCA
     107  # define freea(p) /* nothing */
     108  #else
     109  # define alloca(n) malloc (n)
     110  # define freea(p) free (p)
     111  #endif
     112  
     113  #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
     114  # undef fgets
     115  # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
     116  #endif
     117  #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
     118  # undef feof
     119  # define feof(s) feof_unlocked (s)
     120  #endif
     121  
     122  
     123  struct alias_map
     124  {
     125    const char *alias;
     126    const char *value;
     127  };
     128  
     129  
     130  #ifndef _LIBC
     131  # define libc_freeres_ptr(decl) decl
     132  #endif
     133  
     134  libc_freeres_ptr (static char *string_space);
     135  static size_t string_space_act;
     136  static size_t string_space_max;
     137  libc_freeres_ptr (static struct alias_map *map);
     138  static size_t nmap;
     139  static size_t maxmap;
     140  
     141  
     142  /* Prototypes for local functions.  */
     143  static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
     144       internal_function;
     145  static int extend_alias_table PARAMS ((void));
     146  static int alias_compare PARAMS ((const struct alias_map *map1,
     147  				  const struct alias_map *map2));
     148  
     149  
     150  const char *
     151  _nl_expand_alias (name)
     152      const char *name;
     153  {
     154    static const char *locale_alias_path;
     155    struct alias_map *retval;
     156    const char *result = NULL;
     157    size_t added;
     158  
     159  #ifdef _LIBC
     160    __libc_lock_lock (lock);
     161  #endif
     162  
     163    if (locale_alias_path == NULL)
     164      locale_alias_path = LOCALE_ALIAS_PATH;
     165  
     166    do
     167      {
     168        struct alias_map item;
     169  
     170        item.alias = name;
     171  
     172        if (nmap > 0)
     173  	retval = (struct alias_map *) bsearch (&item, map, nmap,
     174  					       sizeof (struct alias_map),
     175  					       (int (*) PARAMS ((const void *,
     176  								 const void *))
     177  						) alias_compare);
     178        else
     179  	retval = NULL;
     180  
     181        /* We really found an alias.  Return the value.  */
     182        if (retval != NULL)
     183  	{
     184  	  result = retval->value;
     185  	  break;
     186  	}
     187  
     188        /* Perhaps we can find another alias file.  */
     189        added = 0;
     190        while (added == 0 && locale_alias_path[0] != '\0')
     191  	{
     192  	  const char *start;
     193  
     194  	  while (locale_alias_path[0] == PATH_SEPARATOR)
     195  	    ++locale_alias_path;
     196  	  start = locale_alias_path;
     197  
     198  	  while (locale_alias_path[0] != '\0'
     199  		 && locale_alias_path[0] != PATH_SEPARATOR)
     200  	    ++locale_alias_path;
     201  
     202  	  if (start < locale_alias_path)
     203  	    added = read_alias_file (start, locale_alias_path - start);
     204  	}
     205      }
     206    while (added != 0);
     207  
     208  #ifdef _LIBC
     209    __libc_lock_unlock (lock);
     210  #endif
     211  
     212    return result;
     213  }
     214  
     215  
     216  static size_t
     217  internal_function
     218  read_alias_file (fname, fname_len)
     219       const char *fname;
     220       int fname_len;
     221  {
     222    FILE *fp;
     223    char *full_fname;
     224    size_t added;
     225    static const char aliasfile[] = "/locale.alias";
     226  
     227    full_fname = (char *) alloca (fname_len + sizeof aliasfile);
     228  #ifdef HAVE_MEMPCPY
     229    mempcpy (mempcpy (full_fname, fname, fname_len),
     230  	   aliasfile, sizeof aliasfile);
     231  #else
     232    memcpy (full_fname, fname, fname_len);
     233    memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
     234  #endif
     235  
     236    fp = fopen (relocate (full_fname), "r");
     237    freea (full_fname);
     238    if (fp == NULL)
     239      return 0;
     240  
     241  #ifdef HAVE___FSETLOCKING
     242    /* No threads present.  */
     243    __fsetlocking (fp, FSETLOCKING_BYCALLER);
     244  #endif
     245  
     246    added = 0;
     247    while (!FEOF (fp))
     248      {
     249        /* It is a reasonable approach to use a fix buffer here because
     250  	 a) we are only interested in the first two fields
     251  	 b) these fields must be usable as file names and so must not
     252  	    be that long
     253  	 We avoid a multi-kilobyte buffer here since this would use up
     254  	 stack space which we might not have if the program ran out of
     255  	 memory.  */
     256        char buf[400];
     257        char *alias;
     258        char *value;
     259        char *cp;
     260  
     261        if (FGETS (buf, sizeof buf, fp) == NULL)
     262  	/* EOF reached.  */
     263  	break;
     264  
     265        cp = buf;
     266        /* Ignore leading white space.  */
     267        while (isspace ((unsigned char) cp[0]))
     268  	++cp;
     269  
     270        /* A leading '#' signals a comment line.  */
     271        if (cp[0] != '\0' && cp[0] != '#')
     272  	{
     273  	  alias = cp++;
     274  	  while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
     275  	    ++cp;
     276  	  /* Terminate alias name.  */
     277  	  if (cp[0] != '\0')
     278  	    *cp++ = '\0';
     279  
     280  	  /* Now look for the beginning of the value.  */
     281  	  while (isspace ((unsigned char) cp[0]))
     282  	    ++cp;
     283  
     284  	  if (cp[0] != '\0')
     285  	    {
     286  	      size_t alias_len;
     287  	      size_t value_len;
     288  
     289  	      value = cp++;
     290  	      while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
     291  		++cp;
     292  	      /* Terminate value.  */
     293  	      if (cp[0] == '\n')
     294  		{
     295  		  /* This has to be done to make the following test
     296  		     for the end of line possible.  We are looking for
     297  		     the terminating '\n' which do not overwrite here.  */
     298  		  *cp++ = '\0';
     299  		  *cp = '\n';
     300  		}
     301  	      else if (cp[0] != '\0')
     302  		*cp++ = '\0';
     303  
     304  	      if (nmap >= maxmap)
     305  		if (__builtin_expect (extend_alias_table (), 0))
     306  		  return added;
     307  
     308  	      alias_len = strlen (alias) + 1;
     309  	      value_len = strlen (value) + 1;
     310  
     311  	      if (string_space_act + alias_len + value_len > string_space_max)
     312  		{
     313  		  /* Increase size of memory pool.  */
     314  		  size_t new_size = (string_space_max
     315  				     + (alias_len + value_len > 1024
     316  					? alias_len + value_len : 1024));
     317  		  char *new_pool = (char *) realloc (string_space, new_size);
     318  		  if (new_pool == NULL)
     319  		    return added;
     320  
     321  		  if (__builtin_expect (string_space != new_pool, 0))
     322  		    {
     323  		      size_t i;
     324  
     325  		      for (i = 0; i < nmap; i++)
     326  			{
     327  			  map[i].alias += new_pool - string_space;
     328  			  map[i].value += new_pool - string_space;
     329  			}
     330  		    }
     331  
     332  		  string_space = new_pool;
     333  		  string_space_max = new_size;
     334  		}
     335  
     336  	      map[nmap].alias = memcpy (&string_space[string_space_act],
     337  					alias, alias_len);
     338  	      string_space_act += alias_len;
     339  
     340  	      map[nmap].value = memcpy (&string_space[string_space_act],
     341  					value, value_len);
     342  	      string_space_act += value_len;
     343  
     344  	      ++nmap;
     345  	      ++added;
     346  	    }
     347  	}
     348  
     349        /* Possibly not the whole line fits into the buffer.  Ignore
     350  	 the rest of the line.  */
     351        while (strchr (buf, '\n') == NULL)
     352  	if (FGETS (buf, sizeof buf, fp) == NULL)
     353  	  /* Make sure the inner loop will be left.  The outer loop
     354  	     will exit at the `feof' test.  */
     355  	  break;
     356      }
     357  
     358    /* Should we test for ferror()?  I think we have to silently ignore
     359       errors.  --drepper  */
     360    fclose (fp);
     361  
     362    if (added > 0)
     363      qsort (map, nmap, sizeof (struct alias_map),
     364  	   (int (*) PARAMS ((const void *, const void *))) alias_compare);
     365  
     366    return added;
     367  }
     368  
     369  
     370  static int
     371  extend_alias_table ()
     372  {
     373    size_t new_size;
     374    struct alias_map *new_map;
     375  
     376    new_size = maxmap == 0 ? 100 : 2 * maxmap;
     377    new_map = (struct alias_map *) realloc (map, (new_size
     378  						* sizeof (struct alias_map)));
     379    if (new_map == NULL)
     380      /* Simply don't extend: we don't have any more core.  */
     381      return -1;
     382  
     383    map = new_map;
     384    maxmap = new_size;
     385    return 0;
     386  }
     387  
     388  
     389  static int
     390  alias_compare (map1, map2)
     391       const struct alias_map *map1;
     392       const struct alias_map *map2;
     393  {
     394  #if defined _LIBC || defined HAVE_STRCASECMP
     395    return strcasecmp (map1->alias, map2->alias);
     396  #else
     397    const unsigned char *p1 = (const unsigned char *) map1->alias;
     398    const unsigned char *p2 = (const unsigned char *) map2->alias;
     399    unsigned char c1, c2;
     400  
     401    if (p1 == p2)
     402      return 0;
     403  
     404    do
     405      {
     406        /* I know this seems to be odd but the tolower() function in
     407  	 some systems libc cannot handle nonalpha characters.  */
     408        c1 = isupper (*p1) ? tolower (*p1) : *p1;
     409        c2 = isupper (*p2) ? tolower (*p2) : *p2;
     410        if (c1 == '\0')
     411  	break;
     412        ++p1;
     413        ++p2;
     414      }
     415    while (c1 == c2);
     416  
     417    return c1 - c2;
     418  #endif
     419  }