source: trunk/binutils/intl/l10nflist.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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