00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE 1
00024 #endif
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <fcntl.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035
00036 #ifdef __GNUC__
00037 # define alloca __builtin_alloca
00038 # define HAVE_ALLOCA 1
00039 #else
00040 # if defined HAVE_ALLOCA_H || defined _LIBC
00041 # include <alloca.h>
00042 # else
00043 # ifdef _AIX
00044 #pragma alloca
00045 # else
00046 # ifndef alloca
00047 char *alloca ();
00048 # endif
00049 # endif
00050 # endif
00051 #endif
00052
00053 #include <stdlib.h>
00054 #include <string.h>
00055
00056 #if defined HAVE_UNISTD_H || defined _LIBC
00057 # include <unistd.h>
00058 #endif
00059
00060 #ifdef _LIBC
00061 # include <langinfo.h>
00062 # include <locale.h>
00063 #endif
00064
00065 #if (defined HAVE_MMAP_FILE && !defined DISALLOW_MMAP) \
00066 || (defined _LIBC && defined _POSIX_MAPPED_FILES)
00067 # include <sys/mman.h>
00068 # undef HAVE_MMAP
00069 # define HAVE_MMAP 1
00070 #else
00071 # undef HAVE_MMAP
00072 #endif
00073
00074 #include "gettext.h"
00075 #include "gettextP.h"
00076
00077 #ifdef _LIBC
00078 # include "../locale/localeinfo.h"
00079 #endif
00080
00081
00082
00083 #define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1))
00084
00085
00086 #define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \
00087 ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0))
00088 #define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t)))
00089
00090
00091
00092 #ifdef _LIBC
00093
00094
00095
00096 # define open __open
00097 # define close __close
00098 # define read __read
00099 # define mmap __mmap
00100 # define munmap __munmap
00101 #endif
00102
00103
00104
00105
00106
00107 #ifdef _LIBC
00108 # define PLURAL_PARSE __gettextparse
00109 #else
00110 # define PLURAL_PARSE gettextparse__
00111 #endif
00112
00113
00114
00115 #ifdef HAVE_ALLOCA
00116 # define freea(p)
00117 #else
00118 # define alloca(n) malloc (n)
00119 # define freea(p) free (p)
00120 #endif
00121
00122
00123
00124 #if !defined O_BINARY && defined _O_BINARY
00125
00126 # define O_BINARY _O_BINARY
00127 # define O_TEXT _O_TEXT
00128 #endif
00129 #ifdef __BEOS__
00130
00131 # undef O_BINARY
00132 # undef O_TEXT
00133 #endif
00134
00135 #ifndef O_BINARY
00136 # define O_BINARY 0
00137 #endif
00138
00139
00140
00141
00142 int _nl_msg_cat_cntr;
00143
00144 #if (defined __GNUC__ && !defined __APPLE_CC__) \
00145 || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
00146
00147
00148
00149
00150 __extension__ static const struct expression plvar =
00151 {
00152 .nargs = 0,
00153 .operation = var,
00154 };
00155 __extension__ static const struct expression plone =
00156 {
00157 .nargs = 0,
00158 .operation = num,
00159 .val =
00160 {
00161 .num = 1
00162 }
00163 };
00164 __extension__ static struct expression germanic_plural =
00165 {
00166 .nargs = 2,
00167 .operation = not_equal,
00168 .val =
00169 {
00170 .args =
00171 {
00172 [0] = (struct expression *) &plvar,
00173 [1] = (struct expression *) &plone
00174 }
00175 }
00176 };
00177
00178 # define INIT_GERMANIC_PLURAL()
00179
00180 #else
00181
00182
00183
00184
00185 static struct expression plvar;
00186 static struct expression plone;
00187 static struct expression germanic_plural;
00188
00189 static void
00190 init_germanic_plural ()
00191 {
00192 if (plone.val.num == 0)
00193 {
00194 plvar.nargs = 0;
00195 plvar.operation = var;
00196
00197 plone.nargs = 0;
00198 plone.operation = num;
00199 plone.val.num = 1;
00200
00201 germanic_plural.nargs = 2;
00202 germanic_plural.operation = not_equal;
00203 germanic_plural.val.args[0] = &plvar;
00204 germanic_plural.val.args[1] = &plone;
00205 }
00206 }
00207
00208 # define INIT_GERMANIC_PLURAL() init_germanic_plural ()
00209
00210 #endif
00211
00212
00213
00214
00215 const char *
00216 internal_function
00217 _nl_init_domain_conv (domain_file, domain, domainbinding)
00218 struct loaded_l10nfile *domain_file;
00219 struct loaded_domain *domain;
00220 struct binding *domainbinding;
00221 {
00222
00223
00224
00225
00226
00227 char *nullentry;
00228 size_t nullentrylen;
00229
00230
00231 domain->codeset_cntr =
00232 (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
00233 #ifdef _LIBC
00234 domain->conv = (__gconv_t) -1;
00235 #else
00236 # if HAVE_ICONV
00237 domain->conv = (iconv_t) -1;
00238 # endif
00239 #endif
00240 domain->conv_tab = NULL;
00241
00242
00243 nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
00244
00245 if (nullentry != NULL)
00246 {
00247 #if defined _LIBC || HAVE_ICONV
00248 const char *charsetstr;
00249
00250 charsetstr = strstr (nullentry, "charset=");
00251 if (charsetstr != NULL)
00252 {
00253 size_t len;
00254 char *charset;
00255 const char *outcharset;
00256
00257 charsetstr += strlen ("charset=");
00258 len = strcspn (charsetstr, " \t\n");
00259
00260 charset = (char *) alloca (len + 1);
00261 # if defined _LIBC || HAVE_MEMPCPY
00262 *((char *) mempcpy (charset, charsetstr, len)) = '\0';
00263 # else
00264 memcpy (charset, charsetstr, len);
00265 charset[len] = '\0';
00266 # endif
00267
00268
00269
00270
00271
00272
00273 if (domainbinding != NULL && domainbinding->codeset != NULL)
00274 outcharset = domainbinding->codeset;
00275 else
00276 {
00277 outcharset = getenv ("OUTPUT_CHARSET");
00278 if (outcharset == NULL || outcharset[0] == '\0')
00279 {
00280 # ifdef _LIBC
00281 outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
00282 # else
00283 # if HAVE_ICONV
00284 outcharset = locale_charset ();
00285 # endif
00286 # endif
00287 }
00288 }
00289
00290 # ifdef _LIBC
00291
00292 outcharset = norm_add_slashes (outcharset, "TRANSLIT");
00293 charset = norm_add_slashes (charset, NULL);
00294 if (__gconv_open (outcharset, charset, &domain->conv,
00295 GCONV_AVOID_NOCONV)
00296 != __GCONV_OK)
00297 domain->conv = (__gconv_t) -1;
00298 # else
00299 # if HAVE_ICONV
00300
00301 # if _LIBICONV_VERSION >= 0x0105
00302 len = strlen (outcharset);
00303 {
00304 char *tmp = (char *) alloca (len + 10 + 1);
00305 memcpy (tmp, outcharset, len);
00306 memcpy (tmp + len, "//TRANSLIT", 10 + 1);
00307 outcharset = tmp;
00308 }
00309 # endif
00310 domain->conv = iconv_open (outcharset, charset);
00311 # if _LIBICONV_VERSION >= 0x0105
00312 freea (outcharset);
00313 # endif
00314 # endif
00315 # endif
00316
00317 freea (charset);
00318 }
00319 #endif
00320 }
00321
00322 return nullentry;
00323 }
00324
00325
00326 void
00327 internal_function
00328 _nl_free_domain_conv (domain)
00329 struct loaded_domain *domain;
00330 {
00331 if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
00332 free (domain->conv_tab);
00333
00334 #ifdef _LIBC
00335 if (domain->conv != (__gconv_t) -1)
00336 __gconv_close (domain->conv);
00337 #else
00338 # if HAVE_ICONV
00339 if (domain->conv != (iconv_t) -1)
00340 iconv_close (domain->conv);
00341 # endif
00342 #endif
00343 }
00344
00345
00346
00347 void
00348 internal_function
00349 _nl_load_domain (domain_file, domainbinding)
00350 struct loaded_l10nfile *domain_file;
00351 struct binding *domainbinding;
00352 {
00353 int fd;
00354 size_t size;
00355 #ifdef _LIBC
00356 struct stat64 st;
00357 #else
00358 struct stat st;
00359 #endif
00360 struct mo_file_header *data = (struct mo_file_header *) -1;
00361 int use_mmap = 0;
00362 struct loaded_domain *domain;
00363 const char *nullentry;
00364
00365 domain_file->decided = 1;
00366 domain_file->data = NULL;
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 if (domain_file->filename == NULL)
00377 return;
00378
00379
00380 fd = open (domain_file->filename, O_RDONLY | O_BINARY);
00381 if (fd == -1)
00382 return;
00383
00384
00385
00386
00387 if (
00388 #ifdef _LIBC
00389 __builtin_expect (fstat64 (fd, &st) != 0, 0)
00390 #else
00391 __builtin_expect (fstat (fd, &st) != 0, 0)
00392 #endif
00393 || __builtin_expect (st.st_size > INTTYPE_MAXIMUM (ssize_t), 0)
00394 || __builtin_expect (st.st_size < (off_t) sizeof (struct mo_file_header),
00395 0))
00396 {
00397
00398 close (fd);
00399 return;
00400 }
00401 size = (size_t) st.st_size;
00402
00403 #ifdef HAVE_MMAP
00404
00405
00406 data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
00407 MAP_PRIVATE, fd, 0);
00408
00409 if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
00410 {
00411
00412 close (fd);
00413 use_mmap = 1;
00414 }
00415 #endif
00416
00417
00418
00419 if (data == (struct mo_file_header *) -1)
00420 {
00421 size_t to_read;
00422 char *read_ptr;
00423
00424 data = (struct mo_file_header *) malloc (size);
00425 if (data == NULL)
00426 return;
00427
00428 to_read = size;
00429 read_ptr = (char *) data;
00430 do
00431 {
00432 long int nb = (long int) read (fd, read_ptr, to_read);
00433 if (nb <= 0)
00434 {
00435 #ifdef EINTR
00436 if (nb == -1 && errno == EINTR)
00437 continue;
00438 #endif
00439 close (fd);
00440 return;
00441 }
00442 read_ptr += nb;
00443 to_read -= nb;
00444 }
00445 while (to_read > 0);
00446
00447 close (fd);
00448 }
00449
00450
00451
00452 if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
00453 0))
00454 {
00455
00456 #ifdef HAVE_MMAP
00457 if (use_mmap)
00458 munmap ((caddr_t) data, size);
00459 else
00460 #endif
00461 free (data);
00462 return;
00463 }
00464
00465 domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
00466 if (domain == NULL)
00467 return;
00468 domain_file->data = domain;
00469
00470 domain->data = (char *) data;
00471 domain->use_mmap = use_mmap;
00472 domain->mmap_size = size;
00473 domain->must_swap = data->magic != _MAGIC;
00474
00475
00476 switch (W (domain->must_swap, data->revision))
00477 {
00478 case 0:
00479 domain->nstrings = W (domain->must_swap, data->nstrings);
00480 domain->orig_tab = (struct string_desc *)
00481 ((char *) data + W (domain->must_swap, data->orig_tab_offset));
00482 domain->trans_tab = (struct string_desc *)
00483 ((char *) data + W (domain->must_swap, data->trans_tab_offset));
00484 domain->hash_size = W (domain->must_swap, data->hash_tab_size);
00485 domain->hash_tab = (nls_uint32 *)
00486 ((char *) data + W (domain->must_swap, data->hash_tab_offset));
00487 break;
00488 default:
00489
00490 #ifdef HAVE_MMAP
00491 if (use_mmap)
00492 munmap ((caddr_t) data, size);
00493 else
00494 #endif
00495 free (data);
00496 free (domain);
00497 domain_file->data = NULL;
00498 return;
00499 }
00500
00501
00502
00503
00504 nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
00505
00506
00507 if (nullentry != NULL)
00508 {
00509 const char *plural;
00510 const char *nplurals;
00511
00512 plural = strstr (nullentry, "plural=");
00513 nplurals = strstr (nullentry, "nplurals=");
00514 if (plural == NULL || nplurals == NULL)
00515 goto no_plural;
00516 else
00517 {
00518
00519 char *endp;
00520 unsigned long int n;
00521 struct parse_args args;
00522
00523 nplurals += 9;
00524 while (*nplurals != '\0' && isspace ((unsigned char)*nplurals))
00525 ++nplurals;
00526 #if defined HAVE_STRTOUL || defined _LIBC
00527 n = strtoul (nplurals, &endp, 10);
00528 #else
00529 for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
00530 n = n * 10 + (*endp - '0');
00531 #endif
00532 domain->nplurals = n;
00533 if (nplurals == endp)
00534 goto no_plural;
00535
00536
00537
00538
00539
00540 plural += 7;
00541 args.cp = plural;
00542 if (PLURAL_PARSE (&args) != 0)
00543 goto no_plural;
00544 domain->plural = args.res;
00545 }
00546 }
00547 else
00548 {
00549
00550
00551
00552 no_plural:
00553 INIT_GERMANIC_PLURAL ();
00554 domain->plural = &germanic_plural;
00555 domain->nplurals = 2;
00556 }
00557 }
00558
00559
00560 #ifdef _LIBC
00561 void
00562 internal_function
00563 _nl_unload_domain (domain)
00564 struct loaded_domain *domain;
00565 {
00566 if (domain->plural != &germanic_plural)
00567 __gettext_free_exp (domain->plural);
00568
00569 _nl_free_domain_conv (domain);
00570
00571 # ifdef _POSIX_MAPPED_FILES
00572 if (domain->use_mmap)
00573 munmap ((caddr_t) domain->data, domain->mmap_size);
00574 else
00575 # endif
00576 free ((void *) domain->data);
00577
00578 free (domain);
00579 }
00580 #endif