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