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 <string.h>
00031
00032 #if defined _LIBC || defined HAVE_ARGZ_H
00033 # include <argz.h>
00034 #endif
00035 #include <ctype.h>
00036 #include <sys/types.h>
00037 #include <stdlib.h>
00038
00039 #include "loadinfo.h"
00040
00041
00042 #ifndef NULL
00043 # if defined __STDC__ && __STDC__
00044 # define NULL ((void *) 0)
00045 # else
00046 # define NULL 0
00047 # endif
00048 #endif
00049
00050
00051
00052 #ifdef _LIBC
00053
00054
00055
00056 # ifndef stpcpy
00057 # define stpcpy(dest, src) __stpcpy(dest, src)
00058 # endif
00059 #else
00060 # ifndef HAVE_STPCPY
00061 static char *stpcpy PARAMS ((char *dest, const char *src));
00062 # endif
00063 #endif
00064
00065
00066
00067
00068
00069
00070 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
00071
00072 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
00073 # define HAS_DEVICE(P) \
00074 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
00075 && (P)[1] == ':')
00076 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
00077 #else
00078
00079 # define ISSLASH(C) ((C) == '/')
00080 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
00081 #endif
00082
00083
00084
00085 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
00086
00087 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
00088
00089 static size_t
00090 argz_count__ (argz, len)
00091 const char *argz;
00092 size_t len;
00093 {
00094 size_t count = 0;
00095 while (len > 0)
00096 {
00097 size_t part_len = strlen (argz);
00098 argz += part_len + 1;
00099 len -= part_len + 1;
00100 count++;
00101 }
00102 return count;
00103 }
00104 # undef __argz_count
00105 # define __argz_count(argz, len) argz_count__ (argz, len)
00106 #else
00107 # ifdef _LIBC
00108 # define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
00109 # endif
00110 #endif
00111
00112 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
00113
00114
00115 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
00116
00117 static void
00118 argz_stringify__ (argz, len, sep)
00119 char *argz;
00120 size_t len;
00121 int sep;
00122 {
00123 while (len > 0)
00124 {
00125 size_t part_len = strlen (argz);
00126 argz += part_len;
00127 len -= part_len + 1;
00128 if (len > 0)
00129 *argz++ = sep;
00130 }
00131 }
00132 # undef __argz_stringify
00133 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
00134 #else
00135 # ifdef _LIBC
00136 # define __argz_stringify(argz, len, sep) \
00137 INTUSE(__argz_stringify) (argz, len, sep)
00138 # endif
00139 #endif
00140
00141 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
00142 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
00143 const char *entry));
00144
00145 static char *
00146 argz_next__ (argz, argz_len, entry)
00147 char *argz;
00148 size_t argz_len;
00149 const char *entry;
00150 {
00151 if (entry)
00152 {
00153 if (entry < argz + argz_len)
00154 entry = strchr (entry, '\0') + 1;
00155
00156 return entry >= argz + argz_len ? NULL : (char *) entry;
00157 }
00158 else
00159 if (argz_len > 0)
00160 return argz;
00161 else
00162 return 0;
00163 }
00164 # undef __argz_next
00165 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
00166 #endif
00167
00168
00169
00170 static int pop PARAMS ((int x));
00171
00172 static inline int
00173 pop (x)
00174 int x;
00175 {
00176
00177 x = ((x & ~0x5555) >> 1) + (x & 0x5555);
00178 x = ((x & ~0x3333) >> 2) + (x & 0x3333);
00179 x = ((x >> 4) + x) & 0x0f0f;
00180 x = ((x >> 8) + x) & 0xff;
00181
00182 return x;
00183 }
00184
00185
00186 struct loaded_l10nfile *
00187 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
00188 territory, codeset, normalized_codeset, modifier, special,
00189 sponsor, revision, filename, do_allocate)
00190 struct loaded_l10nfile **l10nfile_list;
00191 const char *dirlist;
00192 size_t dirlist_len;
00193 int mask;
00194 const char *language;
00195 const char *territory;
00196 const char *codeset;
00197 const char *normalized_codeset;
00198 const char *modifier;
00199 const char *special;
00200 const char *sponsor;
00201 const char *revision;
00202 const char *filename;
00203 int do_allocate;
00204 {
00205 char *abs_filename;
00206 struct loaded_l10nfile **lastp;
00207 struct loaded_l10nfile *retval;
00208 char *cp;
00209 size_t dirlist_count;
00210 size_t entries;
00211 int cnt;
00212
00213
00214
00215 if (IS_ABSOLUTE_PATH (language))
00216 dirlist_len = 0;
00217
00218
00219 abs_filename = (char *) malloc (dirlist_len
00220 + strlen (language)
00221 + ((mask & TERRITORY) != 0
00222 ? strlen (territory) + 1 : 0)
00223 + ((mask & XPG_CODESET) != 0
00224 ? strlen (codeset) + 1 : 0)
00225 + ((mask & XPG_NORM_CODESET) != 0
00226 ? strlen (normalized_codeset) + 1 : 0)
00227 + (((mask & XPG_MODIFIER) != 0
00228 || (mask & CEN_AUDIENCE) != 0)
00229 ? strlen (modifier) + 1 : 0)
00230 + ((mask & CEN_SPECIAL) != 0
00231 ? strlen (special) + 1 : 0)
00232 + (((mask & CEN_SPONSOR) != 0
00233 || (mask & CEN_REVISION) != 0)
00234 ? (1 + ((mask & CEN_SPONSOR) != 0
00235 ? strlen (sponsor) : 0)
00236 + ((mask & CEN_REVISION) != 0
00237 ? strlen (revision) + 1 : 0)) : 0)
00238 + 1 + strlen (filename) + 1);
00239
00240 if (abs_filename == NULL)
00241 return NULL;
00242
00243
00244 cp = abs_filename;
00245 if (dirlist_len > 0)
00246 {
00247 memcpy (cp, dirlist, dirlist_len);
00248 __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
00249 cp += dirlist_len;
00250 cp[-1] = '/';
00251 }
00252
00253 cp = stpcpy (cp, language);
00254
00255 if ((mask & TERRITORY) != 0)
00256 {
00257 *cp++ = '_';
00258 cp = stpcpy (cp, territory);
00259 }
00260 if ((mask & XPG_CODESET) != 0)
00261 {
00262 *cp++ = '.';
00263 cp = stpcpy (cp, codeset);
00264 }
00265 if ((mask & XPG_NORM_CODESET) != 0)
00266 {
00267 *cp++ = '.';
00268 cp = stpcpy (cp, normalized_codeset);
00269 }
00270 if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
00271 {
00272
00273
00274 *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
00275 cp = stpcpy (cp, modifier);
00276 }
00277 if ((mask & CEN_SPECIAL) != 0)
00278 {
00279 *cp++ = '+';
00280 cp = stpcpy (cp, special);
00281 }
00282 if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
00283 {
00284 *cp++ = ',';
00285 if ((mask & CEN_SPONSOR) != 0)
00286 cp = stpcpy (cp, sponsor);
00287 if ((mask & CEN_REVISION) != 0)
00288 {
00289 *cp++ = '_';
00290 cp = stpcpy (cp, revision);
00291 }
00292 }
00293
00294 *cp++ = '/';
00295 stpcpy (cp, filename);
00296
00297
00298
00299 lastp = l10nfile_list;
00300 for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
00301 if (retval->filename != NULL)
00302 {
00303 int compare = strcmp (retval->filename, abs_filename);
00304 if (compare == 0)
00305
00306 break;
00307 if (compare < 0)
00308 {
00309
00310 retval = NULL;
00311 break;
00312 }
00313
00314 lastp = &retval->next;
00315 }
00316
00317 if (retval != NULL || do_allocate == 0)
00318 {
00319 free (abs_filename);
00320 return retval;
00321 }
00322
00323 dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
00324
00325
00326 retval =
00327 (struct loaded_l10nfile *)
00328 malloc (sizeof (*retval)
00329 + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
00330 * sizeof (struct loaded_l10nfile *)));
00331 if (retval == NULL)
00332 return NULL;
00333
00334 retval->filename = abs_filename;
00335
00336
00337
00338
00339
00340 retval->decided = (dirlist_count > 1
00341 || ((mask & XPG_CODESET) != 0
00342 && (mask & XPG_NORM_CODESET) != 0));
00343 retval->data = NULL;
00344
00345 retval->next = *lastp;
00346 *lastp = retval;
00347
00348 entries = 0;
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
00362 if ((cnt & ~mask) == 0
00363 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
00364 && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
00365 {
00366 if (dirlist_count > 1)
00367 {
00368
00369 char *dir = NULL;
00370
00371 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
00372 != NULL)
00373 retval->successor[entries++]
00374 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
00375 cnt, language, territory, codeset,
00376 normalized_codeset, modifier, special,
00377 sponsor, revision, filename, 1);
00378 }
00379 else
00380 retval->successor[entries++]
00381 = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
00382 cnt, language, territory, codeset,
00383 normalized_codeset, modifier, special,
00384 sponsor, revision, filename, 1);
00385 }
00386 retval->successor[entries] = NULL;
00387
00388 return retval;
00389 }
00390
00391
00392
00393
00394
00395 const char *
00396 _nl_normalize_codeset (codeset, name_len)
00397 const char *codeset;
00398 size_t name_len;
00399 {
00400 int len = 0;
00401 int only_digit = 1;
00402 char *retval;
00403 char *wp;
00404 size_t cnt;
00405
00406 for (cnt = 0; cnt < name_len; ++cnt)
00407 if (isalnum ((unsigned char) codeset[cnt]))
00408 {
00409 ++len;
00410
00411 if (isalpha ((unsigned char) codeset[cnt]))
00412 only_digit = 0;
00413 }
00414
00415 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
00416
00417 if (retval != NULL)
00418 {
00419 if (only_digit)
00420 wp = stpcpy (retval, "iso");
00421 else
00422 wp = retval;
00423
00424 for (cnt = 0; cnt < name_len; ++cnt)
00425 if (isalpha ((unsigned char) codeset[cnt]))
00426 *wp++ = tolower ((unsigned char) codeset[cnt]);
00427 else if (isdigit ((unsigned char) codeset[cnt]))
00428 *wp++ = codeset[cnt];
00429
00430 *wp = '\0';
00431 }
00432
00433 return (const char *) retval;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 #if !_LIBC && !HAVE_STPCPY
00444 static char *
00445 stpcpy (dest, src)
00446 char *dest;
00447 const char *src;
00448 {
00449 while ((*dest++ = *src++) != '\0')
00450 ;
00451 return dest - 1;
00452 }
00453 #endif