l10nflist.c revision 1.1 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