1 /* Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
2 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
19 This must come before <config.h> because <config.h> may include
20 <features.h>, and once <features.h> has been included, it's too late. */
32 #include <sys/types.h>
37 #include "intl/gettext/loadinfo.h"
38 #include "util/string.h"
40 /* Awful hack to permit compilation under cygwin and its broken configure.
41 * Configure script detects these functions, but compilation clashes on
42 * implicit declarations of them... So we force use of internal ones.
43 * Cygwin argz.h do not contain any declaration for these, nor any other
44 * header while they are available in some linked libs.
45 * Feel free to provide a better fix if any. --Zas */
46 #ifdef HAVE_SYS_CYGWIN_H
47 #undef HAVE___ARGZ_STRINGIFY
48 #undef HAVE___ARGZ_COUNT
49 #undef HAVE___ARGZ_NEXT
51 #if defined HAVE_ARGZ_H
56 /* On some strange systems still no definition of NULL is found. Sigh! */
58 #if defined __STDC__ && __STDC__
59 #define NULL ((void *) 0)
65 /* Define function which are usually not available. */
67 #if !defined HAVE___ARGZ_COUNT
68 /* Returns the number of strings in ARGZ. */
69 static size_t argz_count__(const unsigned char *argz
, size_t len
);
72 argz_count__(const unsigned char *argz
, size_t len
)
77 size_t part_len
= strlen(argz
);
87 #define __argz_count(argz, len) argz_count__ (argz, len)
88 #endif /* !HAVE___ARGZ_COUNT */
90 #if !defined HAVE___ARGZ_STRINGIFY
91 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
92 except the last into the character SEP. */
93 static void argz_stringify__(unsigned char *argz
, size_t len
, int sep
);
96 argz_stringify__(unsigned char *argz
, size_t len
, int sep
)
99 size_t part_len
= strlen(argz
);
108 #undef __argz_stringify
109 #define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
110 #endif /* !HAVE___ARGZ_STRINGIFY */
112 #if !defined HAVE___ARGZ_NEXT
113 static unsigned char *argz_next__(unsigned char *argz
, size_t argz_len
,
114 const unsigned char *entry
);
116 static unsigned char *
117 argz_next__(unsigned char *argz
, size_t argz_len
, const unsigned char *entry
)
120 if (entry
< argz
+ argz_len
)
121 entry
= strchr(entry
, '\0') + 1;
123 return entry
>= argz
+ argz_len
? NULL
: (unsigned char *) entry
;
124 } else if (argz_len
> 0)
131 #define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
132 #endif /* !HAVE___ARGZ_NEXT */
134 /* Return number of bits set in X. */
138 /* We assume that no more than 16 bits are used. */
139 x
= ((x
& ~0x5555) >> 1) + (x
& 0x5555);
140 x
= ((x
& ~0x3333) >> 2) + (x
& 0x3333);
141 x
= ((x
>> 4) + x
) & 0x0f0f;
142 x
= ((x
>> 8) + x
) & 0xff;
147 struct loaded_l10nfile
*
148 _nl_make_l10nflist(struct loaded_l10nfile
**l10nfile_list
,
149 const unsigned char *dirlist
,
152 const unsigned char *language
,
153 const unsigned char *territory
,
154 const unsigned char *codeset
,
155 const unsigned char *normalized_codeset
,
156 const unsigned char *modifier
,
157 const unsigned char *special
,
158 const unsigned char *sponsor
,
159 const unsigned char *revision
,
160 const unsigned char *filename
,
163 unsigned char *abs_filename
, *abs_langdirname
;
164 int abs_langdirnamelen
;
165 struct loaded_l10nfile
*last
= NULL
;
166 struct loaded_l10nfile
*retval
;
171 /* Allocate room for the full file name. */
172 abs_filename
= (unsigned char *) malloc(dirlist_len
+ strlen(language
)
173 + ((mask
& TERRITORY
) != 0
174 ? strlen(territory
) + 1 : 0)
175 + ((mask
& XPG_CODESET
) != 0
176 ? strlen(codeset
) + 1 : 0)
177 + ((mask
& XPG_NORM_CODESET
) != 0
178 ? strlen(normalized_codeset
) + 1 : 0)
179 + (((mask
& XPG_MODIFIER
) != 0
180 || (mask
& CEN_AUDIENCE
) != 0)
181 ? strlen(modifier
) + 1 : 0)
182 + ((mask
& CEN_SPECIAL
) != 0
183 ? strlen(special
) + 1 : 0)
184 + (((mask
& CEN_SPONSOR
) != 0
185 || (mask
& CEN_REVISION
) != 0)
186 ? (1 + ((mask
& CEN_SPONSOR
) != 0
187 ? strlen(sponsor
) + 1 : 0)
188 + ((mask
& CEN_REVISION
) != 0
191 + 1 + strlen(filename
) + 1);
193 if (abs_filename
== NULL
)
199 /* Construct file name. */
200 memcpy(abs_filename
, dirlist
, dirlist_len
);
201 __argz_stringify(abs_filename
, dirlist_len
, PATH_SEPARATOR
);
202 cp
= abs_filename
+ (dirlist_len
- 1);
204 abs_langdirname
= cp
;
205 cp
= stpcpy(cp
, language
);
207 if ((mask
& TERRITORY
) != 0) {
209 cp
= stpcpy(cp
, territory
);
211 if ((mask
& XPG_CODESET
) != 0) {
213 cp
= stpcpy(cp
, codeset
);
215 if ((mask
& XPG_NORM_CODESET
) != 0) {
217 cp
= stpcpy(cp
, normalized_codeset
);
219 if ((mask
& (XPG_MODIFIER
| CEN_AUDIENCE
)) != 0) {
220 /* This component can be part of both syntaces but has different
221 leading characters. For CEN we use `+', else `@'. */
222 *cp
++ = (mask
& CEN_AUDIENCE
) != 0 ? '+' : '@';
223 cp
= stpcpy(cp
, modifier
);
225 if ((mask
& CEN_SPECIAL
) != 0) {
227 cp
= stpcpy(cp
, special
);
229 if ((mask
& (CEN_SPONSOR
| CEN_REVISION
)) != 0) {
231 if ((mask
& CEN_SPONSOR
) != 0)
232 cp
= stpcpy(cp
, sponsor
);
233 if ((mask
& CEN_REVISION
) != 0) {
235 cp
= stpcpy(cp
, revision
);
238 abs_langdirnamelen
= cp
- abs_langdirname
;
241 stpcpy(cp
, filename
);
243 /* Look in list of already loaded domains whether it is already
246 for (retval
= *l10nfile_list
; retval
!= NULL
; retval
= retval
->next
)
247 if (retval
->filename
!= NULL
) {
248 int compare
= strcmp(retval
->filename
, abs_filename
);
254 /* It's not in the list. */
262 if (retval
!= NULL
|| do_allocate
== 0) {
267 retval
= (struct loaded_l10nfile
*)
268 malloc(sizeof(*retval
) + (__argz_count(dirlist
, dirlist_len
)
270 * sizeof(struct loaded_l10nfile
*)));
274 retval
->filename
= abs_filename
;
275 retval
->langdirname
= abs_langdirname
;
276 retval
->langdirnamelen
= abs_langdirnamelen
;
277 retval
->decided
= (__argz_count(dirlist
, dirlist_len
) != 1
278 || ((mask
& XPG_CODESET
) != 0
279 && (mask
& XPG_NORM_CODESET
) != 0));
283 retval
->next
= *l10nfile_list
;
284 *l10nfile_list
= retval
;
286 retval
->next
= last
->next
;
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
293 of the inner loop. */
294 cnt
= __argz_count(dirlist
, dirlist_len
) == 1 ? mask
- 1 : mask
;
295 for (; cnt
>= 0; --cnt
)
296 if ((cnt
& ~mask
) == 0
297 && ((cnt
& CEN_SPECIFIC
) == 0 || (cnt
& XPG_SPECIFIC
) == 0)
298 && ((cnt
& XPG_CODESET
) == 0
299 || (cnt
& XPG_NORM_CODESET
) == 0)) {
300 /* Iterate over all elements of the DIRLIST. */
301 unsigned char *dir
= NULL
;
304 __argz_next((unsigned char *) dirlist
, dirlist_len
, dir
))
306 retval
->successor
[entries
++]
307 = _nl_make_l10nflist(l10nfile_list
, dir
,
316 retval
->successor
[entries
] = NULL
;
321 /* Normalize codeset name. There is no standard for the codeset
322 names. Normalization allows the user to use any of the common
323 names. The return value is dynamically allocated and has to be
324 freed by the caller. */
325 const unsigned char *
326 _nl_normalize_codeset(const unsigned char *codeset
, size_t name_len
)
330 unsigned char *retval
;
334 for (cnt
= 0; cnt
< name_len
; ++cnt
)
335 if (isalnum(codeset
[cnt
])) {
338 if (isalpha(codeset
[cnt
]))
342 retval
= (unsigned char *) malloc((only_digit
? 3 : 0) + len
+ 1);
344 if (retval
!= NULL
) {
346 wp
= stpcpy(retval
, "iso");
350 for (cnt
= 0; cnt
< name_len
; ++cnt
)
351 if (isalpha(codeset
[cnt
]))
352 *wp
++ = tolower(codeset
[cnt
]);
353 else if (isdigit(codeset
[cnt
]))
354 *wp
++ = codeset
[cnt
];
359 return (const unsigned char *) retval
;