1 /* l10nflist.c - make localization file list. */
3 /* Copyright (C) 1995-1999, 2000, 2001, 2002, 2005-2009 Free Software Foundation, Inc.
4 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
6 This file is part of GNU Bash.
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
22 /* Tell glibc's <string.h> to provide a prototype for stpcpy().
23 This must come before <config.h> because <config.h> may include
24 <features.h>, and once <features.h> has been included, it's too late. */
26 # define _GNU_SOURCE 1
35 #if defined _LIBC || defined HAVE_ARGZ_H
39 #include <sys/types.h>
44 /* On some strange systems still no definition of NULL is found. Sigh! */
46 # if defined __STDC__ && __STDC__
47 # define NULL ((void *) 0)
53 /* @@ end of prolog @@ */
56 /* Rename the non ANSI C functions. This is required by the standard
57 because some ANSI C functions will require linking with this object
58 file and the name space must not be polluted. */
60 # define stpcpy(dest, src) __stpcpy(dest, src)
64 static char *stpcpy PARAMS ((char *dest, const char *src));
69 ISSLASH(C) tests whether C is a directory separator character.
70 IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
71 it may be concatenated to a directory pathname.
73 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
74 /* Win32, OS/2, DOS */
75 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
76 # define HAS_DEVICE(P) \
77 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
79 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
82 # define ISSLASH(C) ((C) == '/')
83 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
86 /* Define function which are usually not available. */
88 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
89 /* Returns the number of strings in ARGZ. */
90 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
93 argz_count__ (argz, len)
100 size_t part_len = strlen (argz);
101 argz += part_len + 1;
108 # define __argz_count(argz, len) argz_count__ (argz, len)
111 # define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
113 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
115 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
116 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
117 except the last into the character SEP. */
118 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
121 argz_stringify__ (argz, len, sep)
128 size_t part_len = strlen (argz);
135 # undef __argz_stringify
136 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
139 # define __argz_stringify(argz, len, sep) \
140 INTUSE(__argz_stringify) (argz, len, sep)
142 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
144 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
145 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
149 argz_next__ (argz, argz_len, entry)
156 if (entry < argz + argz_len)
157 entry = strchr (entry, '\0') + 1;
159 return entry >= argz + argz_len ? NULL : (char *) entry;
168 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
169 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
172 /* Return number of bits set in X. */
173 static int pop PARAMS ((int x));
179 /* We assume that no more than 16 bits are used. */
180 x = ((x & ~0x5555) >> 1) + (x & 0x5555);
181 x = ((x & ~0x3333) >> 2) + (x & 0x3333);
182 x = ((x >> 4) + x) & 0x0f0f;
183 x = ((x >> 8) + x) & 0xff;
189 struct loaded_l10nfile *
190 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
191 territory, codeset, normalized_codeset, modifier, special,
192 sponsor, revision, filename, do_allocate)
193 struct loaded_l10nfile **l10nfile_list;
197 const char *language;
198 const char *territory;
200 const char *normalized_codeset;
201 const char *modifier;
204 const char *revision;
205 const char *filename;
209 struct loaded_l10nfile **lastp;
210 struct loaded_l10nfile *retval;
212 size_t dirlist_count;
216 /* If LANGUAGE contains an absolute directory specification, we ignore
218 if (IS_ABSOLUTE_PATH (language))
221 /* Allocate room for the full file name. */
222 abs_filename = (char *) malloc (dirlist_len
224 + ((mask & TERRITORY) != 0
225 ? strlen (territory) + 1 : 0)
226 + ((mask & XPG_CODESET) != 0
227 ? strlen (codeset) + 1 : 0)
228 + ((mask & XPG_NORM_CODESET) != 0
229 ? strlen (normalized_codeset) + 1 : 0)
230 + (((mask & XPG_MODIFIER) != 0
231 || (mask & CEN_AUDIENCE) != 0)
232 ? strlen (modifier) + 1 : 0)
233 + ((mask & CEN_SPECIAL) != 0
234 ? strlen (special) + 1 : 0)
235 + (((mask & CEN_SPONSOR) != 0
236 || (mask & CEN_REVISION) != 0)
237 ? (1 + ((mask & CEN_SPONSOR) != 0
238 ? strlen (sponsor) : 0)
239 + ((mask & CEN_REVISION) != 0
240 ? strlen (revision) + 1 : 0)) : 0)
241 + 1 + strlen (filename) + 1);
243 if (abs_filename == NULL)
246 /* Construct file name. */
250 memcpy (cp, dirlist, dirlist_len);
251 __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
256 cp = stpcpy (cp, language);
258 if ((mask & TERRITORY) != 0)
261 cp = stpcpy (cp, territory);
263 if ((mask & XPG_CODESET) != 0)
266 cp = stpcpy (cp, codeset);
268 if ((mask & XPG_NORM_CODESET) != 0)
271 cp = stpcpy (cp, normalized_codeset);
273 if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
275 /* This component can be part of both syntaxes but has different
276 leading characters. For CEN we use `+', else `@'. */
277 *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
278 cp = stpcpy (cp, modifier);
280 if ((mask & CEN_SPECIAL) != 0)
283 cp = stpcpy (cp, special);
285 if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
288 if ((mask & CEN_SPONSOR) != 0)
289 cp = stpcpy (cp, sponsor);
290 if ((mask & CEN_REVISION) != 0)
293 cp = stpcpy (cp, revision);
298 stpcpy (cp, filename);
300 /* Look in list of already loaded domains whether it is already
302 lastp = l10nfile_list;
303 for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
304 if (retval->filename != NULL)
306 int compare = strcmp (retval->filename, abs_filename);
312 /* It's not in the list. */
317 lastp = &retval->next;
320 if (retval != NULL || do_allocate == 0)
326 dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
328 /* Allocate a new loaded_l10nfile. */
330 (struct loaded_l10nfile *)
331 malloc (sizeof (*retval)
332 + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
333 * sizeof (struct loaded_l10nfile *)));
337 retval->filename = abs_filename;
339 /* We set retval->data to NULL here; it is filled in later.
340 Setting retval->decided to 1 here means that retval does not
341 correspond to a real file (dirlist_count > 1) or is not worth
342 looking up (if an unnormalized codeset was specified). */
343 retval->decided = (dirlist_count > 1
344 || ((mask & XPG_CODESET) != 0
345 && (mask & XPG_NORM_CODESET) != 0));
348 retval->next = *lastp;
352 /* Recurse to fill the inheritance list of RETVAL.
353 If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
354 entry does not correspond to a real file; retval->filename contains
355 colons. In this case we loop across all elements of DIRLIST and
356 across all bit patterns dominated by MASK.
357 If the DIRLIST is a single directory or entirely redundant (i.e.
358 DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
359 MASK, excluding MASK itself.
360 In either case, we loop down from MASK to 0. This has the effect
361 that the extra bits in the locale name are dropped in this order:
362 first the modifier, then the territory, then the codeset, then the
363 normalized_codeset. */
364 for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
365 if ((cnt & ~mask) == 0
366 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
367 && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
369 if (dirlist_count > 1)
371 /* Iterate over all elements of the DIRLIST. */
374 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
376 retval->successor[entries++]
377 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
378 cnt, language, territory, codeset,
379 normalized_codeset, modifier, special,
380 sponsor, revision, filename, 1);
383 retval->successor[entries++]
384 = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
385 cnt, language, territory, codeset,
386 normalized_codeset, modifier, special,
387 sponsor, revision, filename, 1);
389 retval->successor[entries] = NULL;
394 /* Normalize codeset name. There is no standard for the codeset
395 names. Normalization allows the user to use any of the common
396 names. The return value is dynamically allocated and has to be
397 freed by the caller. */
399 _nl_normalize_codeset (codeset, name_len)
409 for (cnt = 0; cnt < name_len; ++cnt)
410 if (isalnum ((unsigned char) codeset[cnt]))
414 if (isalpha ((unsigned char) codeset[cnt]))
418 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
423 wp = stpcpy (retval, "iso");
427 for (cnt = 0; cnt < name_len; ++cnt)
428 if (isalpha ((unsigned char) codeset[cnt]))
429 *wp++ = tolower ((unsigned char) codeset[cnt]);
430 else if (isdigit ((unsigned char) codeset[cnt]))
431 *wp++ = codeset[cnt];
436 return (const char *) retval;
440 /* @@ begin of epilog @@ */
442 /* We don't want libintl.a to depend on any other library. So we
443 avoid the non-standard function stpcpy. In GNU C Library this
444 function is available, though. Also allow the symbol HAVE_STPCPY
446 #if !_LIBC && !HAVE_STPCPY
452 while ((*dest++ = *src++) != '\0')