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