NPTL: Remove gratuitous Linuxisms from gai_misc.h.
[platform/upstream/glibc.git] / intl / localealias.c
1 /* Handle aliases for locale names.
2    Copyright (C) 1995-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 2.1 of the License, or
7    (at your option) 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
12    GNU Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
18    This must come before <config.h> because <config.h> may include
19    <features.h>, and once <features.h> has been included, it's too late.  */
20 #ifndef _GNU_SOURCE
21 # define _GNU_SOURCE    1
22 #endif
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <ctype.h>
29 #include <stdio.h>
30 #if defined _LIBC || defined HAVE___FSETLOCKING
31 # include <stdio_ext.h>
32 #endif
33 #include <sys/types.h>
34
35 #ifdef __GNUC__
36 # undef alloca
37 # define alloca __builtin_alloca
38 # define HAVE_ALLOCA 1
39 #else
40 # ifdef _MSC_VER
41 #  include <malloc.h>
42 #  define alloca _alloca
43 # else
44 #  if defined HAVE_ALLOCA_H || defined _LIBC
45 #   include <alloca.h>
46 #  else
47 #   ifdef _AIX
48  #pragma alloca
49 #   else
50 #    ifndef alloca
51 char *alloca ();
52 #    endif
53 #   endif
54 #  endif
55 # endif
56 #endif
57
58 #include <stdlib.h>
59 #include <string.h>
60
61 #include "gettextP.h"
62
63 #ifdef ENABLE_RELOCATABLE
64 # include "relocatable.h"
65 #else
66 # define relocate(pathname) (pathname)
67 #endif
68
69 /* @@ end of prolog @@ */
70
71 #ifdef _LIBC
72 /* Rename the non ANSI C functions.  This is required by the standard
73    because some ANSI C functions will require linking with this object
74    file and the name space must not be polluted.  */
75 # define strcasecmp(s1, s2) __strcasecmp_l (s1, s2, _nl_C_locobj_ptr)
76
77 # ifndef mempcpy
78 #  define mempcpy __mempcpy
79 # endif
80 # define HAVE_MEMPCPY   1
81 # define HAVE___FSETLOCKING     1
82 #endif
83
84 /* Handle multi-threaded applications.  */
85 #ifdef _LIBC
86 # include <bits/libc-lock.h>
87 #else
88 # include "lock.h"
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_DECL_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_DECL_FEOF_UNLOCKED
118 # undef feof
119 # define feof(s) feof_unlocked (s)
120 #endif
121
122
123 __libc_lock_define_initialized (static, lock)
124
125
126 struct alias_map
127 {
128   const char *alias;
129   const char *value;
130 };
131
132
133 #ifndef _LIBC
134 # define libc_freeres_ptr(decl) decl
135 #endif
136
137 libc_freeres_ptr (static char *string_space);
138 static size_t string_space_act;
139 static size_t string_space_max;
140 libc_freeres_ptr (static struct alias_map *map);
141 static size_t nmap;
142 static size_t maxmap;
143
144
145 /* Prototypes for local functions.  */
146 static size_t read_alias_file (const char *fname, int fname_len)
147      internal_function;
148 static int extend_alias_table (void);
149 static int alias_compare (const struct alias_map *map1,
150                           const struct alias_map *map2);
151
152
153 const char *
154 _nl_expand_alias (const char *name)
155 {
156   static const char *locale_alias_path;
157   struct alias_map *retval;
158   const char *result = NULL;
159   size_t added;
160
161   __libc_lock_lock (lock);
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 (*) (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   __libc_lock_unlock (lock);
209
210   return result;
211 }
212
213
214 static size_t
215 internal_function
216 read_alias_file (const char *fname, int fname_len)
217 {
218   FILE *fp;
219   char *full_fname;
220   size_t added;
221   static const char aliasfile[] = "/locale.alias";
222
223   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
224 #ifdef HAVE_MEMPCPY
225   mempcpy (mempcpy (full_fname, fname, fname_len),
226            aliasfile, sizeof aliasfile);
227 #else
228   memcpy (full_fname, fname, fname_len);
229   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
230 #endif
231
232 #ifdef _LIBC
233   /* Note the file is opened with cancellation in the I/O functions
234      disabled.  */
235   fp = fopen (relocate (full_fname), "rce");
236 #else
237   fp = fopen (relocate (full_fname), "r");
238 #endif
239   freea (full_fname);
240   if (fp == NULL)
241     return 0;
242
243 #ifdef HAVE___FSETLOCKING
244   /* No threads present.  */
245   __fsetlocking (fp, FSETLOCKING_BYCALLER);
246 #endif
247
248   added = 0;
249   while (!FEOF (fp))
250     {
251       /* It is a reasonable approach to use a fix buffer here because
252          a) we are only interested in the first two fields
253          b) these fields must be usable as file names and so must not
254             be that long
255          We avoid a multi-kilobyte buffer here since this would use up
256          stack space which we might not have if the program ran out of
257          memory.  */
258       char buf[400];
259       char *alias;
260       char *value;
261       char *cp;
262       int complete_line;
263
264       if (FGETS (buf, sizeof buf, fp) == NULL)
265         /* EOF reached.  */
266         break;
267
268       /* Determine whether the line is complete.  */
269       complete_line = strchr (buf, '\n') != NULL;
270
271       cp = buf;
272       /* Ignore leading white space.  */
273       while (isspace ((unsigned char) cp[0]))
274         ++cp;
275
276       /* A leading '#' signals a comment line.  */
277       if (cp[0] != '\0' && cp[0] != '#')
278         {
279           alias = cp++;
280           while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
281             ++cp;
282           /* Terminate alias name.  */
283           if (cp[0] != '\0')
284             *cp++ = '\0';
285
286           /* Now look for the beginning of the value.  */
287           while (isspace ((unsigned char) cp[0]))
288             ++cp;
289
290           if (cp[0] != '\0')
291             {
292               value = cp++;
293               while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
294                 ++cp;
295               /* Terminate value.  */
296               if (cp[0] == '\n')
297                 {
298                   /* This has to be done to make the following test
299                      for the end of line possible.  We are looking for
300                      the terminating '\n' which do not overwrite here.  */
301                   *cp++ = '\0';
302                   *cp = '\n';
303                 }
304               else if (cp[0] != '\0')
305                 *cp++ = '\0';
306
307 #ifdef IN_LIBGLOCALE
308               /* glibc's locale.alias contains entries for ja_JP and ko_KR
309                  that make it impossible to use a Japanese or Korean UTF-8
310                  locale under the name "ja_JP" or "ko_KR".  Ignore these
311                  entries.  */
312               if (strchr (alias, '_') == NULL)
313 #endif
314                 {
315                   size_t alias_len;
316                   size_t value_len;
317
318                   if (nmap >= maxmap)
319                     if (__builtin_expect (extend_alias_table (), 0))
320                       goto out;
321
322                   alias_len = strlen (alias) + 1;
323                   value_len = strlen (value) + 1;
324
325                   if (string_space_act + alias_len + value_len > string_space_max)
326                     {
327                       /* Increase size of memory pool.  */
328                       size_t new_size = (string_space_max
329                                          + (alias_len + value_len > 1024
330                                             ? alias_len + value_len : 1024));
331                       char *new_pool = (char *) realloc (string_space, new_size);
332                       if (new_pool == NULL)
333                         goto out;
334
335                       if (__builtin_expect (string_space != new_pool, 0))
336                         {
337                           size_t i;
338
339                           for (i = 0; i < nmap; i++)
340                             {
341                               map[i].alias += new_pool - string_space;
342                               map[i].value += new_pool - string_space;
343                             }
344                         }
345
346                       string_space = new_pool;
347                       string_space_max = new_size;
348                     }
349
350                   map[nmap].alias =
351                     (const char *) memcpy (&string_space[string_space_act],
352                                            alias, alias_len);
353                   string_space_act += alias_len;
354
355                   map[nmap].value =
356                     (const char *) memcpy (&string_space[string_space_act],
357                                            value, value_len);
358                   string_space_act += value_len;
359
360                   ++nmap;
361                   ++added;
362                 }
363             }
364         }
365
366       /* Possibly not the whole line fits into the buffer.  Ignore
367          the rest of the line.  */
368       if (! complete_line)
369         do
370           if (FGETS (buf, sizeof buf, fp) == NULL)
371             /* Make sure the inner loop will be left.  The outer loop
372                will exit at the `feof' test.  */
373             break;
374         while (strchr (buf, '\n') == NULL);
375     }
376
377  out:
378   /* Should we test for ferror()?  I think we have to silently ignore
379      errors.  --drepper  */
380   fclose (fp);
381
382   if (added > 0)
383     qsort (map, nmap, sizeof (struct alias_map),
384            (int (*) (const void *, const void *)) alias_compare);
385
386   return added;
387 }
388
389
390 static int
391 extend_alias_table (void)
392 {
393   size_t new_size;
394   struct alias_map *new_map;
395
396   new_size = maxmap == 0 ? 100 : 2 * maxmap;
397   new_map = (struct alias_map *) realloc (map, (new_size
398                                                 * sizeof (struct alias_map)));
399   if (new_map == NULL)
400     /* Simply don't extend: we don't have any more core.  */
401     return -1;
402
403   map = new_map;
404   maxmap = new_size;
405   return 0;
406 }
407
408
409 static int
410 alias_compare (const struct alias_map *map1, const struct alias_map *map2)
411 {
412 #if defined _LIBC || defined HAVE_STRCASECMP
413   return strcasecmp (map1->alias, map2->alias);
414 #else
415   const unsigned char *p1 = (const unsigned char *) map1->alias;
416   const unsigned char *p2 = (const unsigned char *) map2->alias;
417   unsigned char c1, c2;
418
419   if (p1 == p2)
420     return 0;
421
422   do
423     {
424       /* I know this seems to be odd but the tolower() function in
425          some systems libc cannot handle nonalpha characters.  */
426       c1 = isupper (*p1) ? tolower (*p1) : *p1;
427       c2 = isupper (*p2) ? tolower (*p2) : *p2;
428       if (c1 == '\0')
429         break;
430       ++p1;
431       ++p2;
432     }
433   while (c1 == c2);
434
435   return c1 - c2;
436 #endif
437 }