* NEWS: Note SHA-224 and DSA2.
[gnupg.git] / intl / loadmsgcat.c
1 /* Load needed message catalogs.
2    Copyright (C) 1995-1999, 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
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 # undef  alloca
38 # define alloca __builtin_alloca
39 # define HAVE_ALLOCA 1
40 #else
41 # ifdef _MSC_VER
42 #  include <malloc.h>
43 #  define alloca _alloca
44 # else
45 #  if defined HAVE_ALLOCA_H || defined _LIBC
46 #   include <alloca.h>
47 #  else
48 #   ifdef _AIX
49  #pragma alloca
50 #   else
51 #    ifndef alloca
52 char *alloca ();
53 #    endif
54 #   endif
55 #  endif
56 # endif
57 #endif
58
59 #include <stdlib.h>
60 #include <string.h>
61
62 #if defined HAVE_UNISTD_H || defined _LIBC
63 # include <unistd.h>
64 #endif
65
66 #ifdef _LIBC
67 # include <langinfo.h>
68 # include <locale.h>
69 #endif
70
71 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
72     || (defined _LIBC && defined _POSIX_MAPPED_FILES)
73 # include <sys/mman.h>
74 # undef HAVE_MMAP
75 # define HAVE_MMAP      1
76 #else
77 # undef HAVE_MMAP
78 #endif
79
80 #if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
81 # include <stdint.h>
82 #endif
83 #if defined HAVE_INTTYPES_H || defined _LIBC
84 # include <inttypes.h>
85 #endif
86
87 #include "gmo.h"
88 #include "gettextP.h"
89 #include "hash-string.h"
90 #include "plural-exp.h"
91
92 #ifdef _LIBC
93 # include "../locale/localeinfo.h"
94 #endif
95
96 /* Provide fallback values for macros that ought to be defined in <inttypes.h>.
97    Note that our fallback values need not be literal strings, because we don't
98    use them with preprocessor string concatenation.  */
99 #if !defined PRId8 || PRI_MACROS_BROKEN
100 # undef PRId8
101 # define PRId8 "d"
102 #endif
103 #if !defined PRIi8 || PRI_MACROS_BROKEN
104 # undef PRIi8
105 # define PRIi8 "i"
106 #endif
107 #if !defined PRIo8 || PRI_MACROS_BROKEN
108 # undef PRIo8
109 # define PRIo8 "o"
110 #endif
111 #if !defined PRIu8 || PRI_MACROS_BROKEN
112 # undef PRIu8
113 # define PRIu8 "u"
114 #endif
115 #if !defined PRIx8 || PRI_MACROS_BROKEN
116 # undef PRIx8
117 # define PRIx8 "x"
118 #endif
119 #if !defined PRIX8 || PRI_MACROS_BROKEN
120 # undef PRIX8
121 # define PRIX8 "X"
122 #endif
123 #if !defined PRId16 || PRI_MACROS_BROKEN
124 # undef PRId16
125 # define PRId16 "d"
126 #endif
127 #if !defined PRIi16 || PRI_MACROS_BROKEN
128 # undef PRIi16
129 # define PRIi16 "i"
130 #endif
131 #if !defined PRIo16 || PRI_MACROS_BROKEN
132 # undef PRIo16
133 # define PRIo16 "o"
134 #endif
135 #if !defined PRIu16 || PRI_MACROS_BROKEN
136 # undef PRIu16
137 # define PRIu16 "u"
138 #endif
139 #if !defined PRIx16 || PRI_MACROS_BROKEN
140 # undef PRIx16
141 # define PRIx16 "x"
142 #endif
143 #if !defined PRIX16 || PRI_MACROS_BROKEN
144 # undef PRIX16
145 # define PRIX16 "X"
146 #endif
147 #if !defined PRId32 || PRI_MACROS_BROKEN
148 # undef PRId32
149 # define PRId32 "d"
150 #endif
151 #if !defined PRIi32 || PRI_MACROS_BROKEN
152 # undef PRIi32
153 # define PRIi32 "i"
154 #endif
155 #if !defined PRIo32 || PRI_MACROS_BROKEN
156 # undef PRIo32
157 # define PRIo32 "o"
158 #endif
159 #if !defined PRIu32 || PRI_MACROS_BROKEN
160 # undef PRIu32
161 # define PRIu32 "u"
162 #endif
163 #if !defined PRIx32 || PRI_MACROS_BROKEN
164 # undef PRIx32
165 # define PRIx32 "x"
166 #endif
167 #if !defined PRIX32 || PRI_MACROS_BROKEN
168 # undef PRIX32
169 # define PRIX32 "X"
170 #endif
171 #if !defined PRId64 || PRI_MACROS_BROKEN
172 # undef PRId64
173 # define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
174 #endif
175 #if !defined PRIi64 || PRI_MACROS_BROKEN
176 # undef PRIi64
177 # define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
178 #endif
179 #if !defined PRIo64 || PRI_MACROS_BROKEN
180 # undef PRIo64
181 # define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
182 #endif
183 #if !defined PRIu64 || PRI_MACROS_BROKEN
184 # undef PRIu64
185 # define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
186 #endif
187 #if !defined PRIx64 || PRI_MACROS_BROKEN
188 # undef PRIx64
189 # define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
190 #endif
191 #if !defined PRIX64 || PRI_MACROS_BROKEN
192 # undef PRIX64
193 # define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
194 #endif
195 #if !defined PRIdLEAST8 || PRI_MACROS_BROKEN
196 # undef PRIdLEAST8
197 # define PRIdLEAST8 "d"
198 #endif
199 #if !defined PRIiLEAST8 || PRI_MACROS_BROKEN
200 # undef PRIiLEAST8
201 # define PRIiLEAST8 "i"
202 #endif
203 #if !defined PRIoLEAST8 || PRI_MACROS_BROKEN
204 # undef PRIoLEAST8
205 # define PRIoLEAST8 "o"
206 #endif
207 #if !defined PRIuLEAST8 || PRI_MACROS_BROKEN
208 # undef PRIuLEAST8
209 # define PRIuLEAST8 "u"
210 #endif
211 #if !defined PRIxLEAST8 || PRI_MACROS_BROKEN
212 # undef PRIxLEAST8
213 # define PRIxLEAST8 "x"
214 #endif
215 #if !defined PRIXLEAST8 || PRI_MACROS_BROKEN
216 # undef PRIXLEAST8
217 # define PRIXLEAST8 "X"
218 #endif
219 #if !defined PRIdLEAST16 || PRI_MACROS_BROKEN
220 # undef PRIdLEAST16
221 # define PRIdLEAST16 "d"
222 #endif
223 #if !defined PRIiLEAST16 || PRI_MACROS_BROKEN
224 # undef PRIiLEAST16
225 # define PRIiLEAST16 "i"
226 #endif
227 #if !defined PRIoLEAST16 || PRI_MACROS_BROKEN
228 # undef PRIoLEAST16
229 # define PRIoLEAST16 "o"
230 #endif
231 #if !defined PRIuLEAST16 || PRI_MACROS_BROKEN
232 # undef PRIuLEAST16
233 # define PRIuLEAST16 "u"
234 #endif
235 #if !defined PRIxLEAST16 || PRI_MACROS_BROKEN
236 # undef PRIxLEAST16
237 # define PRIxLEAST16 "x"
238 #endif
239 #if !defined PRIXLEAST16 || PRI_MACROS_BROKEN
240 # undef PRIXLEAST16
241 # define PRIXLEAST16 "X"
242 #endif
243 #if !defined PRIdLEAST32 || PRI_MACROS_BROKEN
244 # undef PRIdLEAST32
245 # define PRIdLEAST32 "d"
246 #endif
247 #if !defined PRIiLEAST32 || PRI_MACROS_BROKEN
248 # undef PRIiLEAST32
249 # define PRIiLEAST32 "i"
250 #endif
251 #if !defined PRIoLEAST32 || PRI_MACROS_BROKEN
252 # undef PRIoLEAST32
253 # define PRIoLEAST32 "o"
254 #endif
255 #if !defined PRIuLEAST32 || PRI_MACROS_BROKEN
256 # undef PRIuLEAST32
257 # define PRIuLEAST32 "u"
258 #endif
259 #if !defined PRIxLEAST32 || PRI_MACROS_BROKEN
260 # undef PRIxLEAST32
261 # define PRIxLEAST32 "x"
262 #endif
263 #if !defined PRIXLEAST32 || PRI_MACROS_BROKEN
264 # undef PRIXLEAST32
265 # define PRIXLEAST32 "X"
266 #endif
267 #if !defined PRIdLEAST64 || PRI_MACROS_BROKEN
268 # undef PRIdLEAST64
269 # define PRIdLEAST64 PRId64
270 #endif
271 #if !defined PRIiLEAST64 || PRI_MACROS_BROKEN
272 # undef PRIiLEAST64
273 # define PRIiLEAST64 PRIi64
274 #endif
275 #if !defined PRIoLEAST64 || PRI_MACROS_BROKEN
276 # undef PRIoLEAST64
277 # define PRIoLEAST64 PRIo64
278 #endif
279 #if !defined PRIuLEAST64 || PRI_MACROS_BROKEN
280 # undef PRIuLEAST64
281 # define PRIuLEAST64 PRIu64
282 #endif
283 #if !defined PRIxLEAST64 || PRI_MACROS_BROKEN
284 # undef PRIxLEAST64
285 # define PRIxLEAST64 PRIx64
286 #endif
287 #if !defined PRIXLEAST64 || PRI_MACROS_BROKEN
288 # undef PRIXLEAST64
289 # define PRIXLEAST64 PRIX64
290 #endif
291 #if !defined PRIdFAST8 || PRI_MACROS_BROKEN
292 # undef PRIdFAST8
293 # define PRIdFAST8 "d"
294 #endif
295 #if !defined PRIiFAST8 || PRI_MACROS_BROKEN
296 # undef PRIiFAST8
297 # define PRIiFAST8 "i"
298 #endif
299 #if !defined PRIoFAST8 || PRI_MACROS_BROKEN
300 # undef PRIoFAST8
301 # define PRIoFAST8 "o"
302 #endif
303 #if !defined PRIuFAST8 || PRI_MACROS_BROKEN
304 # undef PRIuFAST8
305 # define PRIuFAST8 "u"
306 #endif
307 #if !defined PRIxFAST8 || PRI_MACROS_BROKEN
308 # undef PRIxFAST8
309 # define PRIxFAST8 "x"
310 #endif
311 #if !defined PRIXFAST8 || PRI_MACROS_BROKEN
312 # undef PRIXFAST8
313 # define PRIXFAST8 "X"
314 #endif
315 #if !defined PRIdFAST16 || PRI_MACROS_BROKEN
316 # undef PRIdFAST16
317 # define PRIdFAST16 "d"
318 #endif
319 #if !defined PRIiFAST16 || PRI_MACROS_BROKEN
320 # undef PRIiFAST16
321 # define PRIiFAST16 "i"
322 #endif
323 #if !defined PRIoFAST16 || PRI_MACROS_BROKEN
324 # undef PRIoFAST16
325 # define PRIoFAST16 "o"
326 #endif
327 #if !defined PRIuFAST16 || PRI_MACROS_BROKEN
328 # undef PRIuFAST16
329 # define PRIuFAST16 "u"
330 #endif
331 #if !defined PRIxFAST16 || PRI_MACROS_BROKEN
332 # undef PRIxFAST16
333 # define PRIxFAST16 "x"
334 #endif
335 #if !defined PRIXFAST16 || PRI_MACROS_BROKEN
336 # undef PRIXFAST16
337 # define PRIXFAST16 "X"
338 #endif
339 #if !defined PRIdFAST32 || PRI_MACROS_BROKEN
340 # undef PRIdFAST32
341 # define PRIdFAST32 "d"
342 #endif
343 #if !defined PRIiFAST32 || PRI_MACROS_BROKEN
344 # undef PRIiFAST32
345 # define PRIiFAST32 "i"
346 #endif
347 #if !defined PRIoFAST32 || PRI_MACROS_BROKEN
348 # undef PRIoFAST32
349 # define PRIoFAST32 "o"
350 #endif
351 #if !defined PRIuFAST32 || PRI_MACROS_BROKEN
352 # undef PRIuFAST32
353 # define PRIuFAST32 "u"
354 #endif
355 #if !defined PRIxFAST32 || PRI_MACROS_BROKEN
356 # undef PRIxFAST32
357 # define PRIxFAST32 "x"
358 #endif
359 #if !defined PRIXFAST32 || PRI_MACROS_BROKEN
360 # undef PRIXFAST32
361 # define PRIXFAST32 "X"
362 #endif
363 #if !defined PRIdFAST64 || PRI_MACROS_BROKEN
364 # undef PRIdFAST64
365 # define PRIdFAST64 PRId64
366 #endif
367 #if !defined PRIiFAST64 || PRI_MACROS_BROKEN
368 # undef PRIiFAST64
369 # define PRIiFAST64 PRIi64
370 #endif
371 #if !defined PRIoFAST64 || PRI_MACROS_BROKEN
372 # undef PRIoFAST64
373 # define PRIoFAST64 PRIo64
374 #endif
375 #if !defined PRIuFAST64 || PRI_MACROS_BROKEN
376 # undef PRIuFAST64
377 # define PRIuFAST64 PRIu64
378 #endif
379 #if !defined PRIxFAST64 || PRI_MACROS_BROKEN
380 # undef PRIxFAST64
381 # define PRIxFAST64 PRIx64
382 #endif
383 #if !defined PRIXFAST64 || PRI_MACROS_BROKEN
384 # undef PRIXFAST64
385 # define PRIXFAST64 PRIX64
386 #endif
387 #if !defined PRIdMAX || PRI_MACROS_BROKEN
388 # undef PRIdMAX
389 # define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
390 #endif
391 #if !defined PRIiMAX || PRI_MACROS_BROKEN
392 # undef PRIiMAX
393 # define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
394 #endif
395 #if !defined PRIoMAX || PRI_MACROS_BROKEN
396 # undef PRIoMAX
397 # define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
398 #endif
399 #if !defined PRIuMAX || PRI_MACROS_BROKEN
400 # undef PRIuMAX
401 # define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
402 #endif
403 #if !defined PRIxMAX || PRI_MACROS_BROKEN
404 # undef PRIxMAX
405 # define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
406 #endif
407 #if !defined PRIXMAX || PRI_MACROS_BROKEN
408 # undef PRIXMAX
409 # define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
410 #endif
411 #if !defined PRIdPTR || PRI_MACROS_BROKEN
412 # undef PRIdPTR
413 # define PRIdPTR \
414   (sizeof (void *) == sizeof (long) ? "ld" : \
415    sizeof (void *) == sizeof (int) ? "d" : \
416    "lld")
417 #endif
418 #if !defined PRIiPTR || PRI_MACROS_BROKEN
419 # undef PRIiPTR
420 # define PRIiPTR \
421   (sizeof (void *) == sizeof (long) ? "li" : \
422    sizeof (void *) == sizeof (int) ? "i" : \
423    "lli")
424 #endif
425 #if !defined PRIoPTR || PRI_MACROS_BROKEN
426 # undef PRIoPTR
427 # define PRIoPTR \
428   (sizeof (void *) == sizeof (long) ? "lo" : \
429    sizeof (void *) == sizeof (int) ? "o" : \
430    "llo")
431 #endif
432 #if !defined PRIuPTR || PRI_MACROS_BROKEN
433 # undef PRIuPTR
434 # define PRIuPTR \
435   (sizeof (void *) == sizeof (long) ? "lu" : \
436    sizeof (void *) == sizeof (int) ? "u" : \
437    "llu")
438 #endif
439 #if !defined PRIxPTR || PRI_MACROS_BROKEN
440 # undef PRIxPTR
441 # define PRIxPTR \
442   (sizeof (void *) == sizeof (long) ? "lx" : \
443    sizeof (void *) == sizeof (int) ? "x" : \
444    "llx")
445 #endif
446 #if !defined PRIXPTR || PRI_MACROS_BROKEN
447 # undef PRIXPTR
448 # define PRIXPTR \
449   (sizeof (void *) == sizeof (long) ? "lX" : \
450    sizeof (void *) == sizeof (int) ? "X" : \
451    "llX")
452 #endif
453
454 /* @@ end of prolog @@ */
455
456 #ifdef _LIBC
457 /* Rename the non ISO C functions.  This is required by the standard
458    because some ISO C functions will require linking with this object
459    file and the name space must not be polluted.  */
460 # define open   __open
461 # define close  __close
462 # define read   __read
463 # define mmap   __mmap
464 # define munmap __munmap
465 #endif
466
467 /* For those losing systems which don't have `alloca' we have to add
468    some additional code emulating it.  */
469 #ifdef HAVE_ALLOCA
470 # define freea(p) /* nothing */
471 #else
472 # define alloca(n) malloc (n)
473 # define freea(p) free (p)
474 #endif
475
476 /* For systems that distinguish between text and binary I/O.
477    O_BINARY is usually declared in <fcntl.h>. */
478 #if !defined O_BINARY && defined _O_BINARY
479   /* For MSC-compatible compilers.  */
480 # define O_BINARY _O_BINARY
481 # define O_TEXT _O_TEXT
482 #endif
483 #ifdef __BEOS__
484   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
485 # undef O_BINARY
486 # undef O_TEXT
487 #endif
488 /* On reasonable systems, binary I/O is the default.  */
489 #ifndef O_BINARY
490 # define O_BINARY 0
491 #endif
492
493
494 /* We need a sign, whether a new catalog was loaded, which can be associated
495    with all translations.  This is important if the translations are
496    cached by one of GCC's features.  */
497 int _nl_msg_cat_cntr;
498
499
500 /* Expand a system dependent string segment.  Return NULL if unsupported.  */
501 static const char *
502 get_sysdep_segment_value (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   /* Test for a glibc specific printf() format directive flag.  */
752   if (name[0] == 'I' && name[1] == '\0')
753     {
754 #if defined _LIBC || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
755       /* The 'I' flag, in numeric format directives, replaces ASCII digits
756          with the 'outdigits' defined in the LC_CTYPE locale facet.  This is
757          used for Farsi (Persian) and maybe Arabic.  */
758       return "I";
759 #else
760       return "";
761 #endif
762     }
763   /* Other system dependent strings are not valid.  */
764   return NULL;
765 }
766
767 /* Initialize the codeset dependent parts of an opened message catalog.
768    Return the header entry.  */
769 const char *
770 internal_function
771 _nl_init_domain_conv (struct loaded_l10nfile *domain_file,
772                       struct loaded_domain *domain,
773                       struct binding *domainbinding)
774 {
775   /* Find out about the character set the file is encoded with.
776      This can be found (in textual form) in the entry "".  If this
777      entry does not exist or if this does not contain the `charset='
778      information, we will assume the charset matches the one the
779      current locale and we don't have to perform any conversion.  */
780   char *nullentry;
781   size_t nullentrylen;
782
783   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
784   domain->codeset_cntr =
785     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
786 #ifdef _LIBC
787   domain->conv = (__gconv_t) -1;
788 #else
789 # if HAVE_ICONV
790   domain->conv = (iconv_t) -1;
791 # endif
792 #endif
793   domain->conv_tab = NULL;
794
795   /* Get the header entry.  */
796   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
797
798   if (nullentry != NULL)
799     {
800 #if defined _LIBC || HAVE_ICONV
801       const char *charsetstr;
802
803       charsetstr = strstr (nullentry, "charset=");
804       if (charsetstr != NULL)
805         {
806           size_t len;
807           char *charset;
808           const char *outcharset;
809
810           charsetstr += strlen ("charset=");
811           len = strcspn (charsetstr, " \t\n");
812
813           charset = (char *) alloca (len + 1);
814 # if defined _LIBC || HAVE_MEMPCPY
815           *((char *) mempcpy (charset, charsetstr, len)) = '\0';
816 # else
817           memcpy (charset, charsetstr, len);
818           charset[len] = '\0';
819 # endif
820
821           /* The output charset should normally be determined by the
822              locale.  But sometimes the locale is not used or not correctly
823              set up, so we provide a possibility for the user to override
824              this.  Moreover, the value specified through
825              bind_textdomain_codeset overrides both.  */
826           if (domainbinding != NULL && domainbinding->codeset != NULL)
827             outcharset = domainbinding->codeset;
828           else
829             {
830               outcharset = getenv ("OUTPUT_CHARSET");
831               if (outcharset == NULL || outcharset[0] == '\0')
832                 {
833 # ifdef _LIBC
834                   outcharset = _NL_CURRENT (LC_CTYPE, CODESET);
835 # else
836 #  if HAVE_ICONV
837                   extern const char *locale_charset (void);
838                   outcharset = locale_charset ();
839 #  endif
840 # endif
841                 }
842             }
843
844 # ifdef _LIBC
845           /* We always want to use transliteration.  */
846           outcharset = norm_add_slashes (outcharset, "TRANSLIT");
847           charset = norm_add_slashes (charset, NULL);
848           if (__gconv_open (outcharset, charset, &domain->conv,
849                             GCONV_AVOID_NOCONV)
850               != __GCONV_OK)
851             domain->conv = (__gconv_t) -1;
852 # else
853 #  if HAVE_ICONV
854           /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
855              we want to use transliteration.  */
856 #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
857        || _LIBICONV_VERSION >= 0x0105
858           if (strchr (outcharset, '/') == NULL)
859             {
860               char *tmp;
861
862               len = strlen (outcharset);
863               tmp = (char *) alloca (len + 10 + 1);
864               memcpy (tmp, outcharset, len);
865               memcpy (tmp + len, "//TRANSLIT", 10 + 1);
866               outcharset = tmp;
867
868               domain->conv = iconv_open (outcharset, charset);
869
870               freea (outcharset);
871             }
872           else
873 #   endif
874             domain->conv = iconv_open (outcharset, charset);
875 #  endif
876 # endif
877
878           freea (charset);
879         }
880 #endif /* _LIBC || HAVE_ICONV */
881     }
882
883   return nullentry;
884 }
885
886 /* Frees the codeset dependent parts of an opened message catalog.  */
887 void
888 internal_function
889 _nl_free_domain_conv (struct loaded_domain *domain)
890 {
891   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
892     free (domain->conv_tab);
893
894 #ifdef _LIBC
895   if (domain->conv != (__gconv_t) -1)
896     __gconv_close (domain->conv);
897 #else
898 # if HAVE_ICONV
899   if (domain->conv != (iconv_t) -1)
900     iconv_close (domain->conv);
901 # endif
902 #endif
903 }
904
905 /* Load the message catalogs specified by FILENAME.  If it is no valid
906    message catalog do nothing.  */
907 void
908 internal_function
909 _nl_load_domain (struct loaded_l10nfile *domain_file,
910                  struct binding *domainbinding)
911 {
912   int fd;
913   size_t size;
914 #ifdef _LIBC
915   struct stat64 st;
916 #else
917   struct stat st;
918 #endif
919   struct mo_file_header *data = (struct mo_file_header *) -1;
920   int use_mmap = 0;
921   struct loaded_domain *domain;
922   int revision;
923   const char *nullentry;
924
925   domain_file->decided = 1;
926   domain_file->data = NULL;
927
928   /* Note that it would be useless to store domainbinding in domain_file
929      because domainbinding might be == NULL now but != NULL later (after
930      a call to bind_textdomain_codeset).  */
931
932   /* If the record does not represent a valid locale the FILENAME
933      might be NULL.  This can happen when according to the given
934      specification the locale file name is different for XPG and CEN
935      syntax.  */
936   if (domain_file->filename == NULL)
937     return;
938
939   /* Try to open the addressed file.  */
940   fd = open (domain_file->filename, O_RDONLY | O_BINARY);
941   if (fd == -1)
942     return;
943
944   /* We must know about the size of the file.  */
945   if (
946 #ifdef _LIBC
947       __builtin_expect (fstat64 (fd, &st) != 0, 0)
948 #else
949       __builtin_expect (fstat (fd, &st) != 0, 0)
950 #endif
951       || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
952       || __builtin_expect (size < sizeof (struct mo_file_header), 0))
953     {
954       /* Something went wrong.  */
955       close (fd);
956       return;
957     }
958
959 #ifdef HAVE_MMAP
960   /* Now we are ready to load the file.  If mmap() is available we try
961      this first.  If not available or it failed we try to load it.  */
962   data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
963                                          MAP_PRIVATE, fd, 0);
964
965   if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
966     {
967       /* mmap() call was successful.  */
968       close (fd);
969       use_mmap = 1;
970     }
971 #endif
972
973   /* If the data is not yet available (i.e. mmap'ed) we try to load
974      it manually.  */
975   if (data == (struct mo_file_header *) -1)
976     {
977       size_t to_read;
978       char *read_ptr;
979
980       data = (struct mo_file_header *) malloc (size);
981       if (data == NULL)
982         return;
983
984       to_read = size;
985       read_ptr = (char *) data;
986       do
987         {
988           long int nb = (long int) read (fd, read_ptr, to_read);
989           if (nb <= 0)
990             {
991 #ifdef EINTR
992               if (nb == -1 && errno == EINTR)
993                 continue;
994 #endif
995               close (fd);
996               return;
997             }
998           read_ptr += nb;
999           to_read -= nb;
1000         }
1001       while (to_read > 0);
1002
1003       close (fd);
1004     }
1005
1006   /* Using the magic number we can test whether it really is a message
1007      catalog file.  */
1008   if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
1009                         0))
1010     {
1011       /* The magic number is wrong: not a message catalog file.  */
1012 #ifdef HAVE_MMAP
1013       if (use_mmap)
1014         munmap ((caddr_t) data, size);
1015       else
1016 #endif
1017         free (data);
1018       return;
1019     }
1020
1021   domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
1022   if (domain == NULL)
1023     return;
1024   domain_file->data = domain;
1025
1026   domain->data = (char *) data;
1027   domain->use_mmap = use_mmap;
1028   domain->mmap_size = size;
1029   domain->must_swap = data->magic != _MAGIC;
1030   domain->malloced = NULL;
1031
1032   /* Fill in the information about the available tables.  */
1033   revision = W (domain->must_swap, data->revision);
1034   /* We support only the major revisions 0 and 1.  */
1035   switch (revision >> 16)
1036     {
1037     case 0:
1038     case 1:
1039       domain->nstrings = W (domain->must_swap, data->nstrings);
1040       domain->orig_tab = (const struct string_desc *)
1041         ((char *) data + W (domain->must_swap, data->orig_tab_offset));
1042       domain->trans_tab = (const struct string_desc *)
1043         ((char *) data + W (domain->must_swap, data->trans_tab_offset));
1044       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
1045       domain->hash_tab =
1046         (domain->hash_size > 2
1047          ? (const nls_uint32 *)
1048            ((char *) data + W (domain->must_swap, data->hash_tab_offset))
1049          : NULL);
1050       domain->must_swap_hash_tab = domain->must_swap;
1051
1052       /* Now dispatch on the minor revision.  */
1053       switch (revision & 0xffff)
1054         {
1055         case 0:
1056           domain->n_sysdep_strings = 0;
1057           domain->orig_sysdep_tab = NULL;
1058           domain->trans_sysdep_tab = NULL;
1059           break;
1060         case 1:
1061         default:
1062           {
1063             nls_uint32 n_sysdep_strings;
1064
1065             if (domain->hash_tab == NULL)
1066               /* This is invalid.  These minor revisions need a hash table.  */
1067               goto invalid;
1068
1069             n_sysdep_strings =
1070               W (domain->must_swap, data->n_sysdep_strings);
1071             if (n_sysdep_strings > 0)
1072               {
1073                 nls_uint32 n_sysdep_segments;
1074                 const struct sysdep_segment *sysdep_segments;
1075                 const char **sysdep_segment_values;
1076                 const nls_uint32 *orig_sysdep_tab;
1077                 const nls_uint32 *trans_sysdep_tab;
1078                 nls_uint32 n_inmem_sysdep_strings;
1079                 size_t memneed;
1080                 char *mem;
1081                 struct sysdep_string_desc *inmem_orig_sysdep_tab;
1082                 struct sysdep_string_desc *inmem_trans_sysdep_tab;
1083                 nls_uint32 *inmem_hash_tab;
1084                 unsigned int i, j;
1085
1086                 /* Get the values of the system dependent segments.  */
1087                 n_sysdep_segments =
1088                   W (domain->must_swap, data->n_sysdep_segments);
1089                 sysdep_segments = (const struct sysdep_segment *)
1090                   ((char *) data
1091                    + W (domain->must_swap, data->sysdep_segments_offset));
1092                 sysdep_segment_values =
1093                   alloca (n_sysdep_segments * sizeof (const char *));
1094                 for (i = 0; i < n_sysdep_segments; i++)
1095                   {
1096                     const char *name =
1097                       (char *) data
1098                       + W (domain->must_swap, sysdep_segments[i].offset);
1099                     nls_uint32 namelen =
1100                       W (domain->must_swap, sysdep_segments[i].length);
1101
1102                     if (!(namelen > 0 && name[namelen - 1] == '\0'))
1103                       {
1104                         freea (sysdep_segment_values);
1105                         goto invalid;
1106                       }
1107
1108                     sysdep_segment_values[i] = get_sysdep_segment_value (name);
1109                   }
1110
1111                 orig_sysdep_tab = (const nls_uint32 *)
1112                   ((char *) data
1113                    + W (domain->must_swap, data->orig_sysdep_tab_offset));
1114                 trans_sysdep_tab = (const nls_uint32 *)
1115                   ((char *) data
1116                    + W (domain->must_swap, data->trans_sysdep_tab_offset));
1117
1118                 /* Compute the amount of additional memory needed for the
1119                    system dependent strings and the augmented hash table.
1120                    At the same time, also drop string pairs which refer to
1121                    an undefined system dependent segment.  */
1122                 n_inmem_sysdep_strings = 0;
1123                 memneed = domain->hash_size * sizeof (nls_uint32);
1124                 for (i = 0; i < n_sysdep_strings; i++)
1125                   {
1126                     int valid = 1;
1127                     size_t needs[2];
1128
1129                     for (j = 0; j < 2; j++)
1130                       {
1131                         const struct sysdep_string *sysdep_string =
1132                           (const struct sysdep_string *)
1133                           ((char *) data
1134                            + W (domain->must_swap,
1135                                 j == 0
1136                                 ? orig_sysdep_tab[i]
1137                                 : trans_sysdep_tab[i]));
1138                         size_t need = 0;
1139                         const struct segment_pair *p = sysdep_string->segments;
1140
1141                         if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
1142                           for (p = sysdep_string->segments;; p++)
1143                             {
1144                               nls_uint32 sysdepref;
1145
1146                               need += W (domain->must_swap, p->segsize);
1147
1148                               sysdepref = W (domain->must_swap, p->sysdepref);
1149                               if (sysdepref == SEGMENTS_END)
1150                                 break;
1151
1152                               if (sysdepref >= n_sysdep_segments)
1153                                 {
1154                                   /* Invalid.  */
1155                                   freea (sysdep_segment_values);
1156                                   goto invalid;
1157                                 }
1158
1159                               if (sysdep_segment_values[sysdepref] == NULL)
1160                                 {
1161                                   /* This particular string pair is invalid.  */
1162                                   valid = 0;
1163                                   break;
1164                                 }
1165
1166                               need += strlen (sysdep_segment_values[sysdepref]);
1167                             }
1168
1169                         needs[j] = need;
1170                         if (!valid)
1171                           break;
1172                       }
1173
1174                     if (valid)
1175                       {
1176                         n_inmem_sysdep_strings++;
1177                         memneed += needs[0] + needs[1];
1178                       }
1179                   }
1180                 memneed += 2 * n_inmem_sysdep_strings
1181                            * sizeof (struct sysdep_string_desc);
1182
1183                 if (n_inmem_sysdep_strings > 0)
1184                   {
1185                     unsigned int k;
1186
1187                     /* Allocate additional memory.  */
1188                     mem = (char *) malloc (memneed);
1189                     if (mem == NULL)
1190                       goto invalid;
1191
1192                     domain->malloced = mem;
1193                     inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
1194                     mem += n_inmem_sysdep_strings
1195                            * sizeof (struct sysdep_string_desc);
1196                     inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
1197                     mem += n_inmem_sysdep_strings
1198                            * sizeof (struct sysdep_string_desc);
1199                     inmem_hash_tab = (nls_uint32 *) mem;
1200                     mem += domain->hash_size * sizeof (nls_uint32);
1201
1202                     /* Compute the system dependent strings.  */
1203                     k = 0;
1204                     for (i = 0; i < n_sysdep_strings; i++)
1205                       {
1206                         int valid = 1;
1207
1208                         for (j = 0; j < 2; j++)
1209                           {
1210                             const struct sysdep_string *sysdep_string =
1211                               (const struct sysdep_string *)
1212                               ((char *) data
1213                                + W (domain->must_swap,
1214                                     j == 0
1215                                     ? orig_sysdep_tab[i]
1216                                     : trans_sysdep_tab[i]));
1217                             const struct segment_pair *p =
1218                               sysdep_string->segments;
1219
1220                             if (W (domain->must_swap, p->sysdepref)
1221                                 != SEGMENTS_END)
1222                               for (p = sysdep_string->segments;; p++)
1223                                 {
1224                                   nls_uint32 sysdepref;
1225
1226                                   sysdepref =
1227                                     W (domain->must_swap, p->sysdepref);
1228                                   if (sysdepref == SEGMENTS_END)
1229                                     break;
1230
1231                                   if (sysdep_segment_values[sysdepref] == NULL)
1232                                     {
1233                                       /* This particular string pair is
1234                                          invalid.  */
1235                                       valid = 0;
1236                                       break;
1237                                     }
1238                                 }
1239
1240                             if (!valid)
1241                               break;
1242                           }
1243
1244                         if (valid)
1245                           {
1246                             for (j = 0; j < 2; j++)
1247                               {
1248                                 const struct sysdep_string *sysdep_string =
1249                                   (const struct sysdep_string *)
1250                                   ((char *) data
1251                                    + W (domain->must_swap,
1252                                         j == 0
1253                                         ? orig_sysdep_tab[i]
1254                                         : trans_sysdep_tab[i]));
1255                                 const char *static_segments =
1256                                   (char *) data
1257                                   + W (domain->must_swap, sysdep_string->offset);
1258                                 const struct segment_pair *p =
1259                                   sysdep_string->segments;
1260
1261                                 /* Concatenate the segments, and fill
1262                                    inmem_orig_sysdep_tab[k] (for j == 0) and
1263                                    inmem_trans_sysdep_tab[k] (for j == 1).  */
1264
1265                                 struct sysdep_string_desc *inmem_tab_entry =
1266                                   (j == 0
1267                                    ? inmem_orig_sysdep_tab
1268                                    : inmem_trans_sysdep_tab)
1269                                   + k;
1270
1271                                 if (W (domain->must_swap, p->sysdepref)
1272                                     == SEGMENTS_END)
1273                                   {
1274                                     /* Only one static segment.  */
1275                                     inmem_tab_entry->length =
1276                                       W (domain->must_swap, p->segsize);
1277                                     inmem_tab_entry->pointer = static_segments;
1278                                   }
1279                                 else
1280                                   {
1281                                     inmem_tab_entry->pointer = mem;
1282
1283                                     for (p = sysdep_string->segments;; p++)
1284                                       {
1285                                         nls_uint32 segsize =
1286                                           W (domain->must_swap, p->segsize);
1287                                         nls_uint32 sysdepref =
1288                                           W (domain->must_swap, p->sysdepref);
1289                                         size_t n;
1290
1291                                         if (segsize > 0)
1292                                           {
1293                                             memcpy (mem, static_segments, segsize);
1294                                             mem += segsize;
1295                                             static_segments += segsize;
1296                                           }
1297
1298                                         if (sysdepref == SEGMENTS_END)
1299                                           break;
1300
1301                                         n = strlen (sysdep_segment_values[sysdepref]);
1302                                         memcpy (mem, sysdep_segment_values[sysdepref], n);
1303                                         mem += n;
1304                                       }
1305
1306                                     inmem_tab_entry->length =
1307                                       mem - inmem_tab_entry->pointer;
1308                                   }
1309                               }
1310
1311                             k++;
1312                           }
1313                       }
1314                     if (k != n_inmem_sysdep_strings)
1315                       abort ();
1316
1317                     /* Compute the augmented hash table.  */
1318                     for (i = 0; i < domain->hash_size; i++)
1319                       inmem_hash_tab[i] =
1320                         W (domain->must_swap_hash_tab, domain->hash_tab[i]);
1321                     for (i = 0; i < n_inmem_sysdep_strings; i++)
1322                       {
1323                         const char *msgid = inmem_orig_sysdep_tab[i].pointer;
1324                         nls_uint32 hash_val = hash_string (msgid);
1325                         nls_uint32 idx = hash_val % domain->hash_size;
1326                         nls_uint32 incr =
1327                           1 + (hash_val % (domain->hash_size - 2));
1328
1329                         for (;;)
1330                           {
1331                             if (inmem_hash_tab[idx] == 0)
1332                               {
1333                                 /* Hash table entry is empty.  Use it.  */
1334                                 inmem_hash_tab[idx] = 1 + domain->nstrings + i;
1335                                 break;
1336                               }
1337
1338                             if (idx >= domain->hash_size - incr)
1339                               idx -= domain->hash_size - incr;
1340                             else
1341                               idx += incr;
1342                           }
1343                       }
1344
1345                     domain->n_sysdep_strings = n_inmem_sysdep_strings;
1346                     domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
1347                     domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
1348
1349                     domain->hash_tab = inmem_hash_tab;
1350                     domain->must_swap_hash_tab = 0;
1351                   }
1352                 else
1353                   {
1354                     domain->n_sysdep_strings = 0;
1355                     domain->orig_sysdep_tab = NULL;
1356                     domain->trans_sysdep_tab = NULL;
1357                   }
1358
1359                 freea (sysdep_segment_values);
1360               }
1361             else
1362               {
1363                 domain->n_sysdep_strings = 0;
1364                 domain->orig_sysdep_tab = NULL;
1365                 domain->trans_sysdep_tab = NULL;
1366               }
1367           }
1368           break;
1369         }
1370       break;
1371     default:
1372       /* This is an invalid revision.  */
1373     invalid:
1374       /* This is an invalid .mo file.  */
1375       if (domain->malloced)
1376         free (domain->malloced);
1377 #ifdef HAVE_MMAP
1378       if (use_mmap)
1379         munmap ((caddr_t) data, size);
1380       else
1381 #endif
1382         free (data);
1383       free (domain);
1384       domain_file->data = NULL;
1385       return;
1386     }
1387
1388   /* Now initialize the character set converter from the character set
1389      the file is encoded with (found in the header entry) to the domain's
1390      specified character set or the locale's character set.  */
1391   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
1392
1393   /* Also look for a plural specification.  */
1394   EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
1395 }
1396
1397
1398 #ifdef _LIBC
1399 void
1400 internal_function
1401 _nl_unload_domain (struct loaded_domain *domain)
1402 {
1403   if (domain->plural != &__gettext_germanic_plural)
1404     __gettext_free_exp (domain->plural);
1405
1406   _nl_free_domain_conv (domain);
1407
1408   if (domain->malloced)
1409     free (domain->malloced);
1410
1411 # ifdef _POSIX_MAPPED_FILES
1412   if (domain->use_mmap)
1413     munmap ((caddr_t) domain->data, domain->mmap_size);
1414   else
1415 # endif /* _POSIX_MAPPED_FILES */
1416     free ((void *) domain->data);
1417
1418   free (domain);
1419 }
1420 #endif