]> git.ipfire.org Git - thirdparty/glibc.git/blame - intl/l10nflist.c
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / intl / l10nflist.c
CommitLineData
568035b7 1/* Copyright (C) 1995-2013 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 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
7a12c6bb 18
0a55a284
UD
19/* Tell glibc's <string.h> to provide a prototype for stpcpy().
20 This must come before <config.h> because <config.h> may include
21 <features.h>, and once <features.h> has been included, it's too late. */
22#ifndef _GNU_SOURCE
23# define _GNU_SOURCE 1
24#endif
25
92f3773b
RM
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
0555fcce 30#include <string.h>
7a12c6bb 31
96e1bff2
RM
32#if defined _LIBC || defined HAVE_ARGZ_H
33# include <argz.h>
34#endif
35#include <ctype.h>
0c5ecdc4 36#include <sys/types.h>
0555fcce 37#include <stdlib.h>
96e1bff2 38
7a12c6bb
RM
39#include "loadinfo.h"
40
842907c6
RM
41/* On some strange systems still no definition of NULL is found. Sigh! */
42#ifndef NULL
43# if defined __STDC__ && __STDC__
44# define NULL ((void *) 0)
45# else
46# define NULL 0
47# endif
48#endif
49
92f3773b
RM
50/* @@ end of prolog @@ */
51
52#ifdef _LIBC
53/* Rename the non ANSI C functions. This is required by the standard
54 because some ANSI C functions will require linking with this object
55 file and the name space must not be polluted. */
9a0a462c
UD
56# ifndef stpcpy
57# define stpcpy(dest, src) __stpcpy(dest, src)
58# endif
92f3773b
RM
59#else
60# ifndef HAVE_STPCPY
61static char *stpcpy PARAMS ((char *dest, const char *src));
62# endif
63#endif
64
5f2eab42
RM
65/* Define function which are usually not available. */
66
842907c6 67#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
5f2eab42 68/* Returns the number of strings in ARGZ. */
842907c6 69static size_t argz_count__ PARAMS ((const char *argz, size_t len));
5f2eab42
RM
70
71static size_t
842907c6 72argz_count__ (argz, len)
5f2eab42
RM
73 const char *argz;
74 size_t len;
75{
76 size_t count = 0;
77 while (len > 0)
78 {
92f3773b 79 size_t part_len = strlen (argz);
5f2eab42
RM
80 argz += part_len + 1;
81 len -= part_len + 1;
82 count++;
83 }
84 return count;
85}
842907c6
RM
86# undef __argz_count
87# define __argz_count(argz, len) argz_count__ (argz, len)
88#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
5f2eab42 89
842907c6 90#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
5f2eab42
RM
91/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
92 except the last into the character SEP. */
842907c6 93static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
5f2eab42
RM
94
95static void
842907c6 96argz_stringify__ (argz, len, sep)
5f2eab42
RM
97 char *argz;
98 size_t len;
99 int sep;
100{
101 while (len > 0)
102 {
92f3773b 103 size_t part_len = strlen (argz);
5f2eab42
RM
104 argz += part_len;
105 len -= part_len + 1;
106 if (len > 0)
107 *argz++ = sep;
108 }
109}
842907c6
RM
110# undef __argz_stringify
111# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
112#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
113
114#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
115static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
116 const char *entry));
5f2eab42 117
5f2eab42 118static char *
842907c6 119argz_next__ (argz, argz_len, entry)
92f3773b
RM
120 char *argz;
121 size_t argz_len;
122 const char *entry;
5f2eab42
RM
123{
124 if (entry)
125 {
126 if (entry < argz + argz_len)
89edf2e9 127 entry = strchr (entry, '\0') + 1;
5f2eab42
RM
128
129 return entry >= argz + argz_len ? NULL : (char *) entry;
130 }
131 else
132 if (argz_len > 0)
133 return argz;
134 else
135 return 0;
136}
842907c6
RM
137# undef __argz_next
138# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
139#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
5f2eab42
RM
140
141
7a12c6bb 142/* Return number of bits set in X. */
8e999d29 143#ifndef ARCH_POP
92f3773b 144static int pop PARAMS ((int x));
7a12c6bb
RM
145
146static inline int
147pop (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}
8e999d29 158#endif
7a12c6bb 159
5f2eab42 160\f
7a12c6bb
RM
161struct loaded_l10nfile *
162_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
e155c801
UD
163 territory, codeset, normalized_codeset, modifier,
164 filename, do_allocate)
7a12c6bb
RM
165 struct loaded_l10nfile **l10nfile_list;
166 const char *dirlist;
167 size_t dirlist_len;
168 int mask;
169 const char *language;
170 const char *territory;
171 const char *codeset;
172 const char *normalized_codeset;
173 const char *modifier;
7a12c6bb
RM
174 const char *filename;
175 int do_allocate;
176{
177 char *abs_filename;
178 struct loaded_l10nfile *last = NULL;
179 struct loaded_l10nfile *retval;
180 char *cp;
181 size_t entries;
182 int cnt;
183
184 /* Allocate room for the full file name. */
185 abs_filename = (char *) malloc (dirlist_len
186 + strlen (language)
e155c801 187 + ((mask & XPG_TERRITORY) != 0
7a12c6bb
RM
188 ? strlen (territory) + 1 : 0)
189 + ((mask & XPG_CODESET) != 0
190 ? strlen (codeset) + 1 : 0)
191 + ((mask & XPG_NORM_CODESET) != 0
192 ? strlen (normalized_codeset) + 1 : 0)
e155c801 193 + ((mask & XPG_MODIFIER) != 0
47707456 194 ? strlen (modifier) + 1 : 0)
7a12c6bb
RM
195 + 1 + strlen (filename) + 1);
196
197 if (abs_filename == NULL)
198 return NULL;
199
200 retval = NULL;
201 last = NULL;
202
203 /* Construct file name. */
204 memcpy (abs_filename, dirlist, dirlist_len);
205 __argz_stringify (abs_filename, dirlist_len, ':');
206 cp = abs_filename + (dirlist_len - 1);
207 *cp++ = '/';
208 cp = stpcpy (cp, language);
209
e155c801 210 if ((mask & XPG_TERRITORY) != 0)
7a12c6bb
RM
211 {
212 *cp++ = '_';
213 cp = stpcpy (cp, territory);
214 }
215 if ((mask & XPG_CODESET) != 0)
216 {
217 *cp++ = '.';
218 cp = stpcpy (cp, codeset);
219 }
220 if ((mask & XPG_NORM_CODESET) != 0)
221 {
222 *cp++ = '.';
223 cp = stpcpy (cp, normalized_codeset);
224 }
e155c801 225 if ((mask & XPG_MODIFIER) != 0)
7a12c6bb 226 {
e155c801 227 *cp++ = '@';
7a12c6bb
RM
228 cp = stpcpy (cp, modifier);
229 }
7a12c6bb
RM
230
231 *cp++ = '/';
232 stpcpy (cp, filename);
233
234 /* Look in list of already loaded domains whether it is already
235 available. */
236 last = NULL;
237 for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
238 if (retval->filename != NULL)
239 {
240 int compare = strcmp (retval->filename, abs_filename);
241 if (compare == 0)
242 /* We found it! */
243 break;
244 if (compare < 0)
245 {
246 /* It's not in the list. */
247 retval = NULL;
248 break;
249 }
250
251 last = retval;
252 }
253
254 if (retval != NULL || do_allocate == 0)
255 {
256 free (abs_filename);
257 return retval;
258 }
259
260 retval = (struct loaded_l10nfile *)
261 malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
262 * (1 << pop (mask))
263 * sizeof (struct loaded_l10nfile *)));
264 if (retval == NULL)
c6813ffe
RM
265 {
266 free (abs_filename);
267 return NULL;
268 }
7a12c6bb
RM
269
270 retval->filename = abs_filename;
ce7265c7
UD
271 /* If more than one directory is in the list this is a pseudo-entry
272 which just references others. We do not try to load data for it,
273 ever. */
7a12c6bb
RM
274 retval->decided = (__argz_count (dirlist, dirlist_len) != 1
275 || ((mask & XPG_CODESET) != 0
276 && (mask & XPG_NORM_CODESET) != 0));
277 retval->data = NULL;
278
279 if (last == NULL)
280 {
281 retval->next = *l10nfile_list;
282 *l10nfile_list = retval;
283 }
284 else
285 {
286 retval->next = last->next;
287 last->next = retval;
288 }
289
290 entries = 0;
6d52618b
UD
291 /* If the DIRLIST is a real list the RETVAL entry corresponds not to
292 a real file. So we have to use the DIRLIST separation mechanism
7a12c6bb
RM
293 of the inner loop. */
294 cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
295 for (; cnt >= 0; --cnt)
e155c801 296 if ((cnt & ~mask) == 0)
7a12c6bb
RM
297 {
298 /* Iterate over all elements of the DIRLIST. */
299 char *dir = NULL;
300
301 while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
302 != NULL)
303 retval->successor[entries++]
304 = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
305 language, territory, codeset,
e155c801 306 normalized_codeset, modifier, filename, 1);
7a12c6bb
RM
307 }
308 retval->successor[entries] = NULL;
309
310 return retval;
311}
312\f
313/* Normalize codeset name. There is no standard for the codeset
314 names. Normalization allows the user to use any of the common
727211c4
UD
315 names. The return value is dynamically allocated and has to be
316 freed by the caller. */
7a12c6bb
RM
317const char *
318_nl_normalize_codeset (codeset, name_len)
8cb569b7 319 const char *codeset;
7a12c6bb
RM
320 size_t name_len;
321{
322 int len = 0;
323 int only_digit = 1;
324 char *retval;
325 char *wp;
326 size_t cnt;
f9ddf089
UD
327#ifdef NOT_IN_libc
328 locale_t locale = newlocale (0, "C", NULL);
329#else
330# define locale _nl_C_locobj_ptr
331#endif
7a12c6bb
RM
332
333 for (cnt = 0; cnt < name_len; ++cnt)
f9ddf089 334 if (__isalnum_l ((unsigned char) codeset[cnt], locale))
7a12c6bb
RM
335 {
336 ++len;
337
f9ddf089 338 if (! __isdigit_l ((unsigned char) codeset[cnt], locale))
7a12c6bb
RM
339 only_digit = 0;
340 }
341
342 retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
343
344 if (retval != NULL)
345 {
f9ddf089 346 wp = retval;
7a12c6bb 347 if (only_digit)
f9ddf089 348 wp = stpcpy (wp, "iso");
7a12c6bb
RM
349
350 for (cnt = 0; cnt < name_len; ++cnt)
f9ddf089
UD
351 if (__isalpha_l ((unsigned char) codeset[cnt], locale))
352 *wp++ = __tolower_l ((unsigned char) codeset[cnt], locale);
353 else if (__isdigit_l ((unsigned char) codeset[cnt], locale))
7a12c6bb
RM
354 *wp++ = codeset[cnt];
355
356 *wp = '\0';
357 }
358
359 return (const char *) retval;
360}
92f3773b
RM
361
362
363/* @@ begin of epilog @@ */
364
365/* We don't want libintl.a to depend on any other library. So we
366 avoid the non-standard function stpcpy. In GNU C Library this
367 function is available, though. Also allow the symbol HAVE_STPCPY
368 to be defined. */
369#if !_LIBC && !HAVE_STPCPY
370static char *
371stpcpy (dest, src)
372 char *dest;
373 const char *src;
374{
375 while ((*dest++ = *src++) != '\0')
376 /* Do nothing. */ ;
377 return dest - 1;
378}
379#endif