1 1.1 mrg /* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. 2 1.1 mrg Contributed by Ulrich Drepper <drepper (at) gnu.ai.mit.edu>, 1995. 3 1.1 mrg 4 1.1 mrg This program is free software; you can redistribute it and/or modify it 5 1.1 mrg under the terms of the GNU Library General Public License as published 6 1.1 mrg by the Free Software Foundation; either version 2, or (at your option) 7 1.1 mrg any later version. 8 1.1 mrg 9 1.1 mrg This program is distributed in the hope that it will be useful, 10 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 11 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 1.1 mrg Library General Public License for more details. 13 1.1 mrg 14 1.1 mrg You should have received a copy of the GNU Library General Public 15 1.1 mrg License along with this program; if not, write to the Free Software 16 1.1 mrg Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 17 1.1 mrg USA. */ 18 1.1 mrg 19 1.1 mrg /* Tell glibc's <string.h> to provide a prototype for stpcpy(). 20 1.1 mrg This must come before <config.h> because <config.h> may include 21 1.1 mrg <features.h>, and once <features.h> has been included, it's too late. */ 22 1.1 mrg #ifndef _GNU_SOURCE 23 1.1 mrg # define _GNU_SOURCE 1 24 1.1 mrg #endif 25 1.1 mrg 26 1.1 mrg #ifdef HAVE_CONFIG_H 27 1.1 mrg # include <config.h> 28 1.1 mrg #endif 29 1.1 mrg 30 1.1 mrg #include <string.h> 31 1.1 mrg 32 1.1 mrg #if defined _LIBC || defined HAVE_ARGZ_H 33 1.1 mrg # include <argz.h> 34 1.1 mrg #endif 35 1.1 mrg #include <ctype.h> 36 1.1 mrg #include <sys/types.h> 37 1.1 mrg #include <stdlib.h> 38 1.1 mrg 39 1.1 mrg #include "loadinfo.h" 40 1.1 mrg 41 1.1 mrg /* On some strange systems still no definition of NULL is found. Sigh! */ 42 1.1 mrg #ifndef NULL 43 1.1 mrg # if defined __STDC__ && __STDC__ 44 1.1 mrg # define NULL ((void *) 0) 45 1.1 mrg # else 46 1.1 mrg # define NULL 0 47 1.1 mrg # endif 48 1.1 mrg #endif 49 1.1 mrg 50 1.1 mrg /* @@ end of prolog @@ */ 51 1.1 mrg 52 1.1 mrg #ifdef _LIBC 53 1.1 mrg /* Rename the non ANSI C functions. This is required by the standard 54 1.1 mrg because some ANSI C functions will require linking with this object 55 1.1 mrg file and the name space must not be polluted. */ 56 1.1 mrg # ifndef stpcpy 57 1.1 mrg # define stpcpy(dest, src) __stpcpy(dest, src) 58 1.1 mrg # endif 59 1.1 mrg #else 60 1.1 mrg # ifndef HAVE_STPCPY 61 1.1 mrg static char *stpcpy PARAMS ((char *dest, const char *src)); 62 1.1 mrg # endif 63 1.1 mrg #endif 64 1.1 mrg 65 1.1 mrg /* Pathname support. 66 1.1 mrg ISSLASH(C) tests whether C is a directory separator character. 67 1.1 mrg IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, 68 1.1 mrg it may be concatenated to a directory pathname. 69 1.1 mrg */ 70 1.1 mrg #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ 71 1.1 mrg /* Win32, OS/2, DOS */ 72 1.1 mrg # define ISSLASH(C) ((C) == '/' || (C) == '\\') 73 1.1 mrg # define HAS_DEVICE(P) \ 74 1.1 mrg ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ 75 1.1 mrg && (P)[1] == ':') 76 1.1 mrg # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) 77 1.1 mrg #else 78 1.1 mrg /* Unix */ 79 1.1 mrg # define ISSLASH(C) ((C) == '/') 80 1.1 mrg # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) 81 1.1 mrg #endif 82 1.1 mrg 83 1.1 mrg /* Define function which are usually not available. */ 84 1.1 mrg 85 1.1 mrg #if !defined _LIBC && !defined HAVE___ARGZ_COUNT 86 1.1 mrg /* Returns the number of strings in ARGZ. */ 87 1.1 mrg static size_t argz_count__ PARAMS ((const char *argz, size_t len)); 88 1.1 mrg 89 1.1 mrg static size_t 90 1.1 mrg argz_count__ (argz, len) 91 1.1 mrg const char *argz; 92 1.1 mrg size_t len; 93 1.1 mrg { 94 1.1 mrg size_t count = 0; 95 1.1 mrg while (len > 0) 96 1.1 mrg { 97 1.1 mrg size_t part_len = strlen (argz); 98 1.1 mrg argz += part_len + 1; 99 1.1 mrg len -= part_len + 1; 100 1.1 mrg count++; 101 1.1 mrg } 102 1.1 mrg return count; 103 1.1 mrg } 104 1.1 mrg # undef __argz_count 105 1.1 mrg # define __argz_count(argz, len) argz_count__ (argz, len) 106 1.1 mrg #else 107 1.1 mrg # ifdef _LIBC 108 1.1 mrg # define __argz_count(argz, len) INTUSE(__argz_count) (argz, len) 109 1.1 mrg # endif 110 1.1 mrg #endif /* !_LIBC && !HAVE___ARGZ_COUNT */ 111 1.1 mrg 112 1.1 mrg #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY 113 1.1 mrg /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's 114 1.1 mrg except the last into the character SEP. */ 115 1.1 mrg static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep)); 116 1.1 mrg 117 1.1 mrg static void 118 1.1 mrg argz_stringify__ (argz, len, sep) 119 1.1 mrg char *argz; 120 1.1 mrg size_t len; 121 1.1 mrg int sep; 122 1.1 mrg { 123 1.1 mrg while (len > 0) 124 1.1 mrg { 125 1.1 mrg size_t part_len = strlen (argz); 126 1.1 mrg argz += part_len; 127 1.1 mrg len -= part_len + 1; 128 1.1 mrg if (len > 0) 129 1.1 mrg *argz++ = sep; 130 1.1 mrg } 131 1.1 mrg } 132 1.1 mrg # undef __argz_stringify 133 1.1 mrg # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) 134 1.1 mrg #else 135 1.1 mrg # ifdef _LIBC 136 1.1 mrg # define __argz_stringify(argz, len, sep) \ 137 1.1 mrg INTUSE(__argz_stringify) (argz, len, sep) 138 1.1 mrg # endif 139 1.1 mrg #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ 140 1.1 mrg 141 1.1 mrg #if !defined _LIBC && !defined HAVE___ARGZ_NEXT 142 1.1 mrg static char *argz_next__ PARAMS ((char *argz, size_t argz_len, 143 1.1 mrg const char *entry)); 144 1.1 mrg 145 1.1 mrg static char * 146 1.1 mrg argz_next__ (argz, argz_len, entry) 147 1.1 mrg char *argz; 148 1.1 mrg size_t argz_len; 149 1.1 mrg const char *entry; 150 1.1 mrg { 151 1.1 mrg if (entry) 152 1.1 mrg { 153 1.1 mrg if (entry < argz + argz_len) 154 1.1 mrg entry = strchr (entry, '\0') + 1; 155 1.1 mrg 156 1.1 mrg return entry >= argz + argz_len ? NULL : (char *) entry; 157 1.1 mrg } 158 1.1 mrg else 159 1.1 mrg if (argz_len > 0) 160 1.1 mrg return argz; 161 1.1 mrg else 162 1.1 mrg return 0; 163 1.1 mrg } 164 1.1 mrg # undef __argz_next 165 1.1 mrg # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) 166 1.1 mrg #endif /* !_LIBC && !HAVE___ARGZ_NEXT */ 167 1.1 mrg 168 1.1 mrg 169 1.1 mrg /* Return number of bits set in X. */ 170 1.1 mrg static int pop PARAMS ((int x)); 171 1.1 mrg 172 1.1 mrg static inline int 173 1.1 mrg pop (x) 174 1.1 mrg int x; 175 1.1 mrg { 176 1.1 mrg /* We assume that no more than 16 bits are used. */ 177 1.1 mrg x = ((x & ~0x5555) >> 1) + (x & 0x5555); 178 1.1 mrg x = ((x & ~0x3333) >> 2) + (x & 0x3333); 179 1.1 mrg x = ((x >> 4) + x) & 0x0f0f; 180 1.1 mrg x = ((x >> 8) + x) & 0xff; 181 1.1 mrg 182 1.1 mrg return x; 183 1.1 mrg } 184 1.1 mrg 185 1.1 mrg 186 1.1 mrg struct loaded_l10nfile * 188 1.1 mrg _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, 189 1.1 mrg territory, codeset, normalized_codeset, modifier, special, 190 1.1 mrg sponsor, revision, filename, do_allocate) 191 1.1 mrg struct loaded_l10nfile **l10nfile_list; 192 1.1 mrg const char *dirlist; 193 1.1 mrg size_t dirlist_len; 194 1.1 mrg int mask; 195 1.1 mrg const char *language; 196 1.1 mrg const char *territory; 197 1.1 mrg const char *codeset; 198 1.1 mrg const char *normalized_codeset; 199 1.1 mrg const char *modifier; 200 1.1 mrg const char *special; 201 1.1 mrg const char *sponsor; 202 1.1 mrg const char *revision; 203 1.1 mrg const char *filename; 204 1.1 mrg int do_allocate; 205 1.1 mrg { 206 1.1 mrg char *abs_filename; 207 1.1 mrg struct loaded_l10nfile **lastp; 208 1.1 mrg struct loaded_l10nfile *retval; 209 1.1 mrg char *cp; 210 1.1 mrg size_t dirlist_count; 211 1.1 mrg size_t entries; 212 1.1 mrg int cnt; 213 1.1 mrg 214 1.1 mrg /* If LANGUAGE contains an absolute directory specification, we ignore 215 1.1 mrg DIRLIST. */ 216 1.1 mrg if (IS_ABSOLUTE_PATH (language)) 217 1.1 mrg dirlist_len = 0; 218 1.1 mrg 219 1.1 mrg /* Allocate room for the full file name. */ 220 1.1 mrg abs_filename = (char *) malloc (dirlist_len 221 1.1 mrg + strlen (language) 222 1.1 mrg + ((mask & TERRITORY) != 0 223 1.1 mrg ? strlen (territory) + 1 : 0) 224 1.1 mrg + ((mask & XPG_CODESET) != 0 225 1.1 mrg ? strlen (codeset) + 1 : 0) 226 1.1 mrg + ((mask & XPG_NORM_CODESET) != 0 227 1.1 mrg ? strlen (normalized_codeset) + 1 : 0) 228 1.1 mrg + (((mask & XPG_MODIFIER) != 0 229 1.1 mrg || (mask & CEN_AUDIENCE) != 0) 230 1.1 mrg ? strlen (modifier) + 1 : 0) 231 1.1 mrg + ((mask & CEN_SPECIAL) != 0 232 1.1 mrg ? strlen (special) + 1 : 0) 233 1.1 mrg + (((mask & CEN_SPONSOR) != 0 234 1.1 mrg || (mask & CEN_REVISION) != 0) 235 1.1 mrg ? (1 + ((mask & CEN_SPONSOR) != 0 236 1.1 mrg ? strlen (sponsor) : 0) 237 1.1 mrg + ((mask & CEN_REVISION) != 0 238 1.1 mrg ? strlen (revision) + 1 : 0)) : 0) 239 1.1 mrg + 1 + strlen (filename) + 1); 240 1.1 mrg 241 1.1 mrg if (abs_filename == NULL) 242 1.1 mrg return NULL; 243 1.1 mrg 244 1.1 mrg /* Construct file name. */ 245 1.1 mrg cp = abs_filename; 246 1.1 mrg if (dirlist_len > 0) 247 1.1 mrg { 248 1.1 mrg memcpy (cp, dirlist, dirlist_len); 249 1.1 mrg __argz_stringify (cp, dirlist_len, PATH_SEPARATOR); 250 1.1 mrg cp += dirlist_len; 251 1.1 mrg cp[-1] = '/'; 252 1.1 mrg } 253 1.1 mrg 254 1.1 mrg cp = stpcpy (cp, language); 255 1.1 mrg 256 1.1 mrg if ((mask & TERRITORY) != 0) 257 1.1 mrg { 258 1.1 mrg *cp++ = '_'; 259 1.1 mrg cp = stpcpy (cp, territory); 260 1.1 mrg } 261 1.1 mrg if ((mask & XPG_CODESET) != 0) 262 1.1 mrg { 263 1.1 mrg *cp++ = '.'; 264 1.1 mrg cp = stpcpy (cp, codeset); 265 1.1 mrg } 266 1.1 mrg if ((mask & XPG_NORM_CODESET) != 0) 267 1.1 mrg { 268 1.1 mrg *cp++ = '.'; 269 1.1 mrg cp = stpcpy (cp, normalized_codeset); 270 1.1 mrg } 271 1.1 mrg if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) 272 1.1 mrg { 273 1.1 mrg /* This component can be part of both syntaces but has different 274 1.1 mrg leading characters. For CEN we use `+', else `@'. */ 275 1.1 mrg *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; 276 1.1 mrg cp = stpcpy (cp, modifier); 277 1.1 mrg } 278 1.1 mrg if ((mask & CEN_SPECIAL) != 0) 279 1.1 mrg { 280 1.1 mrg *cp++ = '+'; 281 1.1 mrg cp = stpcpy (cp, special); 282 1.1 mrg } 283 1.1 mrg if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) 284 1.1 mrg { 285 1.1 mrg *cp++ = ','; 286 1.1 mrg if ((mask & CEN_SPONSOR) != 0) 287 1.1 mrg cp = stpcpy (cp, sponsor); 288 1.1 mrg if ((mask & CEN_REVISION) != 0) 289 1.1 mrg { 290 1.1 mrg *cp++ = '_'; 291 1.1 mrg cp = stpcpy (cp, revision); 292 1.1 mrg } 293 1.1 mrg } 294 1.1 mrg 295 1.1 mrg *cp++ = '/'; 296 1.1 mrg stpcpy (cp, filename); 297 1.1 mrg 298 1.1 mrg /* Look in list of already loaded domains whether it is already 299 1.1 mrg available. */ 300 1.1 mrg lastp = l10nfile_list; 301 1.1 mrg for (retval = *l10nfile_list; retval != NULL; retval = retval->next) 302 1.1 mrg if (retval->filename != NULL) 303 1.1 mrg { 304 1.1 mrg int compare = strcmp (retval->filename, abs_filename); 305 1.1 mrg if (compare == 0) 306 1.1 mrg /* We found it! */ 307 1.1 mrg break; 308 1.1 mrg if (compare < 0) 309 1.1 mrg { 310 1.1 mrg /* It's not in the list. */ 311 1.1 mrg retval = NULL; 312 1.1 mrg break; 313 1.1 mrg } 314 1.1 mrg 315 1.1 mrg lastp = &retval->next; 316 1.1 mrg } 317 1.1 mrg 318 1.1 mrg if (retval != NULL || do_allocate == 0) 319 1.1 mrg { 320 1.1 mrg free (abs_filename); 321 1.1 mrg return retval; 322 1.1 mrg } 323 1.1 mrg 324 1.1 mrg dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1); 325 1.1 mrg 326 1.1 mrg /* Allocate a new loaded_l10nfile. */ 327 1.1 mrg retval = 328 1.1 mrg (struct loaded_l10nfile *) 329 1.1 mrg malloc (sizeof (*retval) 330 1.1 mrg + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0)) 331 1.1 mrg * sizeof (struct loaded_l10nfile *))); 332 1.1 mrg if (retval == NULL) 333 1.1 mrg return NULL; 334 1.1 mrg 335 1.1 mrg retval->filename = abs_filename; 336 1.1 mrg 337 1.1 mrg /* We set retval->data to NULL here; it is filled in later. 338 1.1 mrg Setting retval->decided to 1 here means that retval does not 339 1.1 mrg correspond to a real file (dirlist_count > 1) or is not worth 340 1.1 mrg looking up (if an unnormalized codeset was specified). */ 341 1.1 mrg retval->decided = (dirlist_count > 1 342 1.1 mrg || ((mask & XPG_CODESET) != 0 343 1.1 mrg && (mask & XPG_NORM_CODESET) != 0)); 344 1.1 mrg retval->data = NULL; 345 1.1 mrg 346 1.1 mrg retval->next = *lastp; 347 1.1 mrg *lastp = retval; 348 1.1 mrg 349 1.1 mrg entries = 0; 350 1.1 mrg /* Recurse to fill the inheritance list of RETVAL. 351 1.1 mrg If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL 352 1.1 mrg entry does not correspond to a real file; retval->filename contains 353 1.1 mrg colons. In this case we loop across all elements of DIRLIST and 354 1.1 mrg across all bit patterns dominated by MASK. 355 1.1 mrg If the DIRLIST is a single directory or entirely redundant (i.e. 356 1.1 mrg DIRLIST_COUNT == 1), we loop across all bit patterns dominated by 357 1.1 mrg MASK, excluding MASK itself. 358 1.1 mrg In either case, we loop down from MASK to 0. This has the effect 359 1.1 mrg that the extra bits in the locale name are dropped in this order: 360 1.1 mrg first the modifier, then the territory, then the codeset, then the 361 1.1 mrg normalized_codeset. */ 362 1.1 mrg for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt) 363 1.1 mrg if ((cnt & ~mask) == 0 364 1.1 mrg && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) 365 1.1 mrg && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) 366 1.1 mrg { 367 1.1 mrg if (dirlist_count > 1) 368 1.1 mrg { 369 1.1 mrg /* Iterate over all elements of the DIRLIST. */ 370 1.1 mrg char *dir = NULL; 371 1.1 mrg 372 1.1 mrg while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) 373 1.1 mrg != NULL) 374 1.1 mrg retval->successor[entries++] 375 1.1 mrg = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, 376 1.1 mrg cnt, language, territory, codeset, 377 1.1 mrg normalized_codeset, modifier, special, 378 1.1 mrg sponsor, revision, filename, 1); 379 1.1 mrg } 380 1.1 mrg else 381 1.1 mrg retval->successor[entries++] 382 1.1 mrg = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, 383 1.1 mrg cnt, language, territory, codeset, 384 1.1 mrg normalized_codeset, modifier, special, 385 1.1 mrg sponsor, revision, filename, 1); 386 1.1 mrg } 387 1.1 mrg retval->successor[entries] = NULL; 388 1.1 mrg 389 1.1 mrg return retval; 390 1.1 mrg } 391 1.1 mrg 392 1.1 mrg /* Normalize codeset name. There is no standard for the codeset 394 1.1 mrg names. Normalization allows the user to use any of the common 395 1.1 mrg names. The return value is dynamically allocated and has to be 396 1.1 mrg freed by the caller. */ 397 1.1 mrg const char * 398 1.1 mrg _nl_normalize_codeset (codeset, name_len) 399 1.1 mrg const char *codeset; 400 1.1 mrg size_t name_len; 401 1.1 mrg { 402 1.1 mrg int len = 0; 403 1.1 mrg int only_digit = 1; 404 1.1 mrg char *retval; 405 1.1 mrg char *wp; 406 1.1 mrg size_t cnt; 407 1.1 mrg 408 1.1 mrg for (cnt = 0; cnt < name_len; ++cnt) 409 1.1 mrg if (isalnum ((unsigned char) codeset[cnt])) 410 1.1 mrg { 411 1.1 mrg ++len; 412 1.1 mrg 413 1.1 mrg if (isalpha ((unsigned char) codeset[cnt])) 414 1.1 mrg only_digit = 0; 415 1.1 mrg } 416 1.1 mrg 417 1.1 mrg retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); 418 1.1 mrg 419 1.1 mrg if (retval != NULL) 420 1.1 mrg { 421 1.1 mrg if (only_digit) 422 1.1 mrg wp = stpcpy (retval, "iso"); 423 1.1 mrg else 424 1.1 mrg wp = retval; 425 1.1 mrg 426 1.1 mrg for (cnt = 0; cnt < name_len; ++cnt) 427 1.1 mrg if (isalpha ((unsigned char) codeset[cnt])) 428 1.1 mrg *wp++ = tolower ((unsigned char) codeset[cnt]); 429 1.1 mrg else if (isdigit ((unsigned char) codeset[cnt])) 430 1.1 mrg *wp++ = codeset[cnt]; 431 1.1 mrg 432 1.1 mrg *wp = '\0'; 433 1.1 mrg } 434 1.1 mrg 435 1.1 mrg return (const char *) retval; 436 1.1 mrg } 437 1.1 mrg 438 1.1 mrg 439 1.1 mrg /* @@ begin of epilog @@ */ 440 1.1 mrg 441 1.1 mrg /* We don't want libintl.a to depend on any other library. So we 442 1.1 mrg avoid the non-standard function stpcpy. In GNU C Library this 443 1.1 mrg function is available, though. Also allow the symbol HAVE_STPCPY 444 1.1 mrg to be defined. */ 445 1.1 mrg #if !_LIBC && !HAVE_STPCPY 446 1.1 mrg static char * 447 1.1 mrg stpcpy (dest, src) 448 1.1 mrg char *dest; 449 1.1 mrg const char *src; 450 1.1 mrg { 451 1.1 mrg while ((*dest++ = *src++) != '\0') 452 1.1 mrg /* Do nothing. */ ; 453 1.1 mrg return dest - 1; 454 } 455 #endif 456