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