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