1 /* Handle list of needed message catalogs 2 Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. 3 Written 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 # define stpcpy(dest, src) __stpcpy(dest, src) 69 #else 70 # ifndef HAVE_STPCPY 71 static char *stpcpy PARAMS ((char *dest, const char *src)); 72 # endif 73 #endif 74 75 /* Define function which are usually not available. */ 76 77 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT 78 /* Returns the number of strings in ARGZ. */ 79 static size_t argz_count__ PARAMS ((const char *argz, size_t len)); 80 81 static size_t 82 argz_count__ (argz, len) 83 const char *argz; 84 size_t len; 85 { 86 size_t count = 0; 87 while (len > 0) 88 { 89 size_t part_len = strlen (argz); 90 argz += part_len + 1; 91 len -= part_len + 1; 92 count++; 93 } 94 return count; 95 } 96 # undef __argz_count 97 # define __argz_count(argz, len) argz_count__ (argz, len) 98 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */ 99 100 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY 101 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's 102 except the last into the character SEP. */ 103 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep)); 104 105 static void 106 argz_stringify__ (argz, len, sep) 107 char *argz; 108 size_t len; 109 int sep; 110 { 111 while (len > 0) 112 { 113 size_t part_len = strlen (argz); 114 argz += part_len; 115 len -= part_len + 1; 116 if (len > 0) 117 *argz++ = sep; 118 } 119 } 120 # undef __argz_stringify 121 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) 122 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ 123 124 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT 125 static char *argz_next__ PARAMS ((char *argz, size_t argz_len, 126 const char *entry)); 127 128 static char * 129 argz_next__ (argz, argz_len, entry) 130 char *argz; 131 size_t argz_len; 132 const char *entry; 133 { 134 if (entry) 135 { 136 if (entry < argz + argz_len) 137 entry = strchr (entry, '\0') + 1; 138 139 return entry >= argz + argz_len ? NULL : (char *) entry; 140 } 141 else 142 if (argz_len > 0) 143 return argz; 144 else 145 return 0; 146 } 147 # undef __argz_next 148 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) 149 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */ 150 151 152 /* Return number of bits set in X. */ 153 static int pop PARAMS ((int x)); 154 155 static inline int 156 pop (x) 157 int x; 158 { 159 /* We assume that no more than 16 bits are used. */ 160 x = ((x & ~0x5555) >> 1) + (x & 0x5555); 161 x = ((x & ~0x3333) >> 2) + (x & 0x3333); 162 x = ((x >> 4) + x) & 0x0f0f; 163 x = ((x >> 8) + x) & 0xff; 164 165 return x; 166 } 167 168 169 struct loaded_l10nfile * 170 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, 171 territory, codeset, normalized_codeset, modifier, special, 172 sponsor, revision, filename, do_allocate) 173 struct loaded_l10nfile **l10nfile_list; 174 const char *dirlist; 175 size_t dirlist_len; 176 int mask; 177 const char *language; 178 const char *territory; 179 const char *codeset; 180 const char *normalized_codeset; 181 const char *modifier; 182 const char *special; 183 const char *sponsor; 184 const char *revision; 185 const char *filename; 186 int do_allocate; 187 { 188 char *abs_filename; 189 struct loaded_l10nfile *last = NULL; 190 struct loaded_l10nfile *retval; 191 char *cp; 192 size_t entries; 193 int cnt; 194 195 /* Allocate room for the full file name. */ 196 abs_filename = (char *) malloc (dirlist_len 197 + strlen (language) 198 + ((mask & TERRITORY) != 0 199 ? strlen (territory) + 1 : 0) 200 + ((mask & XPG_CODESET) != 0 201 ? strlen (codeset) + 1 : 0) 202 + ((mask & XPG_NORM_CODESET) != 0 203 ? strlen (normalized_codeset) + 1 : 0) 204 + (((mask & XPG_MODIFIER) != 0 205 || (mask & CEN_AUDIENCE) != 0) 206 ? strlen (modifier) + 1 : 0) 207 + ((mask & CEN_SPECIAL) != 0 208 ? strlen (special) + 1 : 0) 209 + (((mask & CEN_SPONSOR) != 0 210 || (mask & CEN_REVISION) != 0) 211 ? (1 + ((mask & CEN_SPONSOR) != 0 212 ? strlen (sponsor) + 1 : 0) 213 + ((mask & CEN_REVISION) != 0 214 ? strlen (revision) + 1 : 0)) : 0) 215 + 1 + strlen (filename) + 1); 216 217 if (abs_filename == NULL) 218 return NULL; 219 220 retval = NULL; 221 last = NULL; 222 223 /* Construct file name. */ 224 memcpy (abs_filename, dirlist, dirlist_len); 225 __argz_stringify (abs_filename, dirlist_len, ':'); 226 cp = abs_filename + (dirlist_len - 1); 227 *cp++ = '/'; 228 cp = stpcpy (cp, language); 229 230 if ((mask & TERRITORY) != 0) 231 { 232 *cp++ = '_'; 233 cp = stpcpy (cp, territory); 234 } 235 if ((mask & XPG_CODESET) != 0) 236 { 237 *cp++ = '.'; 238 cp = stpcpy (cp, codeset); 239 } 240 if ((mask & XPG_NORM_CODESET) != 0) 241 { 242 *cp++ = '.'; 243 cp = stpcpy (cp, normalized_codeset); 244 } 245 if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) 246 { 247 /* This component can be part of both syntaces but has different 248 leading characters. For CEN we use `+', else `@'. */ 249 *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; 250 cp = stpcpy (cp, modifier); 251 } 252 if ((mask & CEN_SPECIAL) != 0) 253 { 254 *cp++ = '+'; 255 cp = stpcpy (cp, special); 256 } 257 if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) 258 { 259 *cp++ = ','; 260 if ((mask & CEN_SPONSOR) != 0) 261 cp = stpcpy (cp, sponsor); 262 if ((mask & CEN_REVISION) != 0) 263 { 264 *cp++ = '_'; 265 cp = stpcpy (cp, revision); 266 } 267 } 268 269 *cp++ = '/'; 270 stpcpy (cp, filename); 271 272 /* Look in list of already loaded domains whether it is already 273 available. */ 274 last = NULL; 275 for (retval = *l10nfile_list; retval != NULL; retval = retval->next) 276 if (retval->filename != NULL) 277 { 278 int compare = strcmp (retval->filename, abs_filename); 279 if (compare == 0) 280 /* We found it! */ 281 break; 282 if (compare < 0) 283 { 284 /* It's not in the list. */ 285 retval = NULL; 286 break; 287 } 288 289 last = retval; 290 } 291 292 if (retval != NULL || do_allocate == 0) 293 { 294 free (abs_filename); 295 return retval; 296 } 297 298 retval = (struct loaded_l10nfile *) 299 malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len) 300 * (1 << pop (mask)) 301 * sizeof (struct loaded_l10nfile *))); 302 if (retval == NULL) 303 return NULL; 304 305 retval->filename = abs_filename; 306 retval->decided = (__argz_count (dirlist, dirlist_len) != 1 307 || ((mask & XPG_CODESET) != 0 308 && (mask & XPG_NORM_CODESET) != 0)); 309 retval->data = NULL; 310 311 if (last == NULL) 312 { 313 retval->next = *l10nfile_list; 314 *l10nfile_list = retval; 315 } 316 else 317 { 318 retval->next = last->next; 319 last->next = retval; 320 } 321 322 entries = 0; 323 /* If the DIRLIST is a real list the RETVAL entry corresponds not to 324 a real file. So we have to use the DIRLIST separation mechanism 325 of the inner loop. */ 326 cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask; 327 for (; cnt >= 0; --cnt) 328 if ((cnt & ~mask) == 0 329 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) 330 && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) 331 { 332 /* Iterate over all elements of the DIRLIST. */ 333 char *dir = NULL; 334 335 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) 336 != NULL) 337 retval->successor[entries++] 338 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt, 339 language, territory, codeset, 340 normalized_codeset, modifier, special, 341 sponsor, revision, filename, 1); 342 } 343 retval->successor[entries] = NULL; 344 345 return retval; 346 } 347 348 /* Normalize codeset name. There is no standard for the codeset 349 names. Normalization allows the user to use any of the common 350 names. */ 351 const char * 352 _nl_normalize_codeset (codeset, name_len) 353 const char *codeset; 354 size_t name_len; 355 { 356 int len = 0; 357 int only_digit = 1; 358 char *retval; 359 char *wp; 360 size_t cnt; 361 362 for (cnt = 0; cnt < name_len; ++cnt) 363 if (isalnum (codeset[cnt])) 364 { 365 ++len; 366 367 if (isalpha (codeset[cnt])) 368 only_digit = 0; 369 } 370 371 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); 372 373 if (retval != NULL) 374 { 375 if (only_digit) 376 wp = stpcpy (retval, "iso"); 377 else 378 wp = retval; 379 380 for (cnt = 0; cnt < name_len; ++cnt) 381 if (isalpha (codeset[cnt])) 382 *wp++ = tolower (codeset[cnt]); 383 else if (isdigit (codeset[cnt])) 384 *wp++ = codeset[cnt]; 385 386 *wp = '\0'; 387 } 388 389 return (const char *) retval; 390 } 391 392 393 /* @@ begin of epilog @@ */ 394 395 /* We don't want libintl.a to depend on any other library. So we 396 avoid the non-standard function stpcpy. In GNU C Library this 397 function is available, though. Also allow the symbol HAVE_STPCPY 398 to be defined. */ 399 #if !_LIBC && !HAVE_STPCPY 400 static char * 401 stpcpy (dest, src) 402 char *dest; 403 const char *src; 404 { 405 while ((*dest++ = *src++) != '\0') 406 /* Do nothing. */ ; 407 return dest - 1; 408 } 409 #endif 410