]> git.ipfire.org Git - thirdparty/glibc.git/blob - intl/l10nflist.c
Update.
[thirdparty/glibc.git] / intl / l10nflist.c
1 /* Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
2 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 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 # 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 \f
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 \f
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. The return value is dynamically allocated and has to be
353 freed by the caller. */
354 const char *
355 _nl_normalize_codeset (codeset, name_len)
356 const char *codeset;
357 size_t name_len;
358 {
359 int len = 0;
360 int only_digit = 1;
361 char *retval;
362 char *wp;
363 size_t cnt;
364
365 for (cnt = 0; cnt < name_len; ++cnt)
366 if (isalnum (codeset[cnt]))
367 {
368 ++len;
369
370 if (isalpha (codeset[cnt]))
371 only_digit = 0;
372 }
373
374 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
375
376 if (retval != NULL)
377 {
378 if (only_digit)
379 wp = stpcpy (retval, "iso");
380 else
381 wp = retval;
382
383 for (cnt = 0; cnt < name_len; ++cnt)
384 if (isalpha (codeset[cnt]))
385 *wp++ = _tolower (codeset[cnt]);
386 else if (isdigit (codeset[cnt]))
387 *wp++ = codeset[cnt];
388
389 *wp = '\0';
390 }
391
392 return (const char *) retval;
393 }
394
395
396 /* @@ begin of epilog @@ */
397
398 /* We don't want libintl.a to depend on any other library. So we
399 avoid the non-standard function stpcpy. In GNU C Library this
400 function is available, though. Also allow the symbol HAVE_STPCPY
401 to be defined. */
402 #if !_LIBC && !HAVE_STPCPY
403 static char *
404 stpcpy (dest, src)
405 char *dest;
406 const char *src;
407 {
408 while ((*dest++ = *src++) != '\0')
409 /* Do nothing. */ ;
410 return dest - 1;
411 }
412 #endif