Back to Evolution Project page
00001 /* Handle list of needed message catalogs 00002 Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. 00003 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2, or (at your option) 00008 any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software Foundation, 00017 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 00018 00019 #ifdef HAVE_CONFIG_H 00020 # include <config.h> 00021 #endif 00022 00023 00024 #if defined HAVE_STRING_H || defined _LIBC 00025 # ifndef _GNU_SOURCE 00026 # define _GNU_SOURCE 1 00027 # endif 00028 # include <string.h> 00029 #else 00030 # include <strings.h> 00031 # ifndef memcpy 00032 # define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num) 00033 # endif 00034 #endif 00035 #if !HAVE_STRCHR && !defined _LIBC 00036 # ifndef strchr 00037 # define strchr index 00038 # endif 00039 #endif 00040 00041 #if defined _LIBC || defined HAVE_ARGZ_H 00042 # include <argz.h> 00043 #endif 00044 #include <ctype.h> 00045 #include <sys/types.h> 00046 00047 #if defined STDC_HEADERS || defined _LIBC 00048 # include <stdlib.h> 00049 #endif 00050 00051 #include "loadinfo.h" 00052 00053 /* On some strange systems still no definition of NULL is found. Sigh! */ 00054 #ifndef NULL 00055 # if defined __STDC__ && __STDC__ 00056 # define NULL ((void *) 0) 00057 # else 00058 # define NULL 0 00059 # endif 00060 #endif 00061 00062 /* @@ end of prolog @@ */ 00063 00064 #ifdef _LIBC 00065 /* Rename the non ANSI C functions. This is required by the standard 00066 because some ANSI C functions will require linking with this object 00067 file and the name space must not be polluted. */ 00068 # ifndef stpcpy 00069 # define stpcpy(dest, src) __stpcpy(dest, src) 00070 # endif 00071 #else 00072 # ifndef HAVE_STPCPY 00073 static char *stpcpy PARAMS ((char *dest, const char *src)); 00074 # endif 00075 #endif 00076 00077 /* Define function which are usually not available. */ 00078 00079 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT 00080 /* Returns the number of strings in ARGZ. */ 00081 static size_t argz_count__ PARAMS ((const char *argz, size_t len)); 00082 00083 static size_t 00084 argz_count__ (argz, len) 00085 const char *argz; 00086 size_t len; 00087 { 00088 size_t count = 0; 00089 while (len > 0) 00090 { 00091 size_t part_len = strlen (argz); 00092 argz += part_len + 1; 00093 len -= part_len + 1; 00094 count++; 00095 } 00096 return count; 00097 } 00098 # undef __argz_count 00099 # define __argz_count(argz, len) argz_count__ (argz, len) 00100 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */ 00101 00102 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY 00103 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's 00104 except the last into the character SEP. */ 00105 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep)); 00106 00107 static void 00108 argz_stringify__ (argz, len, sep) 00109 char *argz; 00110 size_t len; 00111 int sep; 00112 { 00113 while (len > 0) 00114 { 00115 size_t part_len = strlen (argz); 00116 argz += part_len; 00117 len -= part_len + 1; 00118 if (len > 0) 00119 *argz++ = sep; 00120 } 00121 } 00122 # undef __argz_stringify 00123 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) 00124 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ 00125 00126 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT 00127 static char *argz_next__ PARAMS ((char *argz, size_t argz_len, 00128 const char *entry)); 00129 00130 static char * 00131 argz_next__ (argz, argz_len, entry) 00132 char *argz; 00133 size_t argz_len; 00134 const char *entry; 00135 { 00136 if (entry) 00137 { 00138 if (entry < argz + argz_len) 00139 entry = strchr (entry, '\0') + 1; 00140 00141 return entry >= argz + argz_len ? NULL : (char *) entry; 00142 } 00143 else 00144 if (argz_len > 0) 00145 return argz; 00146 else 00147 return 0; 00148 } 00149 # undef __argz_next 00150 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) 00151 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */ 00152 00153 00154 /* Return number of bits set in X. */ 00155 static int pop PARAMS ((int x)); 00156 00157 static inline int 00158 pop (x) 00159 int x; 00160 { 00161 /* We assume that no more than 16 bits are used. */ 00162 x = ((x & ~0x5555) >> 1) + (x & 0x5555); 00163 x = ((x & ~0x3333) >> 2) + (x & 0x3333); 00164 x = ((x >> 4) + x) & 0x0f0f; 00165 x = ((x >> 8) + x) & 0xff; 00166 00167 return x; 00168 } 00169 00170 00171 struct loaded_l10nfile * 00172 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, 00173 territory, codeset, normalized_codeset, modifier, special, 00174 sponsor, revision, filename, do_allocate) 00175 struct loaded_l10nfile **l10nfile_list; 00176 const char *dirlist; 00177 size_t dirlist_len; 00178 int mask; 00179 const char *language; 00180 const char *territory; 00181 const char *codeset; 00182 const char *normalized_codeset; 00183 const char *modifier; 00184 const char *special; 00185 const char *sponsor; 00186 const char *revision; 00187 const char *filename; 00188 int do_allocate; 00189 { 00190 char *abs_filename; 00191 struct loaded_l10nfile *last = NULL; 00192 struct loaded_l10nfile *retval; 00193 char *cp; 00194 size_t entries; 00195 int cnt; 00196 00197 /* Allocate room for the full file name. */ 00198 abs_filename = (char *) malloc (dirlist_len 00199 + strlen (language) 00200 + ((mask & TERRITORY) != 0 00201 ? strlen (territory) + 1 : 0) 00202 + ((mask & XPG_CODESET) != 0 00203 ? strlen (codeset) + 1 : 0) 00204 + ((mask & XPG_NORM_CODESET) != 0 00205 ? strlen (normalized_codeset) + 1 : 0) 00206 + (((mask & XPG_MODIFIER) != 0 00207 || (mask & CEN_AUDIENCE) != 0) 00208 ? strlen (modifier) + 1 : 0) 00209 + ((mask & CEN_SPECIAL) != 0 00210 ? strlen (special) + 1 : 0) 00211 + (((mask & CEN_SPONSOR) != 0 00212 || (mask & CEN_REVISION) != 0) 00213 ? (1 + ((mask & CEN_SPONSOR) != 0 00214 ? strlen (sponsor) + 1 : 0) 00215 + ((mask & CEN_REVISION) != 0 00216 ? strlen (revision) + 1 : 0)) : 0) 00217 + 1 + strlen (filename) + 1); 00218 00219 if (abs_filename == NULL) 00220 return NULL; 00221 00222 retval = NULL; 00223 last = NULL; 00224 00225 /* Construct file name. */ 00226 memcpy (abs_filename, dirlist, dirlist_len); 00227 __argz_stringify (abs_filename, dirlist_len, ':'); 00228 cp = abs_filename + (dirlist_len - 1); 00229 *cp++ = '/'; 00230 cp = stpcpy (cp, language); 00231 00232 if ((mask & TERRITORY) != 0) 00233 { 00234 *cp++ = '_'; 00235 cp = stpcpy (cp, territory); 00236 } 00237 if ((mask & XPG_CODESET) != 0) 00238 { 00239 *cp++ = '.'; 00240 cp = stpcpy (cp, codeset); 00241 } 00242 if ((mask & XPG_NORM_CODESET) != 0) 00243 { 00244 *cp++ = '.'; 00245 cp = stpcpy (cp, normalized_codeset); 00246 } 00247 if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) 00248 { 00249 /* This component can be part of both syntaces but has different 00250 leading characters. For CEN we use `+', else `@'. */ 00251 *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; 00252 cp = stpcpy (cp, modifier); 00253 } 00254 if ((mask & CEN_SPECIAL) != 0) 00255 { 00256 *cp++ = '+'; 00257 cp = stpcpy (cp, special); 00258 } 00259 if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) 00260 { 00261 *cp++ = ','; 00262 if ((mask & CEN_SPONSOR) != 0) 00263 cp = stpcpy (cp, sponsor); 00264 if ((mask & CEN_REVISION) != 0) 00265 { 00266 *cp++ = '_'; 00267 cp = stpcpy (cp, revision); 00268 } 00269 } 00270 00271 *cp++ = '/'; 00272 stpcpy (cp, filename); 00273 00274 /* Look in list of already loaded domains whether it is already 00275 available. */ 00276 last = NULL; 00277 for (retval = *l10nfile_list; retval != NULL; retval = retval->next) 00278 if (retval->filename != NULL) 00279 { 00280 int compare = strcmp (retval->filename, abs_filename); 00281 if (compare == 0) 00282 /* We found it! */ 00283 break; 00284 if (compare < 0) 00285 { 00286 /* It's not in the list. */ 00287 retval = NULL; 00288 break; 00289 } 00290 00291 last = retval; 00292 } 00293 00294 if (retval != NULL || do_allocate == 0) 00295 { 00296 free (abs_filename); 00297 return retval; 00298 } 00299 00300 retval = (struct loaded_l10nfile *) 00301 malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len) 00302 * (1 << pop (mask)) 00303 * sizeof (struct loaded_l10nfile *))); 00304 if (retval == NULL) 00305 return NULL; 00306 00307 retval->filename = abs_filename; 00308 retval->decided = (__argz_count (dirlist, dirlist_len) != 1 00309 || ((mask & XPG_CODESET) != 0 00310 && (mask & XPG_NORM_CODESET) != 0)); 00311 retval->data = NULL; 00312 00313 if (last == NULL) 00314 { 00315 retval->next = *l10nfile_list; 00316 *l10nfile_list = retval; 00317 } 00318 else 00319 { 00320 retval->next = last->next; 00321 last->next = retval; 00322 } 00323 00324 entries = 0; 00325 /* If the DIRLIST is a real list the RETVAL entry corresponds not to 00326 a real file. So we have to use the DIRLIST separation mechanism 00327 of the inner loop. */ 00328 cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask; 00329 for (; cnt >= 0; --cnt) 00330 if ((cnt & ~mask) == 0 00331 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) 00332 && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) 00333 { 00334 /* Iterate over all elements of the DIRLIST. */ 00335 char *dir = NULL; 00336 00337 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) 00338 != NULL) 00339 retval->successor[entries++] 00340 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt, 00341 language, territory, codeset, 00342 normalized_codeset, modifier, special, 00343 sponsor, revision, filename, 1); 00344 } 00345 retval->successor[entries] = NULL; 00346 00347 return retval; 00348 } 00349 00350 /* Normalize codeset name. There is no standard for the codeset 00351 names. Normalization allows the user to use any of the common 00352 names. */ 00353 const char * 00354 _nl_normalize_codeset (codeset, name_len) 00355 const char *codeset; 00356 size_t name_len; 00357 { 00358 int len = 0; 00359 int only_digit = 1; 00360 char *retval; 00361 char *wp; 00362 size_t cnt; 00363 00364 for (cnt = 0; cnt < name_len; ++cnt) 00365 if (isalnum (codeset[cnt])) 00366 { 00367 ++len; 00368 00369 if (isalpha (codeset[cnt])) 00370 only_digit = 0; 00371 } 00372 00373 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); 00374 00375 if (retval != NULL) 00376 { 00377 if (only_digit) 00378 wp = stpcpy (retval, "iso"); 00379 else 00380 wp = retval; 00381 00382 for (cnt = 0; cnt < name_len; ++cnt) 00383 if (isalpha (codeset[cnt])) 00384 *wp++ = tolower (codeset[cnt]); 00385 else if (isdigit (codeset[cnt])) 00386 *wp++ = codeset[cnt]; 00387 00388 *wp = '\0'; 00389 } 00390 00391 return (const char *) retval; 00392 } 00393 00394 00395 /* @@ begin of epilog @@ */ 00396 00397 /* We don't want libintl.a to depend on any other library. So we 00398 avoid the non-standard function stpcpy. In GNU C Library this 00399 function is available, though. Also allow the symbol HAVE_STPCPY 00400 to be defined. */ 00401 #if !_LIBC && !HAVE_STPCPY 00402 static char * 00403 stpcpy (dest, src) 00404 char *dest; 00405 const char *src; 00406 { 00407 while ((*dest++ = *src++) != '\0') 00408 /* Do nothing. */ ; 00409 return dest - 1; 00410 } 00411 #endif