~ubuntu-branches/ubuntu/trusty/gcompris/trusty

« back to all changes in this revision

Viewing changes to intl/l10nflist.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2002-04-21 16:16:27 UTC
  • Revision ID: james.westby@ubuntu.com-20020421161627-s07yahahm817qxs6
Tags: upstream-1.0.3
ImportĀ upstreamĀ versionĀ 1.0.3

Show diffs side-by-side

added added

removed removed

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