]> git.ipfire.org Git - thirdparty/glibc.git/blob - intl/l10nflist.c
Update.
[thirdparty/glibc.git] / intl / l10nflist.c
1 /* Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 /* Tell glibc's <string.h> to provide a prototype for stpcpy().
21 This must come before <config.h> because <config.h> may include
22 <features.h>, and once <features.h> has been included, it's too late. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <string.h>
32
33 #if defined _LIBC || defined HAVE_ARGZ_H
34 # include <argz.h>
35 #endif
36 #include <ctype.h>
37 #include <sys/types.h>
38 #include <stdlib.h>
39
40 #include "loadinfo.h"
41
42 /* On some strange systems still no definition of NULL is found. Sigh! */
43 #ifndef NULL
44 # if defined __STDC__ && __STDC__
45 # define NULL ((void *) 0)
46 # else
47 # define NULL 0
48 # endif
49 #endif
50
51 /* @@ end of prolog @@ */
52
53 #ifdef _LIBC
54 /* Rename the non ANSI C functions. This is required by the standard
55 because some ANSI C functions will require linking with this object
56 file and the name space must not be polluted. */
57 # ifndef stpcpy
58 # define stpcpy(dest, src) __stpcpy(dest, src)
59 # endif
60 #else
61 # ifndef HAVE_STPCPY
62 static char *stpcpy PARAMS ((char *dest, const char *src));
63 # endif
64 #endif
65
66 /* Define function which are usually not available. */
67
68 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
69 /* Returns the number of strings in ARGZ. */
70 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
71
72 static size_t
73 argz_count__ (argz, len)
74 const char *argz;
75 size_t len;
76 {
77 size_t count = 0;
78 while (len > 0)
79 {
80 size_t part_len = strlen (argz);
81 argz += part_len + 1;
82 len -= part_len + 1;
83 count++;
84 }
85 return count;
86 }
87 # undef __argz_count
88 # define __argz_count(argz, len) argz_count__ (argz, len)
89 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
90
91 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
92 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
93 except the last into the character SEP. */
94 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
95
96 static void
97 argz_stringify__ (argz, len, sep)
98 char *argz;
99 size_t len;
100 int sep;
101 {
102 while (len > 0)
103 {
104 size_t part_len = strlen (argz);
105 argz += part_len;
106 len -= part_len + 1;
107 if (len > 0)
108 *argz++ = sep;
109 }
110 }
111 # undef __argz_stringify
112 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
113 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
114
115 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
116 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
117 const char *entry));
118
119 static char *
120 argz_next__ (argz, argz_len, entry)
121 char *argz;
122 size_t argz_len;
123 const char *entry;
124 {
125 if (entry)
126 {
127 if (entry < argz + argz_len)
128 entry = strchr (entry, '\0') + 1;
129
130 return entry >= argz + argz_len ? NULL : (char *) entry;
131 }
132 else
133 if (argz_len > 0)
134 return argz;
135 else
136 return 0;
137 }
138 # undef __argz_next
139 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
140 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
141
142
143 /* Return number of bits set in X. */
144 static int pop PARAMS ((int x));
145
146 static inline int
147 pop (x)
148 int x;
149 {
150 /* We assume that no more than 16 bits are used. */
151 x = ((x & ~0x5555) >> 1) + (x & 0x5555);
152 x = ((x & ~0x3333) >> 2) + (x & 0x3333);
153 x = ((x >> 4) + x) & 0x0f0f;
154 x = ((x >> 8) + x) & 0xff;
155
156 return x;
157 }
158
159 \f
160 struct loaded_l10nfile *
161 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
162 territory, codeset, normalized_codeset, modifier, special,
163 sponsor, revision, filename, do_allocate)
164 struct loaded_l10nfile **l10nfile_list;
165 const char *dirlist;
166 size_t dirlist_len;
167 int mask;
168 const char *language;
169 const char *territory;
170 const char *codeset;
171 const char *normalized_codeset;
172 const char *modifier;
173 const char *special;
174 const char *sponsor;
175 const char *revision;
176 const char *filename;
177 int do_allocate;
178 {
179 char *abs_filename;
180 struct loaded_l10nfile *last = NULL;
181 struct loaded_l10nfile *retval;
182 char *cp;
183 size_t entries;
184 int cnt;
185
186 /* Allocate room for the full file name. */
187 abs_filename = (char *) malloc (dirlist_len
188 + strlen (language)
189 + ((mask & TERRITORY) != 0
190 ? strlen (territory) + 1 : 0)
191 + ((mask & XPG_CODESET) != 0
192 ? strlen (codeset) + 1 : 0)
193 + ((mask & XPG_NORM_CODESET) != 0
194 ? strlen (normalized_codeset) + 1 : 0)
195 + (((mask & XPG_MODIFIER) != 0
196 || (mask & CEN_AUDIENCE) != 0)
197 ? strlen (modifier) + 1 : 0)
198 + ((mask & CEN_SPECIAL) != 0
199 ? strlen (special) + 1 : 0)
200 + (((mask & CEN_SPONSOR) != 0
201 || (mask & CEN_REVISION) != 0)
202 ? (1 + ((mask & CEN_SPONSOR) != 0
203 ? strlen (sponsor) + 1 : 0)
204 + ((mask & CEN_REVISION) != 0
205 ? strlen (revision) + 1 : 0)) : 0)
206 + 1 + strlen (filename) + 1);
207
208 if (abs_filename == NULL)
209 return NULL;
210
211 retval = NULL;
212 last = NULL;
213
214 /* Construct file name. */
215 memcpy (abs_filename, dirlist, dirlist_len);
216 __argz_stringify (abs_filename, dirlist_len, ':');
217 cp = abs_filename + (dirlist_len - 1);
218 *cp++ = '/';
219 cp = stpcpy (cp, language);
220
221 if ((mask & TERRITORY) != 0)
222 {
223 *cp++ = '_';
224 cp = stpcpy (cp, territory);
225 }
226 if ((mask & XPG_CODESET) != 0)
227 {
228 *cp++ = '.';
229 cp = stpcpy (cp, codeset);
230 }
231 if ((mask & XPG_NORM_CODESET) != 0)
232 {
233 *cp++ = '.';
234 cp = stpcpy (cp, normalized_codeset);
235 }
236 if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
237 {
238 /* This component can be part of both syntaces but has different
239 leading characters. For CEN we use `+', else `@'. */
240 *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
241 cp = stpcpy (cp, modifier);
242 }
243 if ((mask & CEN_SPECIAL) != 0)
244 {
245 *cp++ = '+';
246 cp = stpcpy (cp, special);
247 }
248 if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
249 {
250 *cp++ = ',';
251 if ((mask & CEN_SPONSOR) != 0)
252 cp = stpcpy (cp, sponsor);
253 if ((mask & CEN_REVISION) != 0)
254 {
255 *cp++ = '_';
256 cp = stpcpy (cp, revision);
257 }
258 }
259
260 *cp++ = '/';
261 stpcpy (cp, filename);
262
263 /* Look in list of already loaded domains whether it is already
264 available. */
265 last = NULL;
266 for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
267 if (retval->filename != NULL)
268 {
269 int compare = strcmp (retval->filename, abs_filename);
270 if (compare == 0)
271 /* We found it! */
272 break;
273 if (compare < 0)
274 {
275 /* It's not in the list. */
276 retval = NULL;
277 break;
278 }
279
280 last = retval;
281 }
282
283 if (retval != NULL || do_allocate == 0)
284 {
285 free (abs_filename);
286 return retval;
287 }
288
289 retval = (struct loaded_l10nfile *)
290 malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
291 * (1 << pop (mask))
292 * sizeof (struct loaded_l10nfile *)));
293 if (retval == NULL)
294 return NULL;
295
296 retval->filename = abs_filename;
297 retval->decided = (__argz_count (dirlist, dirlist_len) != 1
298 || ((mask & XPG_CODESET) != 0
299 && (mask & XPG_NORM_CODESET) != 0));
300 retval->data = NULL;
301
302 if (last == NULL)
303 {
304 retval->next = *l10nfile_list;
305 *l10nfile_list = retval;
306 }
307 else
308 {
309 retval->next = last->next;
310 last->next = retval;
311 }
312
313 entries = 0;
314 /* If the DIRLIST is a real list the RETVAL entry corresponds not to
315 a real file. So we have to use the DIRLIST separation mechanism
316 of the inner loop. */
317 cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
318 for (; cnt >= 0; --cnt)
319 if ((cnt & ~mask) == 0
320 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
321 && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
322 {
323 /* Iterate over all elements of the DIRLIST. */
324 char *dir = NULL;
325
326 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
327 != NULL)
328 retval->successor[entries++]
329 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
330 language, territory, codeset,
331 normalized_codeset, modifier, special,
332 sponsor, revision, filename, 1);
333 }
334 retval->successor[entries] = NULL;
335
336 return retval;
337 }
338 \f
339 /* Normalize codeset name. There is no standard for the codeset
340 names. Normalization allows the user to use any of the common
341 names. The return value is dynamically allocated and has to be
342 freed by the caller. */
343 const char *
344 _nl_normalize_codeset (codeset, name_len)
345 const char *codeset;
346 size_t name_len;
347 {
348 int len = 0;
349 int only_digit = 1;
350 char *retval;
351 char *wp;
352 size_t cnt;
353
354 for (cnt = 0; cnt < name_len; ++cnt)
355 if (isalnum ((unsigned char) codeset[cnt]))
356 {
357 ++len;
358
359 if (isalpha ((unsigned char) codeset[cnt]))
360 only_digit = 0;
361 }
362
363 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
364
365 if (retval != NULL)
366 {
367 if (only_digit)
368 wp = stpcpy (retval, "iso");
369 else
370 wp = retval;
371
372 for (cnt = 0; cnt < name_len; ++cnt)
373 if (isalpha ((unsigned char) codeset[cnt]))
374 *wp++ = tolower ((unsigned char) codeset[cnt]);
375 else if (isdigit ((unsigned char) codeset[cnt]))
376 *wp++ = codeset[cnt];
377
378 *wp = '\0';
379 }
380
381 return (const char *) retval;
382 }
383
384
385 /* @@ begin of epilog @@ */
386
387 /* We don't want libintl.a to depend on any other library. So we
388 avoid the non-standard function stpcpy. In GNU C Library this
389 function is available, though. Also allow the symbol HAVE_STPCPY
390 to be defined. */
391 #if !_LIBC && !HAVE_STPCPY
392 static char *
393 stpcpy (dest, src)
394 char *dest;
395 const char *src;
396 {
397 while ((*dest++ = *src++) != '\0')
398 /* Do nothing. */ ;
399 return dest - 1;
400 }
401 #endif