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