source: trunk/third/gnome-core/intl/l10nflist.c @ 15328

Revision 15328, 10.2 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15327, which included commits to RCS files with non-trunk default branches.
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
171struct loaded_l10nfile *
172_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
173                    territory, codeset, normalized_codeset, modifier, special,
174                    sponsor, revision, filename, do_allocate)
175     struct loaded_l10nfile **l10nfile_list;
176     const char *dirlist;
177     size_t dirlist_len;
178     int mask;
179     const char *language;
180     const char *territory;
181     const char *codeset;
182     const char *normalized_codeset;
183     const char *modifier;
184     const char *special;
185     const char *sponsor;
186     const char *revision;
187     const char *filename;
188     int do_allocate;
189{
190  char *abs_filename;
191  struct loaded_l10nfile *last = NULL;
192  struct loaded_l10nfile *retval;
193  char *cp;
194  size_t entries;
195  int cnt;
196
197  /* Allocate room for the full file name.  */
198  abs_filename = (char *) malloc (dirlist_len
199                                  + strlen (language)
200                                  + ((mask & TERRITORY) != 0
201                                     ? strlen (territory) + 1 : 0)
202                                  + ((mask & XPG_CODESET) != 0
203                                     ? strlen (codeset) + 1 : 0)
204                                  + ((mask & XPG_NORM_CODESET) != 0
205                                     ? strlen (normalized_codeset) + 1 : 0)
206                                  + (((mask & XPG_MODIFIER) != 0
207                                      || (mask & CEN_AUDIENCE) != 0)
208                                     ? strlen (modifier) + 1 : 0)
209                                  + ((mask & CEN_SPECIAL) != 0
210                                     ? strlen (special) + 1 : 0)
211                                  + (((mask & CEN_SPONSOR) != 0
212                                      || (mask & CEN_REVISION) != 0)
213                                     ? (1 + ((mask & CEN_SPONSOR) != 0
214                                             ? strlen (sponsor) + 1 : 0)
215                                        + ((mask & CEN_REVISION) != 0
216                                           ? strlen (revision) + 1 : 0)) : 0)
217                                  + 1 + strlen (filename) + 1);
218
219  if (abs_filename == NULL)
220    return NULL;
221
222  retval = NULL;
223  last = NULL;
224
225  /* Construct file name.  */
226  memcpy (abs_filename, dirlist, dirlist_len);
227  __argz_stringify (abs_filename, dirlist_len, ':');
228  cp = abs_filename + (dirlist_len - 1);
229  *cp++ = '/';
230  cp = stpcpy (cp, language);
231
232  if ((mask & TERRITORY) != 0)
233    {
234      *cp++ = '_';
235      cp = stpcpy (cp, territory);
236    }
237  if ((mask & XPG_CODESET) != 0)
238    {
239      *cp++ = '.';
240      cp = stpcpy (cp, codeset);
241    }
242  if ((mask & XPG_NORM_CODESET) != 0)
243    {
244      *cp++ = '.';
245      cp = stpcpy (cp, normalized_codeset);
246    }
247  if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
248    {
249      /* This component can be part of both syntaces but has different
250         leading characters.  For CEN we use `+', else `@'.  */
251      *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
252      cp = stpcpy (cp, modifier);
253    }
254  if ((mask & CEN_SPECIAL) != 0)
255    {
256      *cp++ = '+';
257      cp = stpcpy (cp, special);
258    }
259  if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
260    {
261      *cp++ = ',';
262      if ((mask & CEN_SPONSOR) != 0)
263        cp = stpcpy (cp, sponsor);
264      if ((mask & CEN_REVISION) != 0)
265        {
266          *cp++ = '_';
267          cp = stpcpy (cp, revision);
268        }
269    }
270
271  *cp++ = '/';
272  stpcpy (cp, filename);
273
274  /* Look in list of already loaded domains whether it is already
275     available.  */
276  last = NULL;
277  for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
278    if (retval->filename != NULL)
279      {
280        int compare = strcmp (retval->filename, abs_filename);
281        if (compare == 0)
282          /* We found it!  */
283          break;
284        if (compare < 0)
285          {
286            /* It's not in the list.  */
287            retval = NULL;
288            break;
289          }
290
291        last = retval;
292      }
293
294  if (retval != NULL || do_allocate == 0)
295    {
296      free (abs_filename);
297      return retval;
298    }
299
300  retval = (struct loaded_l10nfile *)
301    malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
302                                * (1 << pop (mask))
303                                * sizeof (struct loaded_l10nfile *)));
304  if (retval == NULL)
305    return NULL;
306
307  retval->filename = abs_filename;
308  retval->decided = (__argz_count (dirlist, dirlist_len) != 1
309                     || ((mask & XPG_CODESET) != 0
310                         && (mask & XPG_NORM_CODESET) != 0));
311  retval->data = NULL;
312
313  if (last == NULL)
314    {
315      retval->next = *l10nfile_list;
316      *l10nfile_list = retval;
317    }
318  else
319    {
320      retval->next = last->next;
321      last->next = retval;
322    }
323
324  entries = 0;
325  /* If the DIRLIST is a real list the RETVAL entry corresponds not to
326     a real file.  So we have to use the DIRLIST separation mechanism
327     of the inner loop.  */
328  cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
329  for (; cnt >= 0; --cnt)
330    if ((cnt & ~mask) == 0
331        && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
332        && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
333      {
334        /* Iterate over all elements of the DIRLIST.  */
335        char *dir = NULL;
336
337        while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
338               != NULL)
339          retval->successor[entries++]
340            = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
341                                  language, territory, codeset,
342                                  normalized_codeset, modifier, special,
343                                  sponsor, revision, filename, 1);
344      }
345  retval->successor[entries] = NULL;
346
347  return retval;
348}
349
350/* Normalize codeset name.  There is no standard for the codeset
351   names.  Normalization allows the user to use any of the common
352   names.  */
353const char *
354_nl_normalize_codeset (codeset, name_len)
355     const char *codeset;
356     size_t name_len;
357{
358  int len = 0;
359  int only_digit = 1;
360  char *retval;
361  char *wp;
362  size_t cnt;
363
364  for (cnt = 0; cnt < name_len; ++cnt)
365    if (isalnum (codeset[cnt]))
366      {
367        ++len;
368
369        if (isalpha (codeset[cnt]))
370          only_digit = 0;
371      }
372
373  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
374
375  if (retval != NULL)
376    {
377      if (only_digit)
378        wp = stpcpy (retval, "iso");
379      else
380        wp = retval;
381
382      for (cnt = 0; cnt < name_len; ++cnt)
383        if (isalpha (codeset[cnt]))
384          *wp++ = tolower (codeset[cnt]);
385        else if (isdigit (codeset[cnt]))
386          *wp++ = codeset[cnt];
387
388      *wp = '\0';
389    }
390
391  return (const char *) retval;
392}
393
394
395/* @@ begin of epilog @@ */
396
397/* We don't want libintl.a to depend on any other library.  So we
398   avoid the non-standard function stpcpy.  In GNU C Library this
399   function is available, though.  Also allow the symbol HAVE_STPCPY
400   to be defined.  */
401#if !_LIBC && !HAVE_STPCPY
402static char *
403stpcpy (dest, src)
404     char *dest;
405     const char *src;
406{
407  while ((*dest++ = *src++) != '\0')
408    /* Do nothing. */ ;
409  return dest - 1;
410}
411#endif
Note: See TracBrowser for help on using the repository browser.