tMissing gettext files added - vaccinewars - be a doctor and try to vaccinate t… | |
git clone git://src.adamsgaard.dk/vaccinewars | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 1d4fe829cbae531259381286d3166e18d070d05d | |
parent 0ffd3ec19b9649f16291084b4aaf35072266873d | |
Author: Ben Webb <[email protected]> | |
Date: Sat, 27 Oct 2001 19:25:19 +0000 | |
Missing gettext files added | |
Diffstat: | |
M ABOUT-NLS | 280 +++++++++++++++++++----------… | |
A intl/dcigettext.c | 1257 +++++++++++++++++++++++++++++… | |
A po/ChangeLog | 6 ++++++ | |
3 files changed, 1438 insertions(+), 105 deletions(-) | |
--- | |
diff --git a/ABOUT-NLS b/ABOUT-NLS | |
t@@ -8,7 +8,7 @@ A few packages already provide translations for their messages. | |
If you found this `ABOUT-NLS' file inside a distribution, you may | |
assume that the distributed package does use GNU `gettext' internally, | |
-itself available at your nearest GNU archive site. But you do *not* | |
+itself available at your nearest GNU archive site. But you do _not_ | |
need to install GNU `gettext' prior to configuring, installing or using | |
this package with messages translated. | |
t@@ -22,8 +22,8 @@ related to internationalization, you should tell about the v… | |
`gettext' which is used. The information can be found in the | |
`intl/VERSION' file, in internationalized packages. | |
-One advise in advance | |
-===================== | |
+Quick configuration advice | |
+========================== | |
If you want to exploit the full power of internationalization, you | |
should configure it using | |
t@@ -34,13 +34,14 @@ to force usage of internationalizing routines provided wit… | |
package, despite the existence of internationalizing capabilities in the | |
operating system where this package is being installed. So far, only | |
the `gettext' implementation in the GNU C library version 2 provides as | |
-many features (such as locale alias or message inheritance) as the | |
-implementation here. It is also not possible to offer this additional | |
-functionality on top of a `catgets' implementation. Future versions of | |
-GNU `gettext' will very likely convey even more functionality. So it | |
-might be a good idea to change to GNU `gettext' as soon as possible. | |
- | |
- So you need not provide this option if you are using GNU libc 2 or | |
+many features (such as locale alias, message inheritance, automatic | |
+charset conversion or plural form handling) as the implementation here. | |
+It is also not possible to offer this additional functionality on top | |
+of a `catgets' implementation. Future versions of GNU `gettext' will | |
+very likely convey even more functionality. So it might be a good idea | |
+to change to GNU `gettext' as soon as possible. | |
+ | |
+ So you need _not_ provide this option if you are using GNU libc 2 or | |
you have installed a recent copy of the GNU gettext package with the | |
included `libintl'. | |
t@@ -53,23 +54,20 @@ Most such packages use GNU `gettext'. Other packages have… | |
ways to internationalization, predating GNU `gettext'. | |
By default, this package will be installed to allow translation of | |
-messages. It will automatically detect whether the system provides | |
-usable `catgets' (if using this is selected by the installer) or | |
-`gettext' functions. If neither is available, the GNU `gettext' own | |
+messages. It will automatically detect whether the system already | |
+provides the GNU `gettext' functions. If not, the GNU `gettext' own | |
library will be used. This library is wholly contained within this | |
package, usually in the `intl/' subdirectory, so prior installation of | |
-the GNU `gettext' package is *not* required. Installers may use | |
+the GNU `gettext' package is _not_ required. Installers may use | |
special options at configuration time for changing the default | |
behaviour. The commands: | |
./configure --with-included-gettext | |
- ./configure --with-catgets | |
./configure --disable-nls | |
-will respectively bypass any pre-existing `catgets' or `gettext' to use | |
-the internationalizing routines provided within this package, enable | |
-the use of the `catgets' functions (if found on the locale system), or | |
-else, *totally* disable translation of messages. | |
+will respectively bypass any pre-existing `gettext' to use the | |
+internationalizing routines provided within this package, or else, | |
+_totally_ disable translation of messages. | |
When you already have GNU `gettext' installed on your system and run | |
configure without an option for your new package, `configure' will | |
t@@ -83,18 +81,10 @@ package is more recent, you should use | |
to prevent auto-detection. | |
- By default the configuration process will not test for the `catgets' | |
-function and therefore they will not be used. The reasons are already | |
-given above: the emulation on top of `catgets' cannot provide all the | |
-extensions provided by the GNU `gettext' library. If you nevertheless | |
-want to use the `catgets' functions use | |
- | |
- ./configure --with-catgets | |
- | |
-to enable the test for `catgets' (this causes no harm if `catgets' is | |
-not available on your system). If you really select this option we | |
-would like to hear about the reasons because we cannot think of any | |
-good one ourself. | |
+ The configuration process will not test for the `catgets' function | |
+and therefore it will not be used. The reason is that even an | |
+emulation of `gettext' on top of `catgets' could not provide all the | |
+extensions of the GNU `gettext' library. | |
Internationalized packages have usually many `po/LL.po' files, where | |
LL gives an ISO 639 two-letter code identifying the language. Unless | |
t@@ -110,22 +100,35 @@ Using This Package | |
As a user, if your language has been installed for this package, you | |
only have to set the `LANG' environment variable to the appropriate | |
-ISO 639 `LL' two-letter code prior to using the programs in the | |
-package. For example, let's suppose that you speak German. At the | |
-shell prompt, merely execute `setenv LANG de' (in `csh'), | |
-`export LANG; LANG=de' (in `sh') or `export LANG=de' (in `bash'). This | |
-can be done from your `.login' or `.profile' file, once and for all. | |
- | |
- An operating system might already offer message localization for | |
-many of its programs, while other programs have been installed locally | |
-with the full capabilities of GNU `gettext'. Just using `gettext' | |
-extended syntax for `LANG' would break proper localization of already | |
-available operating system programs. In this case, users should set | |
-both `LANGUAGE' and `LANG' variables in their environment, as programs | |
-using GNU `gettext' give preference to `LANGUAGE'. For example, some | |
-Swedish users would rather read translations in German than English for | |
-when Swedish is not available. This is easily accomplished by setting | |
-`LANGUAGE' to `sv:de' while leaving `LANG' to `sv'. | |
+`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, | |
+and `CC' is an ISO 3166 two-letter country code. For example, let's | |
+suppose that you speak German and live in Germany. At the shell | |
+prompt, merely execute `setenv LANG de_DE' (in `csh'), | |
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). | |
+This can be done from your `.login' or `.profile' file, once and for | |
+all. | |
+ | |
+ You might think that the country code specification is redundant. | |
+But in fact, some languages have dialects in different countries. For | |
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The | |
+country code serves to distinguish the dialects. | |
+ | |
+ Not all programs have translations for all languages. By default, an | |
+English message is shown in place of a nonexistent translation. If you | |
+understand other languages, you can set up a priority list of languages. | |
+This is done through a different environment variable, called | |
+`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' | |
+for the purpose of message handling, but you still need to have `LANG' | |
+set to the primary language; this is required by other parts of the | |
+system libraries. For example, some Swedish users who would rather | |
+read translations in German than English for when Swedish is not | |
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. | |
+ | |
+ In the `LANGUAGE' environment variable, but not in the `LANG' | |
+environment variable, `LL_CC' combinations can be abbreviated as `LL' | |
+to denote the language's main dialect. For example, `de' is equivalent | |
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' | |
+(Portuguese as spoken in Portugal) in this context. | |
Translating Teams | |
================= | |
t@@ -133,33 +136,21 @@ Translating Teams | |
For the Free Translation Project to be a success, we need interested | |
people who like their own language and write it well, and who are also | |
able to synergize with other translators speaking the same language. | |
-Each translation team has its own mailing list, courtesy of Linux | |
-International. You may reach your translation team at the address | |
-`[email protected]', replacing LL by the two-letter ISO 639 code for your | |
-language. Language codes are *not* the same as the country codes given | |
-in ISO 3166. The following translation teams exist, as of December | |
-1997: | |
- | |
- Chinese `zh', Czech `cs', Danish `da', Dutch `nl', English `en', | |
- Esperanto `eo', Finnish `fi', French `fr', German `de', Hungarian | |
- `hu', Irish `ga', Italian `it', Indonesian `id', Japanese `ja', | |
- Korean `ko', Latin `la', Norwegian `no', Persian `fa', Polish | |
- `pl', Portuguese `pt', Russian `ru', Slovenian `sl', Spanish `es', | |
- Swedish `sv', and Turkish `tr'. | |
- | |
-For example, you may reach the Chinese translation team by writing to | |
-`[email protected]'. | |
- | |
- If you'd like to volunteer to *work* at translating messages, you | |
+Each translation team has its own mailing list. The up-to-date list of | |
+teams can be found at the Free Translation Project's homepage, | |
+`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" | |
+area. | |
+ | |
+ If you'd like to volunteer to _work_ at translating messages, you | |
should become a member of the translating team for your own language. | |
-The subscribing address is *not* the same as the list itself, it has | |
+The subscribing address is _not_ the same as the list itself, it has | |
`-request' appended. For example, speakers of Swedish can send a | |
message to `[email protected]', having this message body: | |
subscribe | |
Keep in mind that team members are expected to participate | |
-*actively* in translations, or at solving translational difficulties, | |
+_actively_ in translations, or at solving translational difficulties, | |
rather than merely lurking around. If your team does not exist yet and | |
you want to start one, or if you are unsure about what to do or how to | |
get started, please write to `[email protected]' to reach the | |
t@@ -173,42 +164,102 @@ Available Packages | |
================== | |
Languages are not equally supported in all packages. The following | |
-matrix shows the current state of internationalization, as of December | |
-1997. The matrix shows, in regard of each package, for which languages | |
-PO files have been submitted to translation coordination. | |
- | |
- Ready PO files cs da de en es fi fr it ja ko nl no pl pt ru sl sv | |
- .----------------------------------------------------. | |
- bash | [] [] [] | 3 | |
- bison | [] [] [] | 3 | |
- clisp | [] [] [] [] | 4 | |
- cpio | [] [] [] [] [] [] | 6 | |
- diffutils | [] [] [] [] [] | 5 | |
- enscript | [] [] [] [] [] [] | 6 | |
- fileutils | [] [] [] [] [] [] [] [] [] [] | 10 | |
- findutils | [] [] [] [] [] [] [] [] [] | 9 | |
- flex | [] [] [] [] | 4 | |
- gcal | [] [] [] [] [] | 5 | |
- gettext | [] [] [] [] [] [] [] [] [] [] [] | 12 | |
- grep | [] [] [] [] [] [] [] [] [] [] | 10 | |
- hello | [] [] [] [] [] [] [] [] [] [] [] | 11 | |
- id-utils | [] [] [] | 3 | |
- indent | [] [] [] [] [] | 5 | |
- libc | [] [] [] [] [] [] [] | 7 | |
- m4 | [] [] [] [] [] [] | 6 | |
- make | [] [] [] [] [] [] | 6 | |
- music | [] [] | 2 | |
- ptx | [] [] [] [] [] [] [] [] | 8 | |
- recode | [] [] [] [] [] [] [] [] [] | 9 | |
- sh-utils | [] [] [] [] [] [] [] [] | 8 | |
- sharutils | [] [] [] [] [] [] | 6 | |
- tar | [] [] [] [] [] [] [] [] [] [] [] | 11 | |
- texinfo | [] [] [] | 3 | |
- textutils | [] [] [] [] [] [] [] [] [] | 9 | |
- wdiff | [] [] [] [] [] [] [] [] | 8 | |
- `----------------------------------------------------' | |
- 17 languages cs da de en es fi fr it ja ko nl no pl pt ru sl sv | |
- 27 packages 6 4 25 1 18 1 26 2 1 12 20 9 19 7 4 7 17 179 | |
+matrix shows the current state of internationalization, as of May 2001. | |
+The matrix shows, in regard of each package, for which languages PO | |
+files have been submitted to translation coordination, with a | |
+translation percentage of at least 50%. | |
+ | |
+ Ready PO files bg cs da de el en eo es et fi fr gl hr id it | |
+ +----------------------------------------------+ | |
+ a2ps | [] [] | | |
+ bash | [] [] [] [] | | |
+ bison | [] [] [] [] | | |
+ clisp | [] [] [] [] | | |
+ cpio | [] [] [] [] | | |
+ diffutils | [] [] [] [] [] [] [] | | |
+ enscript | [] [] | | |
+ error | [] | | |
+ fileutils | [] [] [] [] [] [] [] | | |
+ findutils | [] [] [] [] [] [] [] [] | | |
+ flex | [] [] [] | | |
+ gawk | | | |
+ gcal | | | |
+ gcc | [] | | |
+ gettext | [] [] [] [] [] [] [] [] [] | | |
+ gnupg | [] [] [] [] [] | | |
+ grep | [] [] [] | | |
+ hello | [] [] [] [] [] [] [] [] [] | | |
+ id-utils | [] [] | | |
+ indent | [] [] [] [] [] | | |
+ libc | [] [] [] [] [] [] [] [] | | |
+ lilypond | | | |
+ lynx | [] [] [] | | |
+ m4 | [] [] [] [] [] [] [] | | |
+ make | [] [] [] [] | | |
+ parted | [] [] | | |
+ ptx | [] [] [] [] [] [] [] | | |
+ python | | | |
+ recode | [] [] [] [] [] [] [] [] | | |
+ sed | [] [] [] [] [] [] [] [] [] | | |
+ sh-utils | [] [] [] [] [] [] [] [] [] | | |
+ sharutils | [] [] [] [] [] [] [] | | |
+ soundtracker | | | |
+ sp | | | |
+ tar | [] [] [] [] [] [] [] [] | | |
+ texinfo | [] [] [] [] | | |
+ textutils | [] [] [] [] [] [] [] | | |
+ util-linux | [] | | |
+ wdiff | [] [] [] [] [] [] [] | | |
+ wget | [] [] [] [] [] [] [] [] [] | | |
+ +----------------------------------------------+ | |
+ bg cs da de el en eo es et fi fr gl hr id it | |
+ 0 14 21 27 10 1 8 20 13 1 28 17 0 9 11 | |
+ | |
+ ja ko lv nl no pl pt pt_BR ru sk sl sv tr zh | |
+ +----------------------------------------------+ | |
+ a2ps | [] [] [] | 5 | |
+ bash | | 4 | |
+ bison | [] [] [] | 7 | |
+ clisp | [] | 5 | |
+ cpio | [] [] [] [] [] | 9 | |
+ diffutils | [] [] [] | 10 | |
+ enscript | [] [] [] | 5 | |
+ error | | 1 | |
+ fileutils | [] [] [] [] [] [] [] [] [] | 16 | |
+ findutils | [] [] [] [] [] [] | 14 | |
+ flex | [] [] [] | 6 | |
+ gawk | | 0 | |
+ gcal | | 0 | |
+ gcc | [] | 2 | |
+ gettext | [] [] [] [] [] [] [] [] [] [] | 19 | |
+ gnupg | [] [] [] | 8 | |
+ grep | | 3 | |
+ hello | [] [] [] [] [] [] [] [] | 17 | |
+ id-utils | [] [] [] | 5 | |
+ indent | [] [] [] [] [] [] [] | 12 | |
+ libc | [] [] [] [] [] [] [] | 15 | |
+ lilypond | [] | 1 | |
+ lynx | [] [] [] [] [] | 8 | |
+ m4 | [] [] [] [] [] | 12 | |
+ make | [] [] [] [] [] | 9 | |
+ parted | [] [] [] | 5 | |
+ ptx | [] [] [] [] [] [] | 13 | |
+ python | | 0 | |
+ recode | [] [] [] | 11 | |
+ sed | [] [] [] [] [] [] [] | 16 | |
+ sh-utils | [] [] [] [] [] [] [] [] [] [] | 19 | |
+ sharutils | [] [] [] [] | 11 | |
+ soundtracker | | 0 | |
+ sp | | 0 | |
+ tar | [] [] [] [] [] [] [] [] | 16 | |
+ texinfo | [] [] | 6 | |
+ textutils | [] [] [] [] [] [] [] [] | 15 | |
+ util-linux | [] | 2 | |
+ wdiff | [] [] [] [] [] | 12 | |
+ wget | [] [] [] [] [] [] [] [] | 17 | |
+ +----------------------------------------------+ | |
+ 29 teams ja ko lv nl no pl pt pt_BR ru sk sl sv tr zh | |
+ 40 domains 18 8 0 23 6 16 1 15 26 9 9 20 2 3 336 | |
Some counters in the preceding matrix are higher than the number of | |
visible blocks let us expect. This is because a few extra PO files are | |
t@@ -221,6 +272,25 @@ distributed as such by its maintainer. There might be an… | |
lag between the mere existence a PO file and its wide availability in a | |
distribution. | |
- If December 1997 seems to be old, you may fetch a more recent copy | |
-of this `ABOUT-NLS' file on most GNU archive sites. | |
+ If May 2001 seems to be old, you may fetch a more recent copy of | |
+this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date | |
+matrix with full percentage details can be found at | |
+`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. | |
+ | |
+Using `gettext' in new packages | |
+=============================== | |
+ | |
+ If you are writing a freely available program and want to | |
+internationalize it you are welcome to use GNU `gettext' in your | |
+package. Of course the GNU Public License applies to your sources from | |
+then if you include `gettext' directly in your distribution on but | |
+since you are writing free software anyway this is no restriction. | |
+ | |
+ Once the sources are change appropriately and the setup can handle to | |
+use of `gettext' the only thing missing are the translations. The Free | |
+Translation Project is also available for packages which are not | |
+developed inside the GNU project. Therefore the information given above | |
+applies also for every other Free Software Project. Contact | |
+`[email protected]' to make the `.pot' files available to | |
+the translation teams. | |
diff --git a/intl/dcigettext.c b/intl/dcigettext.c | |
t@@ -0,0 +1,1257 @@ | |
+/* Implementation of the internal dcigettext function. | |
+ Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. | |
+ | |
+ This program is free software; you can redistribute it and/or modify | |
+ it under the terms of the GNU General Public License as published by | |
+ the Free Software Foundation; either version 2, or (at your option) | |
+ any later version. | |
+ | |
+ This program is distributed in the hope that it will be useful, | |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ GNU General Public License for more details. | |
+ | |
+ You should have received a copy of the GNU General Public License | |
+ along with this program; if not, write to the Free Software Foundation, | |
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
+ | |
+/* Tell glibc's <string.h> to provide a prototype for mempcpy(). | |
+ This must come before <config.h> because <config.h> may include | |
+ <features.h>, and once <features.h> has been included, it's too late. */ | |
+#ifndef _GNU_SOURCE | |
+# define _GNU_SOURCE 1 | |
+#endif | |
+ | |
+#ifdef HAVE_CONFIG_H | |
+# include <config.h> | |
+#endif | |
+ | |
+#include <sys/types.h> | |
+ | |
+#ifdef __GNUC__ | |
+# define alloca __builtin_alloca | |
+# define HAVE_ALLOCA 1 | |
+#else | |
+# if defined HAVE_ALLOCA_H || defined _LIBC | |
+# include <alloca.h> | |
+# else | |
+# ifdef _AIX | |
+ #pragma alloca | |
+# else | |
+# ifndef alloca | |
+char *alloca (); | |
+# endif | |
+# endif | |
+# endif | |
+#endif | |
+ | |
+#include <errno.h> | |
+#ifndef errno | |
+extern int errno; | |
+#endif | |
+#ifndef __set_errno | |
+# define __set_errno(val) errno = (val) | |
+#endif | |
+ | |
+#include <stddef.h> | |
+#include <stdlib.h> | |
+ | |
+#include <string.h> | |
+#if !HAVE_STRCHR && !defined _LIBC | |
+# ifndef strchr | |
+# define strchr index | |
+# endif | |
+#endif | |
+ | |
+#if defined HAVE_UNISTD_H || defined _LIBC | |
+# include <unistd.h> | |
+#endif | |
+ | |
+#include <locale.h> | |
+ | |
+#if defined HAVE_SYS_PARAM_H || defined _LIBC | |
+# include <sys/param.h> | |
+#endif | |
+ | |
+#include "gettextP.h" | |
+#ifdef _LIBC | |
+# include <libintl.h> | |
+#else | |
+# include "libgnuintl.h" | |
+#endif | |
+#include "hash-string.h" | |
+ | |
+/* Thread safetyness. */ | |
+#ifdef _LIBC | |
+# include <bits/libc-lock.h> | |
+#else | |
+/* Provide dummy implementation if this is outside glibc. */ | |
+# define __libc_lock_define_initialized(CLASS, NAME) | |
+# define __libc_lock_lock(NAME) | |
+# define __libc_lock_unlock(NAME) | |
+# define __libc_rwlock_define_initialized(CLASS, NAME) | |
+# define __libc_rwlock_rdlock(NAME) | |
+# define __libc_rwlock_unlock(NAME) | |
+#endif | |
+ | |
+/* Alignment of types. */ | |
+#if defined __GNUC__ && __GNUC__ >= 2 | |
+# define alignof(TYPE) __alignof__ (TYPE) | |
+#else | |
+# define alignof(TYPE) \ | |
+ ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2) | |
+#endif | |
+ | |
+/* The internal variables in the standalone libintl.a must have different | |
+ names than the internal variables in GNU libc, otherwise programs | |
+ using libintl.a cannot be linked statically. */ | |
+#if !defined _LIBC | |
+# define _nl_default_default_domain _nl_default_default_domain__ | |
+# define _nl_current_default_domain _nl_current_default_domain__ | |
+# define _nl_default_dirname _nl_default_dirname__ | |
+# define _nl_domain_bindings _nl_domain_bindings__ | |
+#endif | |
+ | |
+/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */ | |
+#ifndef offsetof | |
+# define offsetof(type,ident) ((size_t)&(((type*)0)->ident)) | |
+#endif | |
+ | |
+/* @@ end of prolog @@ */ | |
+ | |
+#ifdef _LIBC | |
+/* Rename the non ANSI C functions. This is required by the standard | |
+ because some ANSI C functions will require linking with this object | |
+ file and the name space must not be polluted. */ | |
+# define getcwd __getcwd | |
+# ifndef stpcpy | |
+# define stpcpy __stpcpy | |
+# endif | |
+# define tfind __tfind | |
+#else | |
+# if !defined HAVE_GETCWD | |
+char *getwd (); | |
+# define getcwd(buf, max) getwd (buf) | |
+# else | |
+char *getcwd (); | |
+# endif | |
+# ifndef HAVE_STPCPY | |
+static char *stpcpy PARAMS ((char *dest, const char *src)); | |
+# endif | |
+# ifndef HAVE_MEMPCPY | |
+static void *mempcpy PARAMS ((void *dest, const void *src, size_t n)); | |
+# endif | |
+#endif | |
+ | |
+/* Amount to increase buffer size by in each try. */ | |
+#define PATH_INCR 32 | |
+ | |
+/* The following is from pathmax.h. */ | |
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define | |
+ PATH_MAX but might cause redefinition warnings when sys/param.h is | |
+ later included (as on MORE/BSD 4.3). */ | |
+#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__) | |
+# include <limits.h> | |
+#endif | |
+ | |
+#ifndef _POSIX_PATH_MAX | |
+# define _POSIX_PATH_MAX 255 | |
+#endif | |
+ | |
+#if !defined PATH_MAX && defined _PC_PATH_MAX | |
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _P… | |
+#endif | |
+ | |
+/* Don't include sys/param.h if it already has been. */ | |
+#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN | |
+# include <sys/param.h> | |
+#endif | |
+ | |
+#if !defined PATH_MAX && defined MAXPATHLEN | |
+# define PATH_MAX MAXPATHLEN | |
+#endif | |
+ | |
+#ifndef PATH_MAX | |
+# define PATH_MAX _POSIX_PATH_MAX | |
+#endif | |
+ | |
+/* Pathname support. | |
+ ISSLASH(C) tests whether C is a directory separator character. | |
+ IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, | |
+ it may be concatenated to a directory pathname. | |
+ IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. | |
+ */ | |
+#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ | |
+ /* Win32, OS/2, DOS */ | |
+# define ISSLASH(C) ((C) == '/' || (C) == '\\') | |
+# define HAS_DEVICE(P) \ | |
+ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ | |
+ && (P)[1] == ':') | |
+# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) | |
+# define IS_PATH_WITH_DIR(P) \ | |
+ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) | |
+#else | |
+ /* Unix */ | |
+# define ISSLASH(C) ((C) == '/') | |
+# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) | |
+# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) | |
+#endif | |
+ | |
+/* XPG3 defines the result of `setlocale (category, NULL)' as: | |
+ ``Directs `setlocale()' to query `category' and return the current | |
+ setting of `local'.'' | |
+ However it does not specify the exact format. Neither do SUSV2 and | |
+ ISO C 99. So we can use this feature only on selected systems (e.g. | |
+ those using GNU C Library). */ | |
+#if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2) | |
+# define HAVE_LOCALE_NULL | |
+#endif | |
+ | |
+/* This is the type used for the search tree where known translations | |
+ are stored. */ | |
+struct known_translation_t | |
+{ | |
+ /* Domain in which to search. */ | |
+ char *domainname; | |
+ | |
+ /* The category. */ | |
+ int category; | |
+ | |
+ /* State of the catalog counter at the point the string was found. */ | |
+ int counter; | |
+ | |
+ /* Catalog where the string was found. */ | |
+ struct loaded_l10nfile *domain; | |
+ | |
+ /* And finally the translation. */ | |
+ const char *translation; | |
+ size_t translation_length; | |
+ | |
+ /* Pointer to the string in question. */ | |
+ char msgid[ZERO]; | |
+}; | |
+ | |
+/* Root of the search tree with known translations. We can use this | |
+ only if the system provides the `tsearch' function family. */ | |
+#if defined HAVE_TSEARCH || defined _LIBC | |
+# include <search.h> | |
+ | |
+static void *root; | |
+ | |
+# ifdef _LIBC | |
+# define tsearch __tsearch | |
+# endif | |
+ | |
+/* Function to compare two entries in the table of known translations. */ | |
+static int transcmp PARAMS ((const void *p1, const void *p2)); | |
+static int | |
+transcmp (p1, p2) | |
+ const void *p1; | |
+ const void *p2; | |
+{ | |
+ const struct known_translation_t *s1; | |
+ const struct known_translation_t *s2; | |
+ int result; | |
+ | |
+ s1 = (const struct known_translation_t *) p1; | |
+ s2 = (const struct known_translation_t *) p2; | |
+ | |
+ result = strcmp (s1->msgid, s2->msgid); | |
+ if (result == 0) | |
+ { | |
+ result = strcmp (s1->domainname, s2->domainname); | |
+ if (result == 0) | |
+ /* We compare the category last (though this is the cheapest | |
+ operation) since it is hopefully always the same (namely | |
+ LC_MESSAGES). */ | |
+ result = s1->category - s2->category; | |
+ } | |
+ | |
+ return result; | |
+} | |
+#endif | |
+ | |
+/* Name of the default domain used for gettext(3) prior any call to | |
+ textdomain(3). The default value for this is "messages". */ | |
+const char _nl_default_default_domain[] = "messages"; | |
+ | |
+/* Value used as the default domain for gettext(3). */ | |
+const char *_nl_current_default_domain = _nl_default_default_domain; | |
+ | |
+/* Contains the default location of the message catalogs. */ | |
+const char _nl_default_dirname[] = LOCALEDIR; | |
+ | |
+/* List with bindings of specific domains created by bindtextdomain() | |
+ calls. */ | |
+struct binding *_nl_domain_bindings; | |
+ | |
+/* Prototypes for local functions. */ | |
+static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain, | |
+ unsigned long int n, | |
+ const char *translation, | |
+ size_t translation_len)) | |
+ internal_function; | |
+static unsigned long int plural_eval PARAMS ((struct expression *pexp, | |
+ unsigned long int n)) | |
+ internal_function; | |
+static const char *category_to_name PARAMS ((int category)) internal_function; | |
+static const char *guess_category_value PARAMS ((int category, | |
+ const char *categoryname)) | |
+ internal_function; | |
+ | |
+ | |
+/* For those loosing systems which don't have `alloca' we have to add | |
+ some additional code emulating it. */ | |
+#ifdef HAVE_ALLOCA | |
+/* Nothing has to be done. */ | |
+# define ADD_BLOCK(list, address) /* nothing */ | |
+# define FREE_BLOCKS(list) /* nothing */ | |
+#else | |
+struct block_list | |
+{ | |
+ void *address; | |
+ struct block_list *next; | |
+}; | |
+# define ADD_BLOCK(list, addr) … | |
+ do { … | |
+ struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \ | |
+ /* If we cannot get a free block we cannot add the new element to … | |
+ the list. */ … | |
+ if (newp != NULL) { … | |
+ newp->address = (addr); … | |
+ newp->next = (list); … | |
+ (list) = newp; … | |
+ } … | |
+ } while (0) | |
+# define FREE_BLOCKS(list) … | |
+ do { … | |
+ while (list != NULL) { … | |
+ struct block_list *old = list; … | |
+ list = list->next; \ | |
+ free (old); … | |
+ } … | |
+ } while (0) | |
+# undef alloca | |
+# define alloca(size) (malloc (size)) | |
+#endif /* have alloca */ | |
+ | |
+ | |
+#ifdef _LIBC | |
+/* List of blocks allocated for translations. */ | |
+typedef struct transmem_list | |
+{ | |
+ struct transmem_list *next; | |
+ char data[ZERO]; | |
+} transmem_block_t; | |
+static struct transmem_list *transmem_list; | |
+#else | |
+typedef unsigned char transmem_block_t; | |
+#endif | |
+ | |
+ | |
+/* Names for the libintl functions are a problem. They must not clash | |
+ with existing names and they should follow ANSI C. But this source | |
+ code is also used in GNU C Library where the names have a __ | |
+ prefix. So we have to make a difference here. */ | |
+#ifdef _LIBC | |
+# define DCIGETTEXT __dcigettext | |
+#else | |
+# define DCIGETTEXT dcigettext__ | |
+#endif | |
+ | |
+/* Lock variable to protect the global data in the gettext implementation. */ | |
+#ifdef _LIBC | |
+__libc_rwlock_define_initialized (, _nl_state_lock) | |
+#endif | |
+ | |
+/* Checking whether the binaries runs SUID must be done and glibc provides | |
+ easier methods therefore we make a difference here. */ | |
+#ifdef _LIBC | |
+# define ENABLE_SECURE __libc_enable_secure | |
+# define DETERMINE_SECURE | |
+#else | |
+# ifndef HAVE_GETUID | |
+# define getuid() 0 | |
+# endif | |
+# ifndef HAVE_GETGID | |
+# define getgid() 0 | |
+# endif | |
+# ifndef HAVE_GETEUID | |
+# define geteuid() getuid() | |
+# endif | |
+# ifndef HAVE_GETEGID | |
+# define getegid() getgid() | |
+# endif | |
+static int enable_secure; | |
+# define ENABLE_SECURE (enable_secure == 1) | |
+# define DETERMINE_SECURE \ | |
+ if (enable_secure == 0) … | |
+ { … | |
+ if (getuid () != geteuid () || getgid () != getegid ()) … | |
+ enable_secure = 1; … | |
+ else … | |
+ enable_secure = -1; … | |
+ } | |
+#endif | |
+ | |
+/* Look up MSGID in the DOMAINNAME message catalog for the current | |
+ CATEGORY locale and, if PLURAL is nonzero, search over string | |
+ depending on the plural form determined by N. */ | |
+char * | |
+DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) | |
+ const char *domainname; | |
+ const char *msgid1; | |
+ const char *msgid2; | |
+ int plural; | |
+ unsigned long int n; | |
+ int category; | |
+{ | |
+#ifndef HAVE_ALLOCA | |
+ struct block_list *block_list = NULL; | |
+#endif | |
+ struct loaded_l10nfile *domain; | |
+ struct binding *binding; | |
+ const char *categoryname; | |
+ const char *categoryvalue; | |
+ char *dirname, *xdomainname; | |
+ char *single_locale; | |
+ char *retval; | |
+ size_t retlen; | |
+ int saved_errno; | |
+#if defined HAVE_TSEARCH || defined _LIBC | |
+ struct known_translation_t *search; | |
+ struct known_translation_t **foundp = NULL; | |
+ size_t msgid_len; | |
+#endif | |
+ size_t domainname_len; | |
+ | |
+ /* If no real MSGID is given return NULL. */ | |
+ if (msgid1 == NULL) | |
+ return NULL; | |
+ | |
+ __libc_rwlock_rdlock (_nl_state_lock); | |
+ | |
+ /* If DOMAINNAME is NULL, we are interested in the default domain. If | |
+ CATEGORY is not LC_MESSAGES this might not make much sense but the | |
+ definition left this undefined. */ | |
+ if (domainname == NULL) | |
+ domainname = _nl_current_default_domain; | |
+ | |
+#if defined HAVE_TSEARCH || defined _LIBC | |
+ msgid_len = strlen (msgid1) + 1; | |
+ | |
+ /* Try to find the translation among those which we found at | |
+ some time. */ | |
+ search = (struct known_translation_t *) | |
+ alloca (offsetof (struct known_translation_t, msgid) + msgid_len); | |
+ memcpy (search->msgid, msgid1, msgid_len); | |
+ search->domainname = (char *) domainname; | |
+ search->category = category; | |
+ | |
+ foundp = (struct known_translation_t **) tfind (search, &root, transcmp); | |
+ if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) | |
+ { | |
+ /* Now deal with plural. */ | |
+ if (plural) | |
+ retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation, | |
+ (*foundp)->translation_length); | |
+ else | |
+ retval = (char *) (*foundp)->translation; | |
+ | |
+ __libc_rwlock_unlock (_nl_state_lock); | |
+ return retval; | |
+ } | |
+#endif | |
+ | |
+ /* Preserve the `errno' value. */ | |
+ saved_errno = errno; | |
+ | |
+ /* See whether this is a SUID binary or not. */ | |
+ DETERMINE_SECURE; | |
+ | |
+ /* First find matching binding. */ | |
+ for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next) | |
+ { | |
+ int compare = strcmp (domainname, binding->domainname); | |
+ if (compare == 0) | |
+ /* We found it! */ | |
+ break; | |
+ if (compare < 0) | |
+ { | |
+ /* It is not in the list. */ | |
+ binding = NULL; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (binding == NULL) | |
+ dirname = (char *) _nl_default_dirname; | |
+ else if (IS_ABSOLUTE_PATH (binding->dirname)) | |
+ dirname = binding->dirname; | |
+ else | |
+ { | |
+ /* We have a relative path. Make it absolute now. */ | |
+ size_t dirname_len = strlen (binding->dirname) + 1; | |
+ size_t path_max; | |
+ char *ret; | |
+ | |
+ path_max = (unsigned int) PATH_MAX; | |
+ path_max += 2; /* The getcwd docs say to do this. */ | |
+ | |
+ for (;;) | |
+ { | |
+ dirname = (char *) alloca (path_max + dirname_len); | |
+ ADD_BLOCK (block_list, dirname); | |
+ | |
+ __set_errno (0); | |
+ ret = getcwd (dirname, path_max); | |
+ if (ret != NULL || errno != ERANGE) | |
+ break; | |
+ | |
+ path_max += path_max / 2; | |
+ path_max += PATH_INCR; | |
+ } | |
+ | |
+ if (ret == NULL) | |
+ { | |
+ /* We cannot get the current working directory. Don't signal an | |
+ error but simply return the default string. */ | |
+ FREE_BLOCKS (block_list); | |
+ __set_errno (saved_errno); | |
+ return (plural == 0 | |
+ ? (char *) msgid1 | |
+ /* Use the Germanic plural rule. */ | |
+ : n == 1 ? (char *) msgid1 : (char *) msgid2); | |
+ } | |
+ | |
+ stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname); | |
+ } | |
+ | |
+ /* Now determine the symbolic name of CATEGORY and its value. */ | |
+ categoryname = category_to_name (category); | |
+ categoryvalue = guess_category_value (category, categoryname); | |
+ | |
+ domainname_len = strlen (domainname); | |
+ xdomainname = (char *) alloca (strlen (categoryname) | |
+ + domainname_len + 5); | |
+ ADD_BLOCK (block_list, xdomainname); | |
+ | |
+ stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"), | |
+ domainname, domainname_len), | |
+ ".mo"); | |
+ | |
+ /* Creating working area. */ | |
+ single_locale = (char *) alloca (strlen (categoryvalue) + 1); | |
+ ADD_BLOCK (block_list, single_locale); | |
+ | |
+ | |
+ /* Search for the given string. This is a loop because we perhaps | |
+ got an ordered list of languages to consider for the translation. */ | |
+ while (1) | |
+ { | |
+ /* Make CATEGORYVALUE point to the next element of the list. */ | |
+ while (categoryvalue[0] != '\0' && categoryvalue[0] == ':') | |
+ ++categoryvalue; | |
+ if (categoryvalue[0] == '\0') | |
+ { | |
+ /* The whole contents of CATEGORYVALUE has been searched but | |
+ no valid entry has been found. We solve this situation | |
+ by implicitly appending a "C" entry, i.e. no translation | |
+ will take place. */ | |
+ single_locale[0] = 'C'; | |
+ single_locale[1] = '\0'; | |
+ } | |
+ else | |
+ { | |
+ char *cp = single_locale; | |
+ while (categoryvalue[0] != '\0' && categoryvalue[0] != ':') | |
+ *cp++ = *categoryvalue++; | |
+ *cp = '\0'; | |
+ | |
+ /* When this is a SUID binary we must not allow accessing files | |
+ outside the dedicated directories. */ | |
+ if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale)) | |
+ /* Ingore this entry. */ | |
+ continue; | |
+ } | |
+ | |
+ /* If the current locale value is C (or POSIX) we don't load a | |
+ domain. Return the MSGID. */ | |
+ if (strcmp (single_locale, "C") == 0 | |
+ || strcmp (single_locale, "POSIX") == 0) | |
+ { | |
+ FREE_BLOCKS (block_list); | |
+ __libc_rwlock_unlock (_nl_state_lock); | |
+ __set_errno (saved_errno); | |
+ return (plural == 0 | |
+ ? (char *) msgid1 | |
+ /* Use the Germanic plural rule. */ | |
+ : n == 1 ? (char *) msgid1 : (char *) msgid2); | |
+ } | |
+ | |
+ | |
+ /* Find structure describing the message catalog matching the | |
+ DOMAINNAME and CATEGORY. */ | |
+ domain = _nl_find_domain (dirname, single_locale, xdomainname, binding); | |
+ | |
+ if (domain != NULL) | |
+ { | |
+ retval = _nl_find_msg (domain, binding, msgid1, &retlen); | |
+ | |
+ if (retval == NULL) | |
+ { | |
+ int cnt; | |
+ | |
+ for (cnt = 0; domain->successor[cnt] != NULL; ++cnt) | |
+ { | |
+ retval = _nl_find_msg (domain->successor[cnt], binding, | |
+ msgid1, &retlen); | |
+ | |
+ if (retval != NULL) | |
+ { | |
+ domain = domain->successor[cnt]; | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (retval != NULL) | |
+ { | |
+ /* Found the translation of MSGID1 in domain DOMAIN: | |
+ starting at RETVAL, RETLEN bytes. */ | |
+ FREE_BLOCKS (block_list); | |
+ __set_errno (saved_errno); | |
+#if defined HAVE_TSEARCH || defined _LIBC | |
+ if (foundp == NULL) | |
+ { | |
+ /* Create a new entry and add it to the search tree. */ | |
+ struct known_translation_t *newp; | |
+ | |
+ newp = (struct known_translation_t *) | |
+ malloc (offsetof (struct known_translation_t, msgid) | |
+ + msgid_len + domainname_len + 1); | |
+ if (newp != NULL) | |
+ { | |
+ newp->domainname = | |
+ mempcpy (newp->msgid, msgid1, msgid_len); | |
+ memcpy (newp->domainname, domainname, domainname_len + 1… | |
+ newp->category = category; | |
+ newp->counter = _nl_msg_cat_cntr; | |
+ newp->domain = domain; | |
+ newp->translation = retval; | |
+ newp->translation_length = retlen; | |
+ | |
+ /* Insert the entry in the search tree. */ | |
+ foundp = (struct known_translation_t **) | |
+ tsearch (newp, &root, transcmp); | |
+ if (foundp == NULL | |
+ || __builtin_expect (*foundp != newp, 0)) | |
+ /* The insert failed. */ | |
+ free (newp); | |
+ } | |
+ } | |
+ else | |
+ { | |
+ /* We can update the existing entry. */ | |
+ (*foundp)->counter = _nl_msg_cat_cntr; | |
+ (*foundp)->domain = domain; | |
+ (*foundp)->translation = retval; | |
+ (*foundp)->translation_length = retlen; | |
+ } | |
+#endif | |
+ /* Now deal with plural. */ | |
+ if (plural) | |
+ retval = plural_lookup (domain, n, retval, retlen); | |
+ | |
+ __libc_rwlock_unlock (_nl_state_lock); | |
+ return retval; | |
+ } | |
+ } | |
+ } | |
+ /* NOTREACHED */ | |
+} | |
+ | |
+ | |
+char * | |
+internal_function | |
+_nl_find_msg (domain_file, domainbinding, msgid, lengthp) | |
+ struct loaded_l10nfile *domain_file; | |
+ struct binding *domainbinding; | |
+ const char *msgid; | |
+ size_t *lengthp; | |
+{ | |
+ struct loaded_domain *domain; | |
+ size_t act; | |
+ char *result; | |
+ size_t resultlen; | |
+ | |
+ if (domain_file->decided == 0) | |
+ _nl_load_domain (domain_file, domainbinding); | |
+ | |
+ if (domain_file->data == NULL) | |
+ return NULL; | |
+ | |
+ domain = (struct loaded_domain *) domain_file->data; | |
+ | |
+ /* Locate the MSGID and its translation. */ | |
+ if (domain->hash_size > 2 && domain->hash_tab != NULL) | |
+ { | |
+ /* Use the hashing table. */ | |
+ nls_uint32 len = strlen (msgid); | |
+ nls_uint32 hash_val = hash_string (msgid); | |
+ nls_uint32 idx = hash_val % domain->hash_size; | |
+ nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); | |
+ | |
+ while (1) | |
+ { | |
+ nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]); | |
+ | |
+ if (nstr == 0) | |
+ /* Hash table entry is empty. */ | |
+ return NULL; | |
+ | |
+ /* Compare msgid with the original string at index nstr-1. | |
+ We compare the lengths with >=, not ==, because plural entries | |
+ are represented by strings with an embedded NUL. */ | |
+ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len | |
+ && (strcmp (msgid, | |
+ domain->data + W (domain->must_swap, | |
+ domain->orig_tab[nstr - 1].offset)) | |
+ == 0)) | |
+ { | |
+ act = nstr - 1; | |
+ goto found; | |
+ } | |
+ | |
+ if (idx >= domain->hash_size - incr) | |
+ idx -= domain->hash_size - incr; | |
+ else | |
+ idx += incr; | |
+ } | |
+ /* NOTREACHED */ | |
+ } | |
+ else | |
+ { | |
+ /* Try the default method: binary search in the sorted array of | |
+ messages. */ | |
+ size_t top, bottom; | |
+ | |
+ bottom = 0; | |
+ top = domain->nstrings; | |
+ while (bottom < top) | |
+ { | |
+ int cmp_val; | |
+ | |
+ act = (bottom + top) / 2; | |
+ cmp_val = strcmp (msgid, (domain->data | |
+ + W (domain->must_swap, | |
+ domain->orig_tab[act].offset))); | |
+ if (cmp_val < 0) | |
+ top = act; | |
+ else if (cmp_val > 0) | |
+ bottom = act + 1; | |
+ else | |
+ goto found; | |
+ } | |
+ /* No translation was found. */ | |
+ return NULL; | |
+ } | |
+ | |
+ found: | |
+ /* The translation was found at index ACT. If we have to convert the | |
+ string to use a different character set, this is the time. */ | |
+ result = ((char *) domain->data | |
+ + W (domain->must_swap, domain->trans_tab[act].offset)); | |
+ resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1; | |
+ | |
+#if defined _LIBC || HAVE_ICONV | |
+ if (domain->codeset_cntr | |
+ != (domainbinding != NULL ? domainbinding->codeset_cntr : 0)) | |
+ { | |
+ /* The domain's codeset has changed through bind_textdomain_codeset() | |
+ since the message catalog was initialized or last accessed. We | |
+ have to reinitialize the converter. */ | |
+ _nl_free_domain_conv (domain); | |
+ _nl_init_domain_conv (domain_file, domain, domainbinding); | |
+ } | |
+ | |
+ if ( | |
+# ifdef _LIBC | |
+ domain->conv != (__gconv_t) -1 | |
+# else | |
+# if HAVE_ICONV | |
+ domain->conv != (iconv_t) -1 | |
+# endif | |
+# endif | |
+ ) | |
+ { | |
+ /* We are supposed to do a conversion. First allocate an | |
+ appropriate table with the same structure as the table | |
+ of translations in the file, where we can put the pointers | |
+ to the converted strings in. | |
+ There is a slight complication with plural entries. They | |
+ are represented by consecutive NUL terminated strings. We | |
+ handle this case by converting RESULTLEN bytes, including | |
+ NULs. */ | |
+ | |
+ if (domain->conv_tab == NULL | |
+ && ((domain->conv_tab = (char **) calloc (domain->nstrings, | |
+ sizeof (char *))) | |
+ == NULL)) | |
+ /* Mark that we didn't succeed allocating a table. */ | |
+ domain->conv_tab = (char **) -1; | |
+ | |
+ if (__builtin_expect (domain->conv_tab == (char **) -1, 0)) | |
+ /* Nothing we can do, no more memory. */ | |
+ goto converted; | |
+ | |
+ if (domain->conv_tab[act] == NULL) | |
+ { | |
+ /* We haven't used this string so far, so it is not | |
+ translated yet. Do this now. */ | |
+ /* We use a bit more efficient memory handling. | |
+ We allocate always larger blocks which get used over | |
+ time. This is faster than many small allocations. */ | |
+ __libc_lock_define_initialized (static, lock) | |
+# define INITIAL_BLOCK_SIZE 4080 | |
+ static unsigned char *freemem; | |
+ static size_t freemem_size; | |
+ | |
+ const unsigned char *inbuf; | |
+ unsigned char *outbuf; | |
+ int malloc_count; | |
+# ifndef _LIBC | |
+ transmem_block_t *transmem_list = NULL; | |
+# endif | |
+ | |
+ __libc_lock_lock (lock); | |
+ | |
+ inbuf = (const unsigned char *) result; | |
+ outbuf = freemem + sizeof (size_t); | |
+ | |
+ malloc_count = 0; | |
+ while (1) | |
+ { | |
+ transmem_block_t *newmem; | |
+# ifdef _LIBC | |
+ size_t non_reversible; | |
+ int res; | |
+ | |
+ if (freemem_size < sizeof (size_t)) | |
+ goto resize_freemem; | |
+ | |
+ res = __gconv (domain->conv, | |
+ &inbuf, inbuf + resultlen, | |
+ &outbuf, | |
+ outbuf + freemem_size - sizeof (size_t), | |
+ &non_reversible); | |
+ | |
+ if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT) | |
+ break; | |
+ | |
+ if (res != __GCONV_FULL_OUTPUT) | |
+ { | |
+ __libc_lock_unlock (lock); | |
+ goto converted; | |
+ } | |
+ | |
+ inbuf = result; | |
+# else | |
+# if HAVE_ICONV | |
+ const char *inptr = (const char *) inbuf; | |
+ size_t inleft = resultlen; | |
+ char *outptr = (char *) outbuf; | |
+ size_t outleft; | |
+ | |
+ if (freemem_size < sizeof (size_t)) | |
+ goto resize_freemem; | |
+ | |
+ outleft = freemem_size - sizeof (size_t); | |
+ if (iconv (domain->conv, | |
+ (ICONV_CONST char **) &inptr, &inleft, | |
+ &outptr, &outleft) | |
+ != (size_t) (-1)) | |
+ { | |
+ outbuf = (unsigned char *) outptr; | |
+ break; | |
+ } | |
+ if (errno != E2BIG) | |
+ { | |
+ __libc_lock_unlock (lock); | |
+ goto converted; | |
+ } | |
+# endif | |
+# endif | |
+ | |
+ resize_freemem: | |
+ /* We must allocate a new buffer or resize the old one. */ | |
+ if (malloc_count > 0) | |
+ { | |
+ ++malloc_count; | |
+ freemem_size = malloc_count * INITIAL_BLOCK_SIZE; | |
+ newmem = (transmem_block_t *) realloc (transmem_list, | |
+ freemem_size); | |
+# ifdef _LIBC | |
+ if (newmem != NULL) | |
+ transmem_list = transmem_list->next; | |
+ else | |
+ { | |
+ struct transmem_list *old = transmem_list; | |
+ | |
+ transmem_list = transmem_list->next; | |
+ free (old); | |
+ } | |
+# endif | |
+ } | |
+ else | |
+ { | |
+ malloc_count = 1; | |
+ freemem_size = INITIAL_BLOCK_SIZE; | |
+ newmem = (transmem_block_t *) malloc (freemem_size); | |
+ } | |
+ if (__builtin_expect (newmem == NULL, 0)) | |
+ { | |
+ freemem = NULL; | |
+ freemem_size = 0; | |
+ __libc_lock_unlock (lock); | |
+ goto converted; | |
+ } | |
+ | |
+# ifdef _LIBC | |
+ /* Add the block to the list of blocks we have to free | |
+ at some point. */ | |
+ newmem->next = transmem_list; | |
+ transmem_list = newmem; | |
+ | |
+ freemem = newmem->data; | |
+ freemem_size -= offsetof (struct transmem_list, data); | |
+# else | |
+ transmem_list = newmem; | |
+ freemem = newmem; | |
+# endif | |
+ | |
+ outbuf = freemem + sizeof (size_t); | |
+ } | |
+ | |
+ /* We have now in our buffer a converted string. Put this | |
+ into the table of conversions. */ | |
+ *(size_t *) freemem = outbuf - freemem - sizeof (size_t); | |
+ domain->conv_tab[act] = (char *) freemem; | |
+ /* Shrink freemem, but keep it aligned. */ | |
+ freemem_size -= outbuf - freemem; | |
+ freemem = outbuf; | |
+ freemem += freemem_size & (alignof (size_t) - 1); | |
+ freemem_size = freemem_size & ~ (alignof (size_t) - 1); | |
+ | |
+ __libc_lock_unlock (lock); | |
+ } | |
+ | |
+ /* Now domain->conv_tab[act] contains the translation of all | |
+ the plural variants. */ | |
+ result = domain->conv_tab[act] + sizeof (size_t); | |
+ resultlen = *(size_t *) domain->conv_tab[act]; | |
+ } | |
+ | |
+ converted: | |
+ /* The result string is converted. */ | |
+ | |
+#endif /* _LIBC || HAVE_ICONV */ | |
+ | |
+ *lengthp = resultlen; | |
+ return result; | |
+} | |
+ | |
+ | |
+/* Look up a plural variant. */ | |
+static char * | |
+internal_function | |
+plural_lookup (domain, n, translation, translation_len) | |
+ struct loaded_l10nfile *domain; | |
+ unsigned long int n; | |
+ const char *translation; | |
+ size_t translation_len; | |
+{ | |
+ struct loaded_domain *domaindata = (struct loaded_domain *) domain->data; | |
+ unsigned long int index; | |
+ const char *p; | |
+ | |
+ index = plural_eval (domaindata->plural, n); | |
+ if (index >= domaindata->nplurals) | |
+ /* This should never happen. It means the plural expression and the | |
+ given maximum value do not match. */ | |
+ index = 0; | |
+ | |
+ /* Skip INDEX strings at TRANSLATION. */ | |
+ p = translation; | |
+ while (index-- > 0) | |
+ { | |
+#ifdef _LIBC | |
+ p = __rawmemchr (p, '\0'); | |
+#else | |
+ p = strchr (p, '\0'); | |
+#endif | |
+ /* And skip over the NUL byte. */ | |
+ p++; | |
+ | |
+ if (p >= translation + translation_len) | |
+ /* This should never happen. It means the plural expression | |
+ evaluated to a value larger than the number of variants | |
+ available for MSGID1. */ | |
+ return (char *) translation; | |
+ } | |
+ return (char *) p; | |
+} | |
+ | |
+ | |
+/* Function to evaluate the plural expression and return an index value. */ | |
+static unsigned long int | |
+internal_function | |
+plural_eval (pexp, n) | |
+ struct expression *pexp; | |
+ unsigned long int n; | |
+{ | |
+ switch (pexp->nargs) | |
+ { | |
+ case 0: | |
+ switch (pexp->operation) | |
+ { | |
+ case var: | |
+ return n; | |
+ case num: | |
+ return pexp->val.num; | |
+ default: | |
+ break; | |
+ } | |
+ /* NOTREACHED */ | |
+ break; | |
+ case 1: | |
+ { | |
+ /* pexp->operation must be lnot. */ | |
+ unsigned long int arg = plural_eval (pexp->val.args[0], n); | |
+ return ! arg; | |
+ } | |
+ case 2: | |
+ { | |
+ unsigned long int leftarg = plural_eval (pexp->val.args[0], n); | |
+ if (pexp->operation == lor) | |
+ return leftarg || plural_eval (pexp->val.args[1], n); | |
+ else if (pexp->operation == land) | |
+ return leftarg && plural_eval (pexp->val.args[1], n); | |
+ else | |
+ { | |
+ unsigned long int rightarg = plural_eval (pexp->val.args[1], n); | |
+ | |
+ switch (pexp->operation) | |
+ { | |
+ case mult: | |
+ return leftarg * rightarg; | |
+ case divide: | |
+ return leftarg / rightarg; | |
+ case module: | |
+ return leftarg % rightarg; | |
+ case plus: | |
+ return leftarg + rightarg; | |
+ case minus: | |
+ return leftarg - rightarg; | |
+ case less_than: | |
+ return leftarg < rightarg; | |
+ case greater_than: | |
+ return leftarg > rightarg; | |
+ case less_or_equal: | |
+ return leftarg <= rightarg; | |
+ case greater_or_equal: | |
+ return leftarg >= rightarg; | |
+ case equal: | |
+ return leftarg == rightarg; | |
+ case not_equal: | |
+ return leftarg != rightarg; | |
+ default: | |
+ break; | |
+ } | |
+ } | |
+ /* NOTREACHED */ | |
+ break; | |
+ } | |
+ case 3: | |
+ { | |
+ /* pexp->operation must be qmop. */ | |
+ unsigned long int boolarg = plural_eval (pexp->val.args[0], n); | |
+ return plural_eval (pexp->val.args[boolarg ? 1 : 2], n); | |
+ } | |
+ } | |
+ /* NOTREACHED */ | |
+ return 0; | |
+} | |
+ | |
+ | |
+/* Return string representation of locale CATEGORY. */ | |
+static const char * | |
+internal_function | |
+category_to_name (category) | |
+ int category; | |
+{ | |
+ const char *retval; | |
+ | |
+ switch (category) | |
+ { | |
+#ifdef LC_COLLATE | |
+ case LC_COLLATE: | |
+ retval = "LC_COLLATE"; | |
+ break; | |
+#endif | |
+#ifdef LC_CTYPE | |
+ case LC_CTYPE: | |
+ retval = "LC_CTYPE"; | |
+ break; | |
+#endif | |
+#ifdef LC_MONETARY | |
+ case LC_MONETARY: | |
+ retval = "LC_MONETARY"; | |
+ break; | |
+#endif | |
+#ifdef LC_NUMERIC | |
+ case LC_NUMERIC: | |
+ retval = "LC_NUMERIC"; | |
+ break; | |
+#endif | |
+#ifdef LC_TIME | |
+ case LC_TIME: | |
+ retval = "LC_TIME"; | |
+ break; | |
+#endif | |
+#ifdef LC_MESSAGES | |
+ case LC_MESSAGES: | |
+ retval = "LC_MESSAGES"; | |
+ break; | |
+#endif | |
+#ifdef LC_RESPONSE | |
+ case LC_RESPONSE: | |
+ retval = "LC_RESPONSE"; | |
+ break; | |
+#endif | |
+#ifdef LC_ALL | |
+ case LC_ALL: | |
+ /* This might not make sense but is perhaps better than any other | |
+ value. */ | |
+ retval = "LC_ALL"; | |
+ break; | |
+#endif | |
+ default: | |
+ /* If you have a better idea for a default value let me know. */ | |
+ retval = "LC_XXX"; | |
+ } | |
+ | |
+ return retval; | |
+} | |
+ | |
+/* Guess value of current locale from value of the environment variables. */ | |
+static const char * | |
+internal_function | |
+guess_category_value (category, categoryname) | |
+ int category; | |
+ const char *categoryname; | |
+{ | |
+ const char *language; | |
+ const char *retval; | |
+ | |
+ /* The highest priority value is the `LANGUAGE' environment | |
+ variable. But we don't use the value if the currently selected | |
+ locale is the C locale. This is a GNU extension. */ | |
+ language = getenv ("LANGUAGE"); | |
+ if (language != NULL && language[0] == '\0') | |
+ language = NULL; | |
+ | |
+ /* We have to proceed with the POSIX methods of looking to `LC_ALL', | |
+ `LC_xxx', and `LANG'. On some systems this can be done by the | |
+ `setlocale' function itself. */ | |
+#if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && de… | |
+ retval = setlocale (category, NULL); | |
+#else | |
+ /* Setting of LC_ALL overwrites all other. */ | |
+ retval = getenv ("LC_ALL"); | |
+ if (retval == NULL || retval[0] == '\0') | |
+ { | |
+ /* Next comes the name of the desired category. */ | |
+ retval = getenv (categoryname); | |
+ if (retval == NULL || retval[0] == '\0') | |
+ { | |
+ /* Last possibility is the LANG environment variable. */ | |
+ retval = getenv ("LANG"); | |
+ if (retval == NULL || retval[0] == '\0') | |
+ /* We use C as the default domain. POSIX says this is | |
+ implementation defined. */ | |
+ return "C"; | |
+ } | |
+ } | |
+#endif | |
+ | |
+ return language != NULL && strcmp (retval, "C") != 0 ? language : retval; | |
+} | |
+ | |
+/* @@ begin of epilog @@ */ | |
+ | |
+/* We don't want libintl.a to depend on any other library. So we | |
+ avoid the non-standard function stpcpy. In GNU C Library this | |
+ function is available, though. Also allow the symbol HAVE_STPCPY | |
+ to be defined. */ | |
+#if !_LIBC && !HAVE_STPCPY | |
+static char * | |
+stpcpy (dest, src) | |
+ char *dest; | |
+ const char *src; | |
+{ | |
+ while ((*dest++ = *src++) != '\0') | |
+ /* Do nothing. */ ; | |
+ return dest - 1; | |
+} | |
+#endif | |
+ | |
+#if !_LIBC && !HAVE_MEMPCPY | |
+static void * | |
+mempcpy (dest, src, n) | |
+ void *dest; | |
+ const void *src; | |
+ size_t n; | |
+{ | |
+ return (void *) ((char *) memcpy (dest, src, n) + n); | |
+} | |
+#endif | |
+ | |
+ | |
+#ifdef _LIBC | |
+/* If we want to free all resources we have to do some work at | |
+ program's end. */ | |
+static void __attribute__ ((unused)) | |
+free_mem (void) | |
+{ | |
+ void *old; | |
+ | |
+ while (_nl_domain_bindings != NULL) | |
+ { | |
+ struct binding *oldp = _nl_domain_bindings; | |
+ _nl_domain_bindings = _nl_domain_bindings->next; | |
+ if (oldp->dirname != _nl_default_dirname) | |
+ /* Yes, this is a pointer comparison. */ | |
+ free (oldp->dirname); | |
+ free (oldp->codeset); | |
+ free (oldp); | |
+ } | |
+ | |
+ if (_nl_current_default_domain != _nl_default_default_domain) | |
+ /* Yes, again a pointer comparison. */ | |
+ free ((char *) _nl_current_default_domain); | |
+ | |
+ /* Remove the search tree with the known translations. */ | |
+ __tdestroy (root, free); | |
+ root = NULL; | |
+ | |
+ while (transmem_list != NULL) | |
+ { | |
+ old = transmem_list; | |
+ transmem_list = transmem_list->next; | |
+ free (old); | |
+ } | |
+} | |
+ | |
+text_set_element (__libc_subfreeres, free_mem); | |
+#endif | |
diff --git a/po/ChangeLog b/po/ChangeLog | |
t@@ -0,0 +1,6 @@ | |
+2001-10-26 gettextize <[email protected]> | |
+ | |
+ * Makefile.in.in: Upgrade to gettext-0.10.38. | |
+ * cat-id-tbl.c: Remove file. | |
+ * stamp-cat-id: Remove file. | |
+ |