"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/intl/loadmsgcat.c" (23 Aug 2021, 15020 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Load needed message catalogs.
2 Copyright (C) 1995-1999, 2000, 2001 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 <autoconf.h> because <autoconf.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 <autoconf.h>
28 #endif
29
30 #undef freea
31
32 /* see AC_FUNC_ALLOCA macro */
33 #ifdef __GNUC__
34 # define alloca __builtin_alloca
35 #else
36 # ifdef _MSC_VER
37 # include <malloc.h>
38 # define alloca _alloca
39 # else
40 # if HAVE_ALLOCA_H
41 # include <alloca.h>
42 # else
43 # ifdef _AIX
44 #pragma alloca
45 # else
46 # ifndef alloca /* predefined by HP cc +Olibcalls */
47 char *alloca ();
48 # else
49 # define freea(n) free(n)
50 # endif
51 # endif
52 # endif
53 # endif
54 #endif
55
56 #ifndef freea
57 #define freea(n) /* nothing */
58 #endif
59
60 #include <ctype.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65
66 #include <stdlib.h>
67 #include <string.h>
68
69 #if defined HAVE_UNISTD_H || defined _LIBC
70 # include <unistd.h>
71 #endif
72
73 #ifdef _LIBC
74 # include <langinfo.h>
75 # include <locale.h>
76 #endif
77
78 #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
79 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
80 # include <sys/mman.h>
81 # undef HAVE_MMAP
82 # define HAVE_MMAP 1
83 #else
84 # undef HAVE_MMAP
85 #endif
86
87 #include "gettext.h"
88 #include "gettextP.h"
89
90 #ifdef _LIBC
91 # include "../locale/localeinfo.h"
92 #endif
93
94 /* @@ end of prolog @@ */
95
96 #ifdef _LIBC
97 /* Rename the non ISO C functions. This is required by the standard
98 because some ISO C functions will require linking with this object
99 file and the name space must not be polluted. */
100 # define open __open
101 # define close __close
102 # define read __read
103 # define mmap __mmap
104 # define munmap __munmap
105 #endif
106
107 /* Names for the libintl functions are a problem. They must not clash
108 with existing names and they should follow ANSI C. But this source
109 code is also used in GNU C Library where the names have a __
110 prefix. So we have to make a difference here. */
111 #ifdef _LIBC
112 # define PLURAL_PARSE __gettextparse
113 #else
114 # define PLURAL_PARSE gettextparse__
115 #endif
116
117 /* For systems that distinguish between text and binary I/O.
118 O_BINARY is usually declared in <fcntl.h>. */
119 #if !defined O_BINARY && defined _O_BINARY
120 /* For MSC-compatible compilers. */
121 # define O_BINARY _O_BINARY
122 # define O_TEXT _O_TEXT
123 #endif
124 #ifdef __BEOS__
125 /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
126 # undef O_BINARY
127 # undef O_TEXT
128 #endif
129 /* On reasonable systems, binary I/O is the default. */
130 #ifndef O_BINARY
131 # define O_BINARY 0
132 #endif
133
134 /* We need a sign, whether a new catalog was loaded, which can be associated
135 with all translations. This is important if the translations are
136 cached by one of GCC's features. */
137 int _nl_msg_cat_cntr;
138
139 #if (defined __GNUC__ && !defined __APPLE_CC__) \
140 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
141
142 /* These structs are the constant expression for the germanic plural
143 form determination. It represents the expression "n != 1". */
144 static const struct expression plvar =
145 {
146 .nargs = 0,
147 .operation = var,
148 };
149 static const struct expression plone =
150 {
151 .nargs = 0,
152 .operation = num,
153 .val =
154 {
155 .num = 1
156 }
157 };
158 static struct expression germanic_plural =
159 {
160 .nargs = 2,
161 .operation = not_equal,
162 .val =
163 {
164 .args =
165 {
166 [0] = (struct expression *) &plvar,
167 [1] = (struct expression *) &plone
168 }
169 }
170 };
171
172 # define INIT_GERMANIC_PLURAL()
173
174 #else
175
176 /* For compilers without support for ISO C 99 struct/union initializers:
177 Initialization at run-time. */
178
179 static struct expression plvar;
180 static struct expression plone;
181 static struct expression germanic_plural;
182
183 static void
184 init_germanic_plural ()
185 {
186 if (plone.val.num == 0)
187 {
188 plvar.nargs = 0;
189 plvar.operation = var;
190
191 plone.nargs = 0;
192 plone.operation = num;
193 plone.val.num = 1;
194
195 germanic_plural.nargs = 2;
196 germanic_plural.operation = not_equal;
197 germanic_plural.val.args[0] = &plvar;
198 germanic_plural.val.args[1] = &plone;
199 }
200 }
201
202 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
203
204 #endif
205
206
207 /* Initialize the codeset dependent parts of an opened message catalog.
208 Return the header entry. */
209 const char *
210 internal_function
211 _nl_init_domain_conv (domain_file, domain, domainbinding)
212 struct loaded_l10nfile *domain_file;
213 struct loaded_domain *domain;
214 struct binding *domainbinding;
215 {
216 /* Find out about the character set the file is encoded with.
217 This can be found (in textual form) in the entry "". If this
218 entry does not exist or if this does not contain the `charset='
219 information, we will assume the charset matches the one the
220 current locale and we don't have to perform any conversion. */
221 char *nullentry;
222 size_t nullentrylen;
223
224 /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
225 domain->codeset_cntr =
226 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
227 #ifdef _LIBC
228 domain->conv = (__gconv_t) -1;
229 #else
230 # ifdef HAVE_ICONV
231 domain->conv = (iconv_t) -1;
232 # endif
233 #endif
234 domain->conv_tab = NULL;
235
236 /* Get the header entry. */
237 nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
238
239 if (nullentry != NULL)
240 {
241 #if defined _LIBC || defined HAVE_ICONV
242 const char *charsetstr;
243
244 charsetstr = strstr (nullentry, "charset=");
245 if (charsetstr != NULL)
246 {
247 size_t len;
248 char *charset;
249 const char *outcharset;
250
251 charsetstr += strlen ("charset=");
252 len = strcspn (charsetstr, " \t\n");
253
254 charset = (char *) alloca (len + 1);
255 # if defined _LIBC || HAVE_MEMPCPY
256 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
257 # else
258 memcpy (charset, charsetstr, len);
259 charset[len] = '\0';
260 # endif
261
262 /* The output charset should normally be determined by the
263 locale. But sometimes the locale is not used or not correctly
264 set up, so we provide a possibility for the user to override
265 this. Moreover, the value specified through
266 bind_textdomain_codeset overrides both. */
267 if (domainbinding != NULL && domainbinding->codeset != NULL)
268 outcharset = domainbinding->codeset;
269 else
270 {
271 outcharset = getenv ("OUTPUT_CHARSET");
272 if (outcharset == NULL || outcharset[0] == '\0')
273 {
274 # ifdef _LIBC
275 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
276 # else
277 # if HAVE_ICONV
278 extern const char *locale_charset (void);
279 outcharset = locale_charset ();
280 # endif
281 # endif
282 }
283 }
284
285 # ifdef _LIBC
286 /* We always want to use transliteration. */
287 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
288 charset = norm_add_slashes (charset, NULL);
289 if (__gconv_open (outcharset, charset, &domain->conv,
290 GCONV_AVOID_NOCONV)
291 != __GCONV_OK)
292 domain->conv = (__gconv_t) -1;
293 # else
294 # if HAVE_ICONV
295 /* When using GNU libiconv, we want to use transliteration. */
296 # if _LIBICONV_VERSION >= 0x0105
297 len = strlen (outcharset);
298 {
299 char *tmp = (char *) alloca (len + 10 + 1);
300 memcpy (tmp, outcharset, len);
301 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
302 outcharset = tmp;
303 }
304 # endif
305 domain->conv = iconv_open (outcharset, charset);
306 # if _LIBICONV_VERSION >= 0x0105
307 freea (outcharset);
308 # endif
309 # endif
310 # endif
311
312 freea (charset);
313 }
314 #endif /* _LIBC || HAVE_ICONV */
315 }
316
317 return nullentry;
318 }
319
320 /* Frees the codeset dependent parts of an opened message catalog. */
321 void
322 internal_function
323 _nl_free_domain_conv (domain)
324 struct loaded_domain *domain;
325 {
326 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
327 free (domain->conv_tab);
328
329 #ifdef _LIBC
330 if (domain->conv != (__gconv_t) -1)
331 __gconv_close (domain->conv);
332 #else
333 # ifdef HAVE_ICONV
334 if (domain->conv != (iconv_t) -1)
335 iconv_close (domain->conv);
336 # endif
337 #endif
338 }
339
340 /* Load the message catalogs specified by FILENAME. If it is no valid
341 message catalog do nothing. */
342 void
343 internal_function
344 _nl_load_domain (domain_file, domainbinding)
345 struct loaded_l10nfile *domain_file;
346 struct binding *domainbinding;
347 {
348 int fd;
349 size_t size;
350 #ifdef _LIBC
351 struct stat64 st;
352 #else
353 struct stat st;
354 #endif
355 struct mo_file_header *data = (struct mo_file_header *) -1;
356 int use_mmap = 0;
357 struct loaded_domain *domain;
358 const char *nullentry;
359
360 domain_file->decided = 1;
361 domain_file->data = NULL;
362
363 /* Note that it would be useless to store domainbinding in domain_file
364 because domainbinding might be == NULL now but != NULL later (after
365 a call to bind_textdomain_codeset). */
366
367 /* If the record does not represent a valid locale the FILENAME
368 might be NULL. This can happen when according to the given
369 specification the locale file name is different for XPG and CEN
370 syntax. */
371 if (domain_file->filename == NULL)
372 return;
373
374 /* Try to open the addressed file. */
375 fd = open (domain_file->filename, O_RDONLY | O_BINARY);
376 if (fd == -1)
377 return;
378
379 /* We must know about the size of the file. */
380 if (
381 #ifdef _LIBC
382 __builtin_expect (fstat64 (fd, &st) != 0, 0)
383 #else
384 __builtin_expect (fstat (fd, &st) != 0, 0)
385 #endif
386 || __builtin_expect ((size = (size_t) st.st_size) != (size_t) st.st_size, 0)
387 || __builtin_expect (size < sizeof (struct mo_file_header), 0))
388 {
389 /* Something went wrong. */
390 close (fd);
391 return;
392 }
393
394 #ifdef HAVE_MMAP
395 /* Now we are ready to load the file. If mmap() is available we try
396 this first. If not available or it failed we try to load it. */
397 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
398 MAP_PRIVATE, fd, 0);
399
400 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
401 {
402 /* mmap() call was successful. */
403 close (fd);
404 use_mmap = 1;
405 }
406 #endif
407
408 /* If the data is not yet available (i.e. mmap'ed) we try to load
409 it manually. */
410 if (data == (struct mo_file_header *) -1)
411 {
412 size_t to_read;
413 char *read_ptr;
414
415 data = (struct mo_file_header *) malloc (size);
416 if (data == NULL) {
417 if (!use_mmap)
418 close (fd);
419 return;
420 }
421
422 to_read = size;
423 read_ptr = (char *) data;
424 do
425 {
426 long int nb = (long int) read (fd, read_ptr, to_read);
427 if (nb <= 0)
428 {
429 #ifdef EINTR
430 if (nb == -1 && errno == EINTR)
431 continue;
432 #endif
433 close (fd);
434 return;
435 }
436 read_ptr += nb;
437 to_read -= nb;
438 }
439 while (to_read > 0);
440
441 close (fd);
442 }
443
444 /* Using the magic number we can test whether it really is a message
445 catalog file. */
446 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
447 0))
448 {
449 /* The magic number is wrong: not a message catalog file. */
450 #ifdef HAVE_MMAP
451 if (use_mmap)
452 munmap ((caddr_t) data, size);
453 else
454 #endif
455 free (data);
456 return;
457 }
458
459 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
460 if (domain == NULL)
461 return;
462 domain_file->data = domain;
463
464 domain->data = (char *) data;
465 domain->use_mmap = use_mmap;
466 domain->mmap_size = size;
467 domain->must_swap = data->magic != _MAGIC;
468
469 /* Fill in the information about the available tables. */
470 switch (W (domain->must_swap, data->revision))
471 {
472 case 0:
473 domain->nstrings = W (domain->must_swap, data->nstrings);
474 domain->orig_tab = (struct string_desc *)
475 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
476 domain->trans_tab = (struct string_desc *)
477 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
478 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
479 domain->hash_tab = (nls_uint32 *)
480 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
481 break;
482 default:
483 /* This is an invalid revision. */
484 #ifdef HAVE_MMAP
485 if (use_mmap)
486 munmap ((caddr_t) data, size);
487 else
488 #endif
489 free (data);
490 free (domain);
491 domain_file->data = NULL;
492 return;
493 }
494
495 /* Now initialize the character set converter from the character set
496 the file is encoded with (found in the header entry) to the domain's
497 specified character set or the locale's character set. */
498 nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
499
500 /* Also look for a plural specification. */
501 if (nullentry != NULL)
502 {
503 const char *plural;
504 const char *nplurals;
505
506 plural = strstr (nullentry, "plural=");
507 nplurals = strstr (nullentry, "nplurals=");
508 if (plural == NULL || nplurals == NULL)
509 goto no_plural;
510 else
511 {
512 /* First get the number. */
513 char *endp;
514 unsigned long int n;
515 struct parse_args args;
516
517 nplurals += 9;
518 while (*nplurals != '\0' && isspace (*nplurals))
519 ++nplurals;
520 #if defined HAVE_STRTOUL || defined _LIBC
521 n = strtoul (nplurals, &endp, 10);
522 #else
523 for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
524 n = n * 10 + (*endp - '0');
525 #endif
526 domain->nplurals = n;
527 if (nplurals == endp)
528 goto no_plural;
529
530 /* Due to the restrictions bison imposes onto the interface of the
531 scanner function we have to put the input string and the result
532 passed up from the parser into the same structure which address
533 is passed down to the parser. */
534 plural += 7;
535 args.cp = plural;
536 if (PLURAL_PARSE (&args) != 0)
537 goto no_plural;
538 domain->plural = args.res;
539 }
540 }
541 else
542 {
543 /* By default we are using the Germanic form: singular form only
544 for `one', the plural form otherwise. Yes, this is also what
545 English is using since English is a Germanic language. */
546 no_plural:
547 INIT_GERMANIC_PLURAL ();
548 domain->plural = &germanic_plural;
549 domain->nplurals = 2;
550 }
551 }
552
553
554 #ifdef _LIBC
555 void
556 internal_function
557 _nl_unload_domain (domain)
558 struct loaded_domain *domain;
559 {
560 if (domain->plural != &germanic_plural)
561 __gettext_free_exp (domain->plural);
562
563 _nl_free_domain_conv (domain);
564
565 # ifdef _POSIX_MAPPED_FILES
566 if (domain->use_mmap)
567 munmap ((caddr_t) domain->data, domain->mmap_size);
568 else
569 # endif /* _POSIX_MAPPED_FILES */
570 free ((void *) domain->data);
571
572 free (domain);
573 }
574 #endif