00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE 1
00024 #endif
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <ctype.h>
00031 #include <stdio.h>
00032 #if defined _LIBC || defined HAVE___FSETLOCKING
00033 # include <stdio_ext.h>
00034 #endif
00035 #include <sys/types.h>
00036
00037 #ifdef __GNUC__
00038 # define alloca __builtin_alloca
00039 # define HAVE_ALLOCA 1
00040 #else
00041 # if defined HAVE_ALLOCA_H || defined _LIBC
00042 # include <alloca.h>
00043 # else
00044 # ifdef _AIX
00045 #pragma alloca
00046 # else
00047 # ifndef alloca
00048 char *alloca ();
00049 # endif
00050 # endif
00051 # endif
00052 #endif
00053
00054 #include <stdlib.h>
00055 #include <string.h>
00056
00057 #include "gettextP.h"
00058
00059
00060
00061 #ifdef _LIBC
00062
00063
00064
00065 # define strcasecmp __strcasecmp
00066
00067 # ifndef mempcpy
00068 # define mempcpy __mempcpy
00069 # endif
00070 # define HAVE_MEMPCPY 1
00071 # define HAVE___FSETLOCKING 1
00072
00073
00074 # include <bits/libc-lock.h>
00075
00076 __libc_lock_define_initialized (static, lock);
00077 #endif
00078
00079 #ifndef internal_function
00080 # define internal_function
00081 #endif
00082
00083
00084 #ifdef _LIBC
00085 # define FEOF(fp) feof_unlocked (fp)
00086 # define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
00087 #else
00088 # define FEOF(fp) feof (fp)
00089 # define FGETS(buf, n, fp) fgets (buf, n, fp)
00090 #endif
00091
00092
00093
00094 #ifdef HAVE_ALLOCA
00095 # define freea(p)
00096 #else
00097 # define alloca(n) malloc (n)
00098 # define freea(p) free (p)
00099 #endif
00100
00101 #if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
00102 # undef fgets
00103 # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
00104 #endif
00105 #if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
00106 # undef feof
00107 # define feof(s) feof_unlocked (s)
00108 #endif
00109
00110
00111 struct alias_map
00112 {
00113 const char *alias;
00114 const char *value;
00115 };
00116
00117
00118 static char *string_space;
00119 static size_t string_space_act;
00120 static size_t string_space_max;
00121 static struct alias_map *map;
00122 static size_t nmap;
00123 static size_t maxmap;
00124
00125
00126
00127 static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
00128 internal_function;
00129 static int extend_alias_table PARAMS ((void));
00130 static int alias_compare PARAMS ((const struct alias_map *map1,
00131 const struct alias_map *map2));
00132
00133
00134 const char *
00135 _nl_expand_alias (name)
00136 const char *name;
00137 {
00138 static const char *locale_alias_path;
00139 struct alias_map *retval;
00140 const char *result = NULL;
00141 size_t added;
00142
00143 #ifdef _LIBC
00144 __libc_lock_lock (lock);
00145 #endif
00146
00147 if (locale_alias_path == NULL)
00148 locale_alias_path = LOCALE_ALIAS_PATH;
00149
00150 do
00151 {
00152 struct alias_map item;
00153
00154 item.alias = name;
00155
00156 if (nmap > 0)
00157 retval = (struct alias_map *) bsearch (&item, map, nmap,
00158 sizeof (struct alias_map),
00159 (int (*) PARAMS ((const void *,
00160 const void *))
00161 ) alias_compare);
00162 else
00163 retval = NULL;
00164
00165
00166 if (retval != NULL)
00167 {
00168 result = retval->value;
00169 break;
00170 }
00171
00172
00173 added = 0;
00174 while (added == 0 && locale_alias_path[0] != '\0')
00175 {
00176 const char *start;
00177
00178 while (locale_alias_path[0] == PATH_SEPARATOR)
00179 ++locale_alias_path;
00180 start = locale_alias_path;
00181
00182 while (locale_alias_path[0] != '\0'
00183 && locale_alias_path[0] != PATH_SEPARATOR)
00184 ++locale_alias_path;
00185
00186 if (start < locale_alias_path)
00187 added = read_alias_file (start, locale_alias_path - start);
00188 }
00189 }
00190 while (added != 0);
00191
00192 #ifdef _LIBC
00193 __libc_lock_unlock (lock);
00194 #endif
00195
00196 return result;
00197 }
00198
00199
00200 static size_t
00201 internal_function
00202 read_alias_file (fname, fname_len)
00203 const char *fname;
00204 int fname_len;
00205 {
00206 FILE *fp;
00207 char *full_fname;
00208 size_t added;
00209 static const char aliasfile[] = "/locale.alias";
00210
00211 full_fname = (char *) alloca (fname_len + sizeof aliasfile);
00212 #ifdef HAVE_MEMPCPY
00213 mempcpy (mempcpy (full_fname, fname, fname_len),
00214 aliasfile, sizeof aliasfile);
00215 #else
00216 memcpy (full_fname, fname, fname_len);
00217 memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
00218 #endif
00219
00220 fp = fopen (full_fname, "r");
00221 freea (full_fname);
00222 if (fp == NULL)
00223 return 0;
00224
00225 #ifdef HAVE___FSETLOCKING
00226
00227 __fsetlocking (fp, FSETLOCKING_BYCALLER);
00228 #endif
00229
00230 added = 0;
00231 while (!FEOF (fp))
00232 {
00233
00234
00235
00236
00237
00238 char buf[BUFSIZ];
00239 char *alias;
00240 char *value;
00241 char *cp;
00242
00243 if (FGETS (buf, sizeof buf, fp) == NULL)
00244
00245 break;
00246
00247
00248
00249 if (strchr (buf, '\n') == NULL)
00250 {
00251 char altbuf[BUFSIZ];
00252 do
00253 if (FGETS (altbuf, sizeof altbuf, fp) == NULL)
00254
00255
00256 break;
00257 while (strchr (altbuf, '\n') == NULL);
00258 }
00259
00260 cp = buf;
00261
00262 while (isspace ((unsigned char) cp[0]))
00263 ++cp;
00264
00265
00266 if (cp[0] != '\0' && cp[0] != '#')
00267 {
00268 alias = cp++;
00269 while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
00270 ++cp;
00271
00272 if (cp[0] != '\0')
00273 *cp++ = '\0';
00274
00275
00276 while (isspace ((unsigned char) cp[0]))
00277 ++cp;
00278
00279 if (cp[0] != '\0')
00280 {
00281 size_t alias_len;
00282 size_t value_len;
00283
00284 value = cp++;
00285 while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
00286 ++cp;
00287
00288 if (cp[0] == '\n')
00289 {
00290
00291
00292
00293 *cp++ = '\0';
00294 *cp = '\n';
00295 }
00296 else if (cp[0] != '\0')
00297 *cp++ = '\0';
00298
00299 if (nmap >= maxmap)
00300 if (__builtin_expect (extend_alias_table (), 0))
00301 return added;
00302
00303 alias_len = strlen (alias) + 1;
00304 value_len = strlen (value) + 1;
00305
00306 if (string_space_act + alias_len + value_len > string_space_max)
00307 {
00308
00309 size_t new_size = (string_space_max
00310 + (alias_len + value_len > 1024
00311 ? alias_len + value_len : 1024));
00312 char *new_pool = (char *) realloc (string_space, new_size);
00313 if (new_pool == NULL)
00314 return added;
00315
00316 if (__builtin_expect (string_space != new_pool, 0))
00317 {
00318 size_t i;
00319
00320 for (i = 0; i < nmap; i++)
00321 {
00322 map[i].alias += new_pool - string_space;
00323 map[i].value += new_pool - string_space;
00324 }
00325 }
00326
00327 string_space = new_pool;
00328 string_space_max = new_size;
00329 }
00330
00331 map[nmap].alias = memcpy (&string_space[string_space_act],
00332 alias, alias_len);
00333 string_space_act += alias_len;
00334
00335 map[nmap].value = memcpy (&string_space[string_space_act],
00336 value, value_len);
00337 string_space_act += value_len;
00338
00339 ++nmap;
00340 ++added;
00341 }
00342 }
00343 }
00344
00345
00346
00347 fclose (fp);
00348
00349 if (added > 0)
00350 qsort (map, nmap, sizeof (struct alias_map),
00351 (int (*) PARAMS ((const void *, const void *))) alias_compare);
00352
00353 return added;
00354 }
00355
00356
00357 static int
00358 extend_alias_table ()
00359 {
00360 size_t new_size;
00361 struct alias_map *new_map;
00362
00363 new_size = maxmap == 0 ? 100 : 2 * maxmap;
00364 new_map = (struct alias_map *) realloc (map, (new_size
00365 * sizeof (struct alias_map)));
00366 if (new_map == NULL)
00367
00368 return -1;
00369
00370 map = new_map;
00371 maxmap = new_size;
00372 return 0;
00373 }
00374
00375
00376 #ifdef _LIBC
00377 static void __attribute__ ((unused))
00378 free_mem (void)
00379 {
00380 if (string_space != NULL)
00381 free (string_space);
00382 if (map != NULL)
00383 free (map);
00384 }
00385 text_set_element (__libc_subfreeres, free_mem);
00386 #endif
00387
00388
00389 static int
00390 alias_compare (map1, map2)
00391 const struct alias_map *map1;
00392 const struct alias_map *map2;
00393 {
00394 #if defined _LIBC || defined HAVE_STRCASECMP
00395 return strcasecmp (map1->alias, map2->alias);
00396 #else
00397 const unsigned char *p1 = (const unsigned char *) map1->alias;
00398 const unsigned char *p2 = (const unsigned char *) map2->alias;
00399 unsigned char c1, c2;
00400
00401 if (p1 == p2)
00402 return 0;
00403
00404 do
00405 {
00406
00407
00408 c1 = isupper (*p1) ? tolower (*p1) : *p1;
00409 c2 = isupper (*p2) ? tolower (*p2) : *p2;
00410 if (c1 == '\0')
00411 break;
00412 ++p1;
00413 ++p2;
00414 }
00415 while (c1 == c2);
00416
00417 return c1 - c2;
00418 #endif
00419 }