516f5211b6405d21af367a86657a4990b2cf231c
[mikachu/openbox.git] / intl / loadmsgcat.c
1 /* Load needed message catalogs.
2    Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc.
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 mempcpy().
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 <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #ifdef __GNUC__
37 # define alloca __builtin_alloca
38 # define HAVE_ALLOCA 1
39 #else
40 # if defined HAVE_ALLOCA_H || defined _LIBC
41 #  include <alloca.h>
42 # else
43 #  ifdef _AIX
44  #pragma alloca
45 #  else
46 #   ifndef alloca
47 char *alloca ();
48 #   endif
49 #  endif
50 # endif
51 #endif
52
53 #include <stdlib.h>
54 #include <string.h>
55
56 #if defined HAVE_UNISTD_H || defined _LIBC
57 # include <unistd.h>
58 #endif
59
60 #ifdef _LIBC
61 # include <langinfo.h>
62 # include <locale.h>
63 #endif
64
65 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
66     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
67 # include <sys/mman.h>
68 # undef HAVE_MMAP
69 # define HAVE_MMAP      1
70 #else
71 # undef HAVE_MMAP
72 #endif
73
74 #if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
75 # include <stdint.h>
76 #endif
77 #if defined HAVE_INTTYPES_H || defined _LIBC
78 # include <inttypes.h>
79 #endif
80
81 #include "gmo.h"
82 #include "gettextP.h"
83 #include "hash-string.h"
84 #include "plural-exp.h"
85
86 #ifdef _LIBC
87 # include "../locale/localeinfo.h"
88 #endif
89
90 /* Provide fallback values for macros that ought to be defined in <inttypes.h>.
91    Note that our fallback values need not be literal strings, because we don't
92    use them with preprocessor string concatenation.  */
93 #if !defined PRId8 || PRI_MACROS_BROKEN
94 # undef PRId8
95 # define PRId8 "d"
96 #endif
97 #if !defined PRIi8 || PRI_MACROS_BROKEN
98 # undef PRIi8
99 # define PRIi8 "i"
100 #endif
101 #if !defined PRIo8 || PRI_MACROS_BROKEN
102 # undef PRIo8
103 # define PRIo8 "o"
104 #endif
105 #if !defined PRIu8 || PRI_MACROS_BROKEN
106 # undef PRIu8
107 # define PRIu8 "u"
108 #endif
109 #if !defined PRIx8 || PRI_MACROS_BROKEN
110 # undef PRIx8
111 # define PRIx8 "x"
112 #endif
113 #if !defined PRIX8 || PRI_MACROS_BROKEN
114 # undef PRIX8
115 # define PRIX8 "X"
116 #endif
117 #if !defined PRId16 || PRI_MACROS_BROKEN
118 # undef PRId16
119 # define PRId16 "d"
120 #endif
121 #if !defined PRIi16 || PRI_MACROS_BROKEN
122 # undef PRIi16
123 # define PRIi16 "i"
124 #endif
125 #if !defined PRIo16 || PRI_MACROS_BROKEN
126 # undef PRIo16
127 # define PRIo16 "o"
128 #endif
129 #if !defined PRIu16 || PRI_MACROS_BROKEN
130 # undef PRIu16
131 # define PRIu16 "u"
132 #endif
133 #if !defined PRIx16 || PRI_MACROS_BROKEN
134 # undef PRIx16
135 # define PRIx16 "x"
136 #endif
137 #if !defined PRIX16 || PRI_MACROS_BROKEN
138 # undef PRIX16
139 # define PRIX16 "X"
140 #endif
141 #if !defined PRId32 || PRI_MACROS_BROKEN
142 # undef PRId32
143 # define PRId32 "d"
144 #endif
145 #if !defined PRIi32 || PRI_MACROS_BROKEN
146 # undef PRIi32
147 # define PRIi32 "i"
148 #endif
149 #if !defined PRIo32 || PRI_MACROS_BROKEN
150 # undef PRIo32
151 # define PRIo32 "o"
152 #endif
153 #if !defined PRIu32 || PRI_MACROS_BROKEN
154 # undef PRIu32
155 # define PRIu32 "u"
156 #endif
157 #if !defined PRIx32 || PRI_MACROS_BROKEN
158 # undef PRIx32
159 # define PRIx32 "x"
160 #endif
161 #if !defined PRIX32 || PRI_MACROS_BROKEN
162 # undef PRIX32
163 # define PRIX32 "X"
164 #endif
165 #if !defined PRId64 || PRI_MACROS_BROKEN
166 # undef PRId64
167 # define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
168 #endif
169 #if !defined PRIi64 || PRI_MACROS_BROKEN
170 # undef PRIi64
171 # define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
172 #endif
173 #if !defined PRIo64 || PRI_MACROS_BROKEN
174 # undef PRIo64
175 # define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
176 #endif
177 #if !defined PRIu64 || PRI_MACROS_BROKEN
178 # undef PRIu64
179 # define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
180 #endif
181 #if !defined PRIx64 || PRI_MACROS_BROKEN
182 # undef PRIx64
183 # define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
184 #endif
185 #if !defined PRIX64 || PRI_MACROS_BROKEN
186 # undef PRIX64
187 # define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
188 #endif
189 #if !defined PRIdLEAST8 || PRI_MACROS_BROKEN
190 # undef PRIdLEAST8
191 # define PRIdLEAST8 "d"
192 #endif
193 #if !defined PRIiLEAST8 || PRI_MACROS_BROKEN
194 # undef PRIiLEAST8
195 # define PRIiLEAST8 "i"
196 #endif
197 #if !defined PRIoLEAST8 || PRI_MACROS_BROKEN
198 # undef PRIoLEAST8
199 # define PRIoLEAST8 "o"
200 #endif
201 #if !defined PRIuLEAST8 || PRI_MACROS_BROKEN
202 # undef PRIuLEAST8
203 # define PRIuLEAST8 "u"
204 #endif
205 #if !defined PRIxLEAST8 || PRI_MACROS_BROKEN
206 # undef PRIxLEAST8
207 # define PRIxLEAST8 "x"
208 #endif
209 #if !defined PRIXLEAST8 || PRI_MACROS_BROKEN
210 # undef PRIXLEAST8
211 # define PRIXLEAST8 "X"
212 #endif
213 #if !defined PRIdLEAST16 || PRI_MACROS_BROKEN
214 # undef PRIdLEAST16
215 # define PRIdLEAST16 "d"
216 #endif
217 #if !defined PRIiLEAST16 || PRI_MACROS_BROKEN
218 # undef PRIiLEAST16
219 # define PRIiLEAST16 "i"
220 #endif
221 #if !defined PRIoLEAST16 || PRI_MACROS_BROKEN
222 # undef PRIoLEAST16
223 # define PRIoLEAST16 "o"
224 #endif
225 #if !defined PRIuLEAST16 || PRI_MACROS_BROKEN
226 # undef PRIuLEAST16
227 # define PRIuLEAST16 "u"
228 #endif
229 #if !defined PRIxLEAST16 || PRI_MACROS_BROKEN
230 # undef PRIxLEAST16
231 # define PRIxLEAST16 "x"
232 #endif
233 #if !defined PRIXLEAST16 || PRI_MACROS_BROKEN
234 # undef PRIXLEAST16
235 # define PRIXLEAST16 "X"
236 #endif
237 #if !defined PRIdLEAST32 || PRI_MACROS_BROKEN
238 # undef PRIdLEAST32
239 # define PRIdLEAST32 "d"
240 #endif
241 #if !defined PRIiLEAST32 || PRI_MACROS_BROKEN
242 # undef PRIiLEAST32
243 # define PRIiLEAST32 "i"
244 #endif
245 #if !defined PRIoLEAST32 || PRI_MACROS_BROKEN
246 # undef PRIoLEAST32
247 # define PRIoLEAST32 "o"
248 #endif
249 #if !defined PRIuLEAST32 || PRI_MACROS_BROKEN
250 # undef PRIuLEAST32
251 # define PRIuLEAST32 "u"
252 #endif
253 #if !defined PRIxLEAST32 || PRI_MACROS_BROKEN
254 # undef PRIxLEAST32
255 # define PRIxLEAST32 "x"
256 #endif
257 #if !defined PRIXLEAST32 || PRI_MACROS_BROKEN
258 # undef PRIXLEAST32
259 # define PRIXLEAST32 "X"
260 #endif
261 #if !defined PRIdLEAST64 || PRI_MACROS_BROKEN
262 # undef PRIdLEAST64
263 # define PRIdLEAST64 PRId64
264 #endif
265 #if !defined PRIiLEAST64 || PRI_MACROS_BROKEN
266 # undef PRIiLEAST64
267 # define PRIiLEAST64 PRIi64
268 #endif
269 #if !defined PRIoLEAST64 || PRI_MACROS_BROKEN
270 # undef PRIoLEAST64
271 # define PRIoLEAST64 PRIo64
272 #endif
273 #if !defined PRIuLEAST64 || PRI_MACROS_BROKEN
274 # undef PRIuLEAST64
275 # define PRIuLEAST64 PRIu64
276 #endif
277 #if !defined PRIxLEAST64 || PRI_MACROS_BROKEN
278 # undef PRIxLEAST64
279 # define PRIxLEAST64 PRIx64
280 #endif
281 #if !defined PRIXLEAST64 || PRI_MACROS_BROKEN
282 # undef PRIXLEAST64
283 # define PRIXLEAST64 PRIX64
284 #endif
285 #if !defined PRIdFAST8 || PRI_MACROS_BROKEN
286 # undef PRIdFAST8
287 # define PRIdFAST8 "d"
288 #endif
289 #if !defined PRIiFAST8 || PRI_MACROS_BROKEN
290 # undef PRIiFAST8
291 # define PRIiFAST8 "i"
292 #endif
293 #if !defined PRIoFAST8 || PRI_MACROS_BROKEN
294 # undef PRIoFAST8
295 # define PRIoFAST8 "o"
296 #endif
297 #if !defined PRIuFAST8 || PRI_MACROS_BROKEN
298 # undef PRIuFAST8
299 # define PRIuFAST8 "u"
300 #endif
301 #if !defined PRIxFAST8 || PRI_MACROS_BROKEN
302 # undef PRIxFAST8
303 # define PRIxFAST8 "x"
304 #endif
305 #if !defined PRIXFAST8 || PRI_MACROS_BROKEN
306 # undef PRIXFAST8
307 # define PRIXFAST8 "X"
308 #endif
309 #if !defined PRIdFAST16 || PRI_MACROS_BROKEN
310 # undef PRIdFAST16
311 # define PRIdFAST16 "d"
312 #endif
313 #if !defined PRIiFAST16 || PRI_MACROS_BROKEN
314 # undef PRIiFAST16
315 # define PRIiFAST16 "i"
316 #endif
317 #if !defined PRIoFAST16 || PRI_MACROS_BROKEN
318 # undef PRIoFAST16
319 # define PRIoFAST16 "o"
320 #endif
321 #if !defined PRIuFAST16 || PRI_MACROS_BROKEN
322 # undef PRIuFAST16
323 # define PRIuFAST16 "u"
324 #endif
325 #if !defined PRIxFAST16 || PRI_MACROS_BROKEN
326 # undef PRIxFAST16
327 # define PRIxFAST16 "x"
328 #endif
329 #if !defined PRIXFAST16 || PRI_MACROS_BROKEN
330 # undef PRIXFAST16
331 # define PRIXFAST16 "X"
332 #endif
333 #if !defined PRIdFAST32 || PRI_MACROS_BROKEN
334 # undef PRIdFAST32
335 # define PRIdFAST32 "d"
336 #endif
337 #if !defined PRIiFAST32 || PRI_MACROS_BROKEN
338 # undef PRIiFAST32
339 # define PRIiFAST32 "i"
340 #endif
341 #if !defined PRIoFAST32 || PRI_MACROS_BROKEN
342 # undef PRIoFAST32
343 # define PRIoFAST32 "o"
344 #endif
345 #if !defined PRIuFAST32 || PRI_MACROS_BROKEN
346 # undef PRIuFAST32
347 # define PRIuFAST32 "u"
348 #endif
349 #if !defined PRIxFAST32 || PRI_MACROS_BROKEN
350 # undef PRIxFAST32
351 # define PRIxFAST32 "x"
352 #endif
353 #if !defined PRIXFAST32 || PRI_MACROS_BROKEN
354 # undef PRIXFAST32
355 # define PRIXFAST32 "X"
356 #endif
357 #if !defined PRIdFAST64 || PRI_MACROS_BROKEN
358 # undef PRIdFAST64
359 # define PRIdFAST64 PRId64
360 #endif
361 #if !defined PRIiFAST64 || PRI_MACROS_BROKEN
362 # undef PRIiFAST64
363 # define PRIiFAST64 PRIi64
364 #endif
365 #if !defined PRIoFAST64 || PRI_MACROS_BROKEN
366 # undef PRIoFAST64
367 # define PRIoFAST64 PRIo64
368 #endif
369 #if !defined PRIuFAST64 || PRI_MACROS_BROKEN
370 # undef PRIuFAST64
371 # define PRIuFAST64 PRIu64
372 #endif
373 #if !defined PRIxFAST64 || PRI_MACROS_BROKEN
374 # undef PRIxFAST64
375 # define PRIxFAST64 PRIx64
376 #endif
377 #if !defined PRIXFAST64 || PRI_MACROS_BROKEN
378 # undef PRIXFAST64
379 # define PRIXFAST64 PRIX64
380 #endif
381 #if !defined PRIdMAX || PRI_MACROS_BROKEN
382 # undef PRIdMAX
383 # define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
384 #endif
385 #if !defined PRIiMAX || PRI_MACROS_BROKEN
386 # undef PRIiMAX
387 # define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
388 #endif
389 #if !defined PRIoMAX || PRI_MACROS_BROKEN
390 # undef PRIoMAX
391 # define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
392 #endif
393 #if !defined PRIuMAX || PRI_MACROS_BROKEN
394 # undef PRIuMAX
395 # define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
396 #endif
397 #if !defined PRIxMAX || PRI_MACROS_BROKEN
398 # undef PRIxMAX
399 # define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
400 #endif
401 #if !defined PRIXMAX || PRI_MACROS_BROKEN
402 # undef PRIXMAX
403 # define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
404 #endif
405 #if !defined PRIdPTR || PRI_MACROS_BROKEN
406 # undef PRIdPTR
407 # define PRIdPTR \
408   (sizeof (void *) == sizeof (long) ? "ld" : \
409    sizeof (void *) == sizeof (int) ? "d" : \
410    "lld")
411 #endif
412 #if !defined PRIiPTR || PRI_MACROS_BROKEN
413 # undef PRIiPTR
414 # define PRIiPTR \
415   (sizeof (void *) == sizeof (long) ? "li" : \
416    sizeof (void *) == sizeof (int) ? "i" : \
417    "lli")
418 #endif
419 #if !defined PRIoPTR || PRI_MACROS_BROKEN
420 # undef PRIoPTR
421 # define PRIoPTR \
422   (sizeof (void *) == sizeof (long) ? "lo" : \
423    sizeof (void *) == sizeof (int) ? "o" : \
424    "llo")
425 #endif
426 #if !defined PRIuPTR || PRI_MACROS_BROKEN
427 # undef PRIuPTR
428 # define PRIuPTR \
429   (sizeof (void *) == sizeof (long) ? "lu" : \
430    sizeof (void *) == sizeof (int) ? "u" : \
431    "llu")
432 #endif
433 #if !defined PRIxPTR || PRI_MACROS_BROKEN
434 # undef PRIxPTR
435 # define PRIxPTR \
436   (sizeof (void *) == sizeof (long) ? "lx" : \
437    sizeof (void *) == sizeof (int) ? "x" : \
438    "llx")
439 #endif
440 #if !defined PRIXPTR || PRI_MACROS_BROKEN
441 # undef PRIXPTR
442 # define PRIXPTR \
443   (sizeof (void *) == sizeof (long) ? "lX" : \
444    sizeof (void *) == sizeof (int) ? "X" : \
445    "llX")
446 #endif
447
448 /* @@ end of prolog @@ */
449
450 #ifdef _LIBC
451 /* Rename the non ISO C functions.  This is required by the standard
452    because some ISO C functions will require linking with this object
453    file and the name space must not be polluted.  */
454 # define open   __open
455 # define close  __close
456 # define read   __read
457 # define mmap   __mmap
458 # define munmap __munmap
459 #endif
460
461 /* For those losing systems which don't have `alloca' we have to add
462    some additional code emulating it.  */
463 #ifdef HAVE_ALLOCA
464 # define freea(p) /* nothing */
465 #else
466 # define alloca(n) malloc (n)
467 # define freea(p) free (p)
468 #endif
469
470 /* For systems that distinguish between text and binary I/O.
471    O_BINARY is usually declared in <fcntl.h>. */
472 #if !defined O_BINARY && defined _O_BINARY
473   /* For MSC-compatible compilers.  */
474 # define O_BINARY _O_BINARY
475 # define O_TEXT _O_TEXT
476 #endif
477 #ifdef __BEOS__
478   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
479 # undef O_BINARY
480 # undef O_TEXT
481 #endif
482 /* On reasonable systems, binary I/O is the default.  */
483 #ifndef O_BINARY
484 # define O_BINARY 0
485 #endif
486
487
488 /* Prototypes for local functions.  Needed to ensure compiler checking of
489    function argument counts despite of K&R C function definition syntax.  */
490 static const char *get_sysdep_segment_value PARAMS ((const char *name));
491
492
493 /* We need a sign, whether a new catalog was loaded, which can be associated
494    with all translations.  This is important if the translations are
495    cached by one of GCC's features.  */
496 int _nl_msg_cat_cntr;
497
498
499 /* Expand a system dependent string segment.  Return NULL if unsupported.  */
500 static const char *
501 get_sysdep_segment_value (name)
502      const char *name;
503 {
504   /* Test for an ISO C 99 section 7.8.1 format string directive.
505      Syntax:
506      P R I { d | i | o | u | x | X }
507      { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR }  */
508   /* We don't use a table of 14 times 6 'const char *' strings here, because
509      data relocations cost startup time.  */
510   if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I')
511     {
512       if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u'
513           || name[3] == 'x' || name[3] == 'X')
514         {
515           if (name[4] == '8' && name[5] == '\0')
516             {
517               if (name[3] == 'd')
518                 return PRId8;
519               if (name[3] == 'i')
520                 return PRIi8;
521               if (name[3] == 'o')
522                 return PRIo8;
523               if (name[3] == 'u')
524                 return PRIu8;
525               if (name[3] == 'x')
526                 return PRIx8;
527               if (name[3] == 'X')
528                 return PRIX8;
529               abort ();
530             }
531           if (name[4] == '1' && name[5] == '6' && name[6] == '\0')
532             {
533               if (name[3] == 'd')
534                 return PRId16;
535               if (name[3] == 'i')
536                 return PRIi16;
537               if (name[3] == 'o')
538                 return PRIo16;
539               if (name[3] == 'u')
540                 return PRIu16;
541               if (name[3] == 'x')
542                 return PRIx16;
543               if (name[3] == 'X')
544                 return PRIX16;
545               abort ();
546             }
547           if (name[4] == '3' && name[5] == '2' && name[6] == '\0')
548             {
549               if (name[3] == 'd')
550                 return PRId32;
551               if (name[3] == 'i')
552                 return PRIi32;
553               if (name[3] == 'o')
554                 return PRIo32;
555               if (name[3] == 'u')
556                 return PRIu32;
557               if (name[3] == 'x')
558                 return PRIx32;
559               if (name[3] == 'X')
560                 return PRIX32;
561               abort ();
562             }
563           if (name[4] == '6' && name[5] == '4' && name[6] == '\0')
564             {
565               if (name[3] == 'd')
566                 return PRId64;
567               if (name[3] == 'i')
568                 return PRIi64;
569               if (name[3] == 'o')
570                 return PRIo64;
571               if (name[3] == 'u')
572                 return PRIu64;
573               if (name[3] == 'x')
574                 return PRIx64;
575               if (name[3] == 'X')
576                 return PRIX64;
577               abort ();
578             }
579           if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A'
580               && name[7] == 'S' && name[8] == 'T')
581             {
582               if (name[9] == '8' && name[10] == '\0')
583                 {
584                   if (name[3] == 'd')
585                     return PRIdLEAST8;
586                   if (name[3] == 'i')
587                     return PRIiLEAST8;
588                   if (name[3] == 'o')
589                     return PRIoLEAST8;
590                   if (name[3] == 'u')
591                     return PRIuLEAST8;
592                   if (name[3] == 'x')
593                     return PRIxLEAST8;
594                   if (name[3] == 'X')
595                     return PRIXLEAST8;
596                   abort ();
597                 }
598               if (name[9] == '1' && name[10] == '6' && name[11] == '\0')
599                 {
600                   if (name[3] == 'd')
601                     return PRIdLEAST16;
602                   if (name[3] == 'i')
603                     return PRIiLEAST16;
604                   if (name[3] == 'o')
605                     return PRIoLEAST16;
606                   if (name[3] == 'u')
607                     return PRIuLEAST16;
608                   if (name[3] == 'x')
609                     return PRIxLEAST16;
610                   if (name[3] == 'X')
611                     return PRIXLEAST16;
612                   abort ();
613                 }
614               if (name[9] == '3' && name[10] == '2' && name[11] == '\0')
615                 {
616                   if (name[3] == 'd')
617                     return PRIdLEAST32;
618                   if (name[3] == 'i')
619                     return PRIiLEAST32;
620                   if (name[3] == 'o')
621                     return PRIoLEAST32;
622                   if (name[3] == 'u')
623                     return PRIuLEAST32;
624                   if (name[3] == 'x')
625                     return PRIxLEAST32;
626                   if (name[3] == 'X')
627                     return PRIXLEAST32;
628                   abort ();
629                 }
630               if (name[9] == '6' && name[10] == '4' && name[11] == '\0')
631                 {
632                   if (name[3] == 'd')
633                     return PRIdLEAST64;
634                   if (name[3] == 'i')
635                     return PRIiLEAST64;
636                   if (name[3] == 'o')
637                     return PRIoLEAST64;
638                   if (name[3] == 'u')
639                     return PRIuLEAST64;
640                   if (name[3] == 'x')
641                     return PRIxLEAST64;
642                   if (name[3] == 'X')
643                     return PRIXLEAST64;
644                   abort ();
645                 }
646             }
647           if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S'
648               && name[7] == 'T')
649             {
650               if (name[8] == '8' && name[9] == '\0')
651                 {
652                   if (name[3] == 'd')
653                     return PRIdFAST8;
654                   if (name[3] == 'i')
655                     return PRIiFAST8;
656                   if (name[3] == 'o')
657                     return PRIoFAST8;
658                   if (name[3] == 'u')
659                     return PRIuFAST8;
660                   if (name[3] == 'x')
661                     return PRIxFAST8;
662                   if (name[3] == 'X')
663                     return PRIXFAST8;
664                   abort ();
665                 }
666               if (name[8] == '1' && name[9] == '6' && name[10] == '\0')
667                 {
668                   if (name[3] == 'd')
669                     return PRIdFAST16;
670                   if (name[3] == 'i')
671                     return PRIiFAST16;
672                   if (name[3] == 'o')
673                     return PRIoFAST16;
674                   if (name[3] == 'u')
675                     return PRIuFAST16;
676                   if (name[3] == 'x')
677                     return PRIxFAST16;
678                   if (name[3] == 'X')
679                     return PRIXFAST16;
680                   abort ();
681                 }
682               if (name[8] == '3' && name[9] == '2' && name[10] == '\0')
683                 {
684                   if (name[3] == 'd')
685                     return PRIdFAST32;
686                   if (name[3] == 'i')
687                     return PRIiFAST32;
688                   if (name[3] == 'o')
689                     return PRIoFAST32;
690                   if (name[3] == 'u')
691                     return PRIuFAST32;
692                   if (name[3] == 'x')
693                     return PRIxFAST32;
694                   if (name[3] == 'X')
695                     return PRIXFAST32;
696                   abort ();
697                 }
698               if (name[8] == '6' && name[9] == '4' && name[10] == '\0')
699                 {
700                   if (name[3] == 'd')
701                     return PRIdFAST64;
702                   if (name[3] == 'i')
703                     return PRIiFAST64;
704                   if (name[3] == 'o')
705                     return PRIoFAST64;
706                   if (name[3] == 'u')
707                     return PRIuFAST64;
708                   if (name[3] == 'x')
709                     return PRIxFAST64;
710                   if (name[3] == 'X')
711                     return PRIXFAST64;
712                   abort ();
713                 }
714             }
715           if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X'
716               && name[7] == '\0')
717             {
718               if (name[3] == 'd')
719                 return PRIdMAX;
720               if (name[3] == 'i')
721                 return PRIiMAX;
722               if (name[3] == 'o')
723                 return PRIoMAX;
724               if (name[3] == 'u')
725                 return PRIuMAX;
726               if (name[3] == 'x')
727                 return PRIxMAX;
728               if (name[3] == 'X')
729                 return PRIXMAX;
730               abort ();
731             }
732           if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R'
733               && name[7] == '\0')
734             {
735               if (name[3] == 'd')
736                 return PRIdPTR;
737               if (name[3] == 'i')
738                 return PRIiPTR;
739               if (name[3] == 'o')
740                 return PRIoPTR;
741               if (name[3] == 'u')
742                 return PRIuPTR;
743               if (name[3] == 'x')
744                 return PRIxPTR;
745               if (name[3] == 'X')
746                 return PRIXPTR;
747               abort ();
748             }
749         }
750     }
751   /* Other system dependent strings are not valid.  */
752   return NULL;
753 }
754
755 /* Initialize the codeset dependent parts of an opened message catalog.
756    Return the header entry.  */
757 const char *
758 internal_function
759 _nl_init_domain_conv (domain_file, domain, domainbinding)
760      struct loaded_l10nfile *domain_file;
761      struct loaded_domain *domain;
762      struct binding *domainbinding;
763 {
764   /* Find out about the character set the file is encoded with.
765      This can be found (in textual form) in the entry "".  If this
766      entry does not exist or if this does not contain the `charset='
767      information, we will assume the charset matches the one the
768      current locale and we don't have to perform any conversion.  */
769   char *nullentry;
770   size_t nullentrylen;
771
772   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
773   domain->codeset_cntr =
774     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
775 #ifdef _LIBC
776   domain->conv = (__gconv_t) -1;
777 #else
778 # if HAVE_ICONV
779   domain->conv = (iconv_t) -1;
780 # endif
781 #endif
782   domain->conv_tab = NULL;
783
784   /* Get the header entry.  */
785   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
786
787   if (nullentry != NULL)
788     {
789 #if defined _LIBC || HAVE_ICONV
790       const char *charsetstr;
791
792       charsetstr = strstr (nullentry, "charset=");
793       if (charsetstr != NULL)
794         {
795           size_t len;
796           char *charset;
797           const char *outcharset;
798
799           charsetstr += strlen ("charset=");
800           len = strcspn (charsetstr, " \t\n");
801
802           charset = (char *) alloca (len + 1);
803 # if defined _LIBC || HAVE_MEMPCPY
804           *((char *) mempcpy (charset, charsetstr, len)) = '\0';
805 # else
806           memcpy (charset, charsetstr, len);
807           charset[len] = '\0';
808 # endif
809
810           /* The output charset should normally be determined by the
811              locale.  But sometimes the locale is not used or not correctly
812              set up, so we provide a possibility for the user to override
813              this.  Moreover, the value specified through
814              bind_textdomain_codeset overrides both.  */
815           if (domainbinding != NULL && domainbinding->codeset != NULL)
816             outcharset = domainbinding->codeset;
817           else
818             {
819               outcharset = getenv ("OUTPUT_CHARSET");
820               if (outcharset == NULL || outcharset[0] == '\0')
821                 {
822 # ifdef _LIBC
823                   outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
824 # else
825 #  if HAVE_ICONV
826                   extern const char *locale_charset PARAMS ((void));
827                   outcharset = locale_charset ();
828 #  endif
829 # endif
830                 }
831             }
832
833 # ifdef _LIBC
834           /* We always want to use transliteration.  */
835           outcharset = norm_add_slashes (outcharset, "TRANSLIT");
836           charset = norm_add_slashes (charset, NULL);
837           if (__gconv_open (outcharset, charset, &domain->conv,
838                             GCONV_AVOID_NOCONV)
839               != __GCONV_OK)
840             domain->conv = (__gconv_t) -1;
841 # else
842 #  if HAVE_ICONV
843           /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
844              we want to use transliteration.  */
845 #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
846        || _LIBICONV_VERSION >= 0x0105
847           if (strchr (outcharset, '/') == NULL)
848             {
849               char *tmp;
850
851               len = strlen (outcharset);
852               tmp = (char *) alloca (len + 10 + 1);
853               memcpy (tmp, outcharset, len);
854               memcpy (tmp + len, "//TRANSLIT", 10 + 1);
855               outcharset = tmp;
856
857               domain->conv = iconv_open (outcharset, charset);
858
859               freea (outcharset);
860             }
861           else
862 #   endif
863             domain->conv = iconv_open (outcharset, charset);
864 #  endif
865 # endif
866
867           freea (charset);
868         }
869 #endif /* _LIBC || HAVE_ICONV */
870     }
871
872   return nullentry;
873 }
874
875 /* Frees the codeset dependent parts of an opened message catalog.  */
876 void
877 internal_function
878 _nl_free_domain_conv (domain)
879      struct loaded_domain *domain;
880 {
881   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
882     free (domain->conv_tab);
883
884 #ifdef _LIBC
885   if (domain->conv != (__gconv_t) -1)
886     __gconv_close (domain->conv);
887 #else
888 # if HAVE_ICONV
889   if (domain->conv != (iconv_t) -1)
890     iconv_close (domain->conv);
891 # endif
892 #endif
893 }
894
895 /* Load the message catalogs specified by FILENAME.  If it is no valid
896    message catalog do nothing.  */
897 void
898 internal_function
899 _nl_load_domain (domain_file, domainbinding)
900      struct loaded_l10nfile *domain_file;
901      struct binding *domainbinding;
902 {
903   int fd;
904   size_t size;
905 #ifdef _LIBC
906   struct stat64 st;
907 #else
908   struct stat st;
909 #endif
910   struct mo_file_header *data = (struct mo_file_header *) -1;
911   int use_mmap = 0;
912   struct loaded_domain *domain;
913   int revision;
914   const char *nullentry;
915
916   domain_file->decided = 1;
917   domain_file->data = NULL;
918
919   /* Note that it would be useless to store domainbinding in domain_file
920      because domainbinding might be == NULL now but != NULL later (after
921      a call to bind_textdomain_codeset).  */
922
923   /* If the record does not represent a valid locale the FILENAME
924      might be NULL.  This can happen when according to the given
925      specification the locale file name is different for XPG and CEN
926      syntax.  */
927   if (domain_file->filename == NULL)
928     return;
929
930   /* Try to open the addressed file.  */
931   fd = open (domain_file->filename, O_RDONLY | O_BINARY);
932   if (fd == -1)
933     return;
934
935   /* We must know about the size of the file.  */
936   if (
937 #ifdef _LIBC
938       __builtin_expect (fstat64 (fd, &st) != 0, 0)
939 #else
940       __builtin_expect (fstat (fd, &st) != 0, 0)
941 #endif
942       || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
943       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
944     {
945       /* Something went wrong.  */
946       close (fd);
947       return;
948     }
949
950 #ifdef HAVE_MMAP
951   /* Now we are ready to load the file.  If mmap() is available we try
952      this first.  If not available or it failed we try to load it.  */
953   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
954                                          MAP_PRIVATE, fd, 0);
955
956   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
957     {
958       /* mmap() call was successful.  */
959       close (fd);
960       use_mmap = 1;
961     }
962 #endif
963
964   /* If the data is not yet available (i.e. mmap'ed) we try to load
965      it manually.  */
966   if (data == (struct mo_file_header *) -1)
967     {
968       size_t to_read;
969       char *read_ptr;
970
971       data = (struct mo_file_header *) malloc (size);
972       if (data == NULL)
973         return;
974
975       to_read = size;
976       read_ptr = (char *) data;
977       do
978         {
979           long int nb = (long int) read (fd, read_ptr, to_read);
980           if (nb <= 0)
981             {
982 #ifdef EINTR
983               if (nb == -1 && errno == EINTR)
984                 continue;
985 #endif
986               close (fd);
987               return;
988             }
989           read_ptr += nb;
990           to_read -= nb;
991         }
992       while (to_read > 0);
993
994       close (fd);
995     }
996
997   /* Using the magic number we can test whether it really is a message
998      catalog file.  */
999   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
1000                         0))
1001     {
1002       /* The magic number is wrong: not a message catalog file.  */
1003 #ifdef HAVE_MMAP
1004       if (use_mmap)
1005         munmap ((caddr_t) data, size);
1006       else
1007 #endif
1008         free (data);
1009       return;
1010     }
1011
1012   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
1013   if (domain == NULL)
1014     return;
1015   domain_file->data = domain;
1016
1017   domain->data = (char *) data;
1018   domain->use_mmap = use_mmap;
1019   domain->mmap_size = size;
1020   domain->must_swap = data->magic != _MAGIC;
1021   domain->malloced = NULL;
1022
1023   /* Fill in the information about the available tables.  */
1024   revision = W (domain->must_swap, data->revision);
1025   /* We support only the major revision 0.  */
1026   switch (revision >> 16)
1027     {
1028     case 0:
1029       domain->nstrings = W (domain->must_swap, data->nstrings);
1030       domain->orig_tab = (const struct string_desc *)
1031         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
1032       domain->trans_tab = (const struct string_desc *)
1033         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
1034       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
1035       domain->hash_tab =
1036         (domain->hash_size > 2
1037          ? (const nls_uint32 *)
1038            ((char *) data + W (domain->must_swap, data->hash_tab_offset))
1039          : NULL);
1040       domain->must_swap_hash_tab = domain->must_swap;
1041
1042       /* Now dispatch on the minor revision.  */
1043       switch (revision & 0xffff)
1044         {
1045         case 0:
1046           domain->n_sysdep_strings = 0;
1047           domain->orig_sysdep_tab = NULL;
1048           domain->trans_sysdep_tab = NULL;
1049           break;
1050         case 1:
1051         default:
1052           {
1053             nls_uint32 n_sysdep_strings;
1054
1055             if (domain->hash_tab == NULL)
1056               /* This is invalid.  These minor revisions need a hash table.  */
1057               goto invalid;
1058
1059             n_sysdep_strings =
1060               W (domain->must_swap, data->n_sysdep_strings);
1061             if (n_sysdep_strings > 0)
1062               {
1063                 nls_uint32 n_sysdep_segments;
1064                 const struct sysdep_segment *sysdep_segments;
1065                 const char **sysdep_segment_values;
1066                 const nls_uint32 *orig_sysdep_tab;
1067                 const nls_uint32 *trans_sysdep_tab;
1068                 size_t memneed;
1069                 char *mem;
1070                 struct sysdep_string_desc *inmem_orig_sysdep_tab;
1071                 struct sysdep_string_desc *inmem_trans_sysdep_tab;
1072                 nls_uint32 *inmem_hash_tab;
1073                 unsigned int i;
1074
1075                 /* Get the values of the system dependent segments.  */
1076                 n_sysdep_segments =
1077                   W (domain->must_swap, data->n_sysdep_segments);
1078                 sysdep_segments = (const struct sysdep_segment *)
1079                   ((char *) data
1080                    + W (domain->must_swap, data->sysdep_segments_offset));
1081                 sysdep_segment_values =
1082                   alloca (n_sysdep_segments * sizeof (const char *));
1083                 for (i = 0; i < n_sysdep_segments; i++)
1084                   {
1085                     const char *name =
1086                       (char *) data
1087                       + W (domain->must_swap, sysdep_segments[i].offset);
1088                     nls_uint32 namelen =
1089                       W (domain->must_swap, sysdep_segments[i].length);
1090
1091                     if (!(namelen > 0 && name[namelen - 1] == '\0'))
1092                       {
1093                         freea (sysdep_segment_values);
1094                         goto invalid;
1095                       }
1096
1097                     sysdep_segment_values[i] = get_sysdep_segment_value (name);
1098                   }
1099
1100                 orig_sysdep_tab = (const nls_uint32 *)
1101                   ((char *) data
1102                    + W (domain->must_swap, data->orig_sysdep_tab_offset));
1103                 trans_sysdep_tab = (const nls_uint32 *)
1104                   ((char *) data
1105                    + W (domain->must_swap, data->trans_sysdep_tab_offset));
1106
1107                 /* Compute the amount of additional memory needed for the
1108                    system dependent strings and the augmented hash table.  */
1109                 memneed = 2 * n_sysdep_strings
1110                           * sizeof (struct sysdep_string_desc)
1111                           + domain->hash_size * sizeof (nls_uint32);
1112                 for (i = 0; i < 2 * n_sysdep_strings; i++)
1113                   {
1114                     const struct sysdep_string *sysdep_string =
1115                       (const struct sysdep_string *)
1116                       ((char *) data
1117                        + W (domain->must_swap,
1118                             i < n_sysdep_strings
1119                             ? orig_sysdep_tab[i]
1120                             : trans_sysdep_tab[i - n_sysdep_strings]));
1121                     size_t need = 0;
1122                     const struct segment_pair *p = sysdep_string->segments;
1123
1124                     if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
1125                       for (p = sysdep_string->segments;; p++)
1126                         {
1127                           nls_uint32 sysdepref;
1128
1129                           need += W (domain->must_swap, p->segsize);
1130
1131                           sysdepref = W (domain->must_swap, p->sysdepref);
1132                           if (sysdepref == SEGMENTS_END)
1133                             break;
1134
1135                           if (sysdepref >= n_sysdep_segments)
1136                             {
1137                               /* Invalid.  */
1138                               freea (sysdep_segment_values);
1139                               goto invalid;
1140                             }
1141
1142                           need += strlen (sysdep_segment_values[sysdepref]);
1143                         }
1144
1145                     memneed += need;
1146                   }
1147
1148                 /* Allocate additional memory.  */
1149                 mem = (char *) malloc (memneed);
1150                 if (mem == NULL)
1151                   goto invalid;
1152
1153                 domain->malloced = mem;
1154                 inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
1155                 mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
1156                 inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
1157                 mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
1158                 inmem_hash_tab = (nls_uint32 *) mem;
1159                 mem += domain->hash_size * sizeof (nls_uint32);
1160
1161                 /* Compute the system dependent strings.  */
1162                 for (i = 0; i < 2 * n_sysdep_strings; i++)
1163                   {
1164                     const struct sysdep_string *sysdep_string =
1165                       (const struct sysdep_string *)
1166                       ((char *) data
1167                        + W (domain->must_swap,
1168                             i < n_sysdep_strings
1169                             ? orig_sysdep_tab[i]
1170                             : trans_sysdep_tab[i - n_sysdep_strings]));
1171                     const char *static_segments =
1172                       (char *) data
1173                       + W (domain->must_swap, sysdep_string->offset);
1174                     const struct segment_pair *p = sysdep_string->segments;
1175
1176                     /* Concatenate the segments, and fill
1177                        inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and
1178                        inmem_trans_sysdep_tab[i-n_sysdep_strings] (for
1179                        i >= n_sysdep_strings).  */
1180
1181                     if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END)
1182                       {
1183                         /* Only one static segment.  */
1184                         inmem_orig_sysdep_tab[i].length =
1185                           W (domain->must_swap, p->segsize);
1186                         inmem_orig_sysdep_tab[i].pointer = static_segments;
1187                       }
1188                     else
1189                       {
1190                         inmem_orig_sysdep_tab[i].pointer = mem;
1191
1192                         for (p = sysdep_string->segments;; p++)
1193                           {
1194                             nls_uint32 segsize =
1195                               W (domain->must_swap, p->segsize);
1196                             nls_uint32 sysdepref =
1197                               W (domain->must_swap, p->sysdepref);
1198                             size_t n;
1199
1200                             if (segsize > 0)
1201                               {
1202                                 memcpy (mem, static_segments, segsize);
1203                                 mem += segsize;
1204                                 static_segments += segsize;
1205                               }
1206
1207                             if (sysdepref == SEGMENTS_END)
1208                               break;
1209
1210                             n = strlen (sysdep_segment_values[sysdepref]);
1211                             memcpy (mem, sysdep_segment_values[sysdepref], n);
1212                             mem += n;
1213                           }
1214
1215                         inmem_orig_sysdep_tab[i].length =
1216                           mem - inmem_orig_sysdep_tab[i].pointer;
1217                       }
1218                   }
1219
1220                 /* Compute the augmented hash table.  */
1221                 for (i = 0; i < domain->hash_size; i++)
1222                   inmem_hash_tab[i] =
1223                     W (domain->must_swap_hash_tab, domain->hash_tab[i]);
1224                 for (i = 0; i < n_sysdep_strings; i++)
1225                   {
1226                     const char *msgid = inmem_orig_sysdep_tab[i].pointer;
1227                     nls_uint32 hash_val = hash_string (msgid);
1228                     nls_uint32 idx = hash_val % domain->hash_size;
1229                     nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
1230
1231                     for (;;)
1232                       {
1233                         if (inmem_hash_tab[idx] == 0)
1234                           {
1235                             /* Hash table entry is empty.  Use it.  */
1236                             inmem_hash_tab[idx] = 1 + domain->nstrings + i;
1237                             break;
1238                           }
1239
1240                         if (idx >= domain->hash_size - incr)
1241                           idx -= domain->hash_size - incr;
1242                         else
1243                           idx += incr;
1244                       }
1245                   }
1246
1247                 freea (sysdep_segment_values);
1248
1249                 domain->n_sysdep_strings = n_sysdep_strings;
1250                 domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
1251                 domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
1252
1253                 domain->hash_tab = inmem_hash_tab;
1254                 domain->must_swap_hash_tab = 0;
1255               }
1256             else
1257               {
1258                 domain->n_sysdep_strings = 0;
1259                 domain->orig_sysdep_tab = NULL;
1260                 domain->trans_sysdep_tab = NULL;
1261               }
1262           }
1263           break;
1264         }
1265       break;
1266     default:
1267       /* This is an invalid revision.  */
1268     invalid:
1269       /* This is an invalid .mo file.  */
1270       if (domain->malloced)
1271         free (domain->malloced);
1272 #ifdef HAVE_MMAP
1273       if (use_mmap)
1274         munmap ((caddr_t) data, size);
1275       else
1276 #endif
1277         free (data);
1278       free (domain);
1279       domain_file->data = NULL;
1280       return;
1281     }
1282
1283   /* Now initialize the character set converter from the character set
1284      the file is encoded with (found in the header entry) to the domain's
1285      specified character set or the locale's character set.  */
1286   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
1287
1288   /* Also look for a plural specification.  */
1289   EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
1290 }
1291
1292
1293 #ifdef _LIBC
1294 void
1295 internal_function
1296 _nl_unload_domain (domain)
1297      struct loaded_domain *domain;
1298 {
1299   if (domain->plural != &__gettext_germanic_plural)
1300     __gettext_free_exp (domain->plural);
1301
1302   _nl_free_domain_conv (domain);
1303
1304   if (domain->malloced)
1305     free (domain->malloced);
1306
1307 # ifdef _POSIX_MAPPED_FILES
1308   if (domain->use_mmap)
1309     munmap ((caddr_t) domain->data, domain->mmap_size);
1310   else
1311 # endif /* _POSIX_MAPPED_FILES */
1312     free ((void *) domain->data);
1313
1314   free (domain);
1315 }
1316 #endif