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