diff options
author | Pavel Roskin <proskin@src.gnome.org> | 2001-06-29 06:38:47 +0000 |
---|---|---|
committer | Pavel Roskin <proskin@src.gnome.org> | 2001-06-29 06:38:47 +0000 |
commit | e67857422148467c9d6c85545f5803e99a2e871f (patch) | |
tree | 2c471cfab4118c5cb2249c25121c194b6fd0db56 /intl | |
parent | c43e25d0fb6a4272f3a4bfdd4e4075174c14ca15 (diff) | |
download | shared-mime-info-e67857422148467c9d6c85545f5803e99a2e871f.tar.gz |
Add missing files from gettext-0.10.38.
svn path=/trunk/; revision=1836
Diffstat (limited to 'intl')
-rwxr-xr-x | intl/config.charset | 438 | ||||
-rw-r--r-- | intl/dcigettext.c | 1257 | ||||
-rw-r--r-- | intl/dcngettext.c | 59 | ||||
-rw-r--r-- | intl/dngettext.c | 60 | ||||
-rw-r--r-- | intl/libgnuintl.h | 127 | ||||
-rw-r--r-- | intl/localcharset.c | 271 | ||||
-rw-r--r-- | intl/locale.alias | 77 | ||||
-rw-r--r-- | intl/ngettext.c | 67 | ||||
-rw-r--r-- | intl/plural.c | 1325 | ||||
-rw-r--r-- | intl/plural.y | 412 | ||||
-rw-r--r-- | intl/ref-add.sin | 31 | ||||
-rw-r--r-- | intl/ref-del.sin | 26 |
12 files changed, 4150 insertions, 0 deletions
diff --git a/intl/config.charset b/intl/config.charset new file mode 100755 index 00000000..d6f36955 --- /dev/null +++ b/intl/config.charset @@ -0,0 +1,438 @@ +#! /bin/sh +# Output a system dependent table of character encoding aliases. +# +# Copyright (C) 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 Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library 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. +# +# The table consists of lines of the form +# ALIAS CANONICAL +# +# ALIAS is the (system dependent) result of "nl_langinfo (CODESET)". +# ALIAS is compared in a case sensitive way. +# +# CANONICAL is the GNU canonical name for this character encoding. +# It must be an encoding supported by libiconv. Support by GNU libc is +# also desirable. CANONICAL is case insensitive. Usually an upper case +# MIME charset name is preferred. +# The current list of GNU canonical charset names is as follows. +# +# name used by which systems a MIME name? +# ASCII, ANSI_X3.4-1968 glibc solaris freebsd +# ISO-8859-1 glibc aix hpux irix osf solaris freebsd yes +# ISO-8859-2 glibc aix hpux irix osf solaris freebsd yes +# ISO-8859-3 glibc yes +# ISO-8859-4 osf solaris freebsd yes +# ISO-8859-5 glibc aix hpux irix osf solaris freebsd yes +# ISO-8859-6 glibc aix hpux solaris yes +# ISO-8859-7 glibc aix hpux irix osf solaris yes +# ISO-8859-8 glibc aix hpux osf solaris yes +# ISO-8859-9 glibc aix hpux irix osf solaris yes +# ISO-8859-13 glibc +# ISO-8859-15 glibc aix osf solaris freebsd +# KOI8-R glibc solaris freebsd yes +# KOI8-U glibc freebsd yes +# CP437 dos +# CP775 dos +# CP850 aix osf dos +# CP852 dos +# CP855 dos +# CP856 aix +# CP857 dos +# CP861 dos +# CP862 dos +# CP864 dos +# CP865 dos +# CP866 freebsd dos +# CP869 dos +# CP874 win32 dos +# CP922 aix +# CP932 aix win32 dos +# CP943 aix +# CP949 osf win32 dos +# CP950 win32 dos +# CP1046 aix +# CP1124 aix +# CP1129 aix +# CP1250 win32 +# CP1251 glibc win32 +# CP1252 aix win32 +# CP1253 win32 +# CP1254 win32 +# CP1255 win32 +# CP1256 win32 +# CP1257 win32 +# GB2312 glibc aix hpux irix solaris freebsd yes +# EUC-JP glibc aix hpux irix osf solaris freebsd yes +# EUC-KR glibc aix hpux irix osf solaris freebsd yes +# EUC-TW glibc aix hpux irix osf solaris +# BIG5 glibc aix hpux osf solaris freebsd yes +# BIG5HKSCS glibc +# GBK aix osf win32 dos +# GB18030 glibc +# SJIS hpux osf solaris freebsd +# JOHAB glibc win32 +# TIS-620 glibc aix hpux osf solaris +# VISCII glibc yes +# HP-ROMAN8 hpux +# HP-ARABIC8 hpux +# HP-GREEK8 hpux +# HP-HEBREW8 hpux +# HP-TURKISH8 hpux +# HP-KANA8 hpux +# DEC-KANJI osf +# DEC-HANYU osf +# UTF-8 glibc aix hpux osf solaris yes +# +# Note: Names which are not marked as being a MIME name should not be used in +# Internet protocols for information interchange (mail, news, etc.). +# +# Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Applications +# must understand both names and treat them as equivalent. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM + +host="$1" +os=`echo "$host" | sed -e 's/^[^-]*-[^-]*-\(.*\)$/\1/'` +echo "# This file contains a table of character encoding aliases," +echo "# suitable for operating system '${os}'." +echo "# It was automatically generated from config.charset." +# List of references, updated during installation: +echo "# Packages using this file: " +case "$os" in + linux* | *-gnu*) + # With glibc-2.1 or newer, we don't need any canonicalization, + # because glibc has iconv and both glibc and libiconv support all + # GNU canonical names directly. Therefore, the Makefile does not + # need to install the alias file at all. + # The following applies only to glibc-2.0.x and older libcs. + echo "ISO_646.IRV:1983 ASCII" + ;; + aix*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-6 ISO-8859-6" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "IBM-850 CP850" + echo "IBM-856 CP856" + echo "IBM-921 ISO-8859-13" + echo "IBM-922 CP922" + echo "IBM-932 CP932" + echo "IBM-943 CP943" + echo "IBM-1046 CP1046" + echo "IBM-1124 CP1124" + echo "IBM-1129 CP1129" + echo "IBM-1252 CP1252" + echo "IBM-eucCN GB2312" + echo "IBM-eucJP EUC-JP" + echo "IBM-eucKR EUC-KR" + echo "IBM-eucTW EUC-TW" + echo "big5 BIG5" + echo "GBK GBK" + echo "TIS-620 TIS-620" + echo "UTF-8 UTF-8" + ;; + hpux*) + echo "iso88591 ISO-8859-1" + echo "iso88592 ISO-8859-2" + echo "iso88595 ISO-8859-5" + echo "iso88596 ISO-8859-6" + echo "iso88597 ISO-8859-7" + echo "iso88598 ISO-8859-8" + echo "iso88599 ISO-8859-9" + echo "iso885915 ISO-8859-15" + echo "roman8 HP-ROMAN8" + echo "arabic8 HP-ARABIC8" + echo "greek8 HP-GREEK8" + echo "hebrew8 HP-HEBREW8" + echo "turkish8 HP-TURKISH8" + echo "kana8 HP-KANA8" + echo "tis620 TIS-620" + echo "big5 BIG5" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + echo "hp15CN GB2312" + #echo "ccdc ?" # what is this? + echo "SJIS SJIS" + echo "utf8 UTF-8" + ;; + irix*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-9 ISO-8859-9" + echo "eucCN GB2312" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + ;; + osf*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "cp850 CP850" + echo "big5 BIG5" + echo "dechanyu DEC-HANYU" + echo "dechanzi GB2312" + echo "deckanji DEC-KANJI" + echo "deckorean EUC-KR" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + echo "GBK GBK" + echo "KSC5601 CP949" + echo "sdeckanji EUC-JP" + echo "SJIS SJIS" + echo "TACTIS TIS-620" + echo "UTF-8 UTF-8" + ;; + solaris*) + echo "646 ASCII" + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-6 ISO-8859-6" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "koi8-r KOI8-R" + echo "BIG5 BIG5" + echo "gb2312 GB2312" + echo "cns11643 EUC-TW" + echo "5601 EUC-KR" + echo "eucJP EUC-JP" + echo "PCK SJIS" + echo "TIS620.2533 TIS-620" + #echo "sun_eu_greek ?" # what is this? + echo "UTF-8 UTF-8" + ;; + freebsd*) + # FreeBSD 4.2 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + echo "C ASCII" + echo "US-ASCII ASCII" + for l in la_LN lt_LN; do + echo "$l.ASCII ASCII" + done + for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \ + fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT la_LN \ + lt_LN nl_BE nl_NL no_NO pt_PT sv_SE; do + echo "$l.ISO_8859-1 ISO-8859-1" + echo "$l.DIS_8859-15 ISO-8859-15" + done + for l in cs_CZ hr_HR hu_HU la_LN lt_LN pl_PL sl_SI; do + echo "$l.ISO_8859-2 ISO-8859-2" + done + for l in la_LN lt_LT; do + echo "$l.ISO_8859-4 ISO-8859-4" + done + for l in ru_RU ru_SU; do + echo "$l.KOI8-R KOI8-R" + echo "$l.ISO_8859-5 ISO-8859-5" + echo "$l.CP866 CP866" + done + echo "uk_UA.KOI8-U KOI8-U" + echo "zh_TW.BIG5 BIG5" + echo "zh_TW.Big5 BIG5" + echo "zh_CN.EUC GB2312" + echo "ja_JP.EUC EUC-JP" + echo "ja_JP.SJIS SJIS" + echo "ja_JP.Shift_JIS SJIS" + echo "ko_KR.EUC EUC-KR" + ;; + beos*) + # BeOS has a single locale, and it has UTF-8 encoding. + echo "* UTF-8" + ;; + msdosdjgpp*) + # DJGPP 2.03 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + echo "#" + echo "# The encodings given here may not all be correct." + echo "# If you find that the encoding given for your language and" + echo "# country is not the one your DOS machine actually uses, just" + echo "# correct it in this file, and send a mail to" + echo "# Juan Manuel Guerrero <st001906@hrz1.hrz.tu-darmstadt.de>" + echo "# and Bruno Haible <haible@clisp.cons.org>." + echo "#" + echo "C ASCII" + # ISO-8859-1 languages + echo "ca CP850" + echo "ca_ES CP850" + echo "da CP865" # not CP850 ?? + echo "da_DK CP865" # not CP850 ?? + echo "de CP850" + echo "de_AT CP850" + echo "de_CH CP850" + echo "de_DE CP850" + echo "en CP850" + echo "en_AU CP850" # not CP437 ?? + echo "en_CA CP850" + echo "en_GB CP850" + echo "en_NZ CP437" + echo "en_US CP437" + echo "en_ZA CP850" # not CP437 ?? + echo "es CP850" + echo "es_AR CP850" + echo "es_BO CP850" + echo "es_CL CP850" + echo "es_CO CP850" + echo "es_CR CP850" + echo "es_CU CP850" + echo "es_DO CP850" + echo "es_EC CP850" + echo "es_ES CP850" + echo "es_GT CP850" + echo "es_HN CP850" + echo "es_MX CP850" + echo "es_NI CP850" + echo "es_PA CP850" + echo "es_PY CP850" + echo "es_PE CP850" + echo "es_SV CP850" + echo "es_UY CP850" + echo "es_VE CP850" + echo "et CP850" + echo "et_EE CP850" + echo "eu CP850" + echo "eu_ES CP850" + echo "fi CP850" + echo "fi_FI CP850" + echo "fr CP850" + echo "fr_BE CP850" + echo "fr_CA CP850" + echo "fr_CH CP850" + echo "fr_FR CP850" + echo "ga CP850" + echo "ga_IE CP850" + echo "gd CP850" + echo "gd_GB CP850" + echo "gl CP850" + echo "gl_ES CP850" + echo "id CP850" # not CP437 ?? + echo "id_ID CP850" # not CP437 ?? + echo "is CP861" # not CP850 ?? + echo "is_IS CP861" # not CP850 ?? + echo "it CP850" + echo "it_CH CP850" + echo "it_IT CP850" + echo "lt CP775" + echo "lt_LT CP775" + echo "lv CP775" + echo "lv_LV CP775" + echo "nb CP865" # not CP850 ?? + echo "nb_NO CP865" # not CP850 ?? + echo "nl CP850" + echo "nl_BE CP850" + echo "nl_NL CP850" + echo "nn CP865" # not CP850 ?? + echo "nn_NO CP865" # not CP850 ?? + echo "no CP865" # not CP850 ?? + echo "no_NO CP865" # not CP850 ?? + echo "pt CP850" + echo "pt_BR CP850" + echo "pt_PT CP850" + echo "sv CP850" + echo "sv_SE CP850" + # ISO-8859-2 languages + echo "cs CP852" + echo "cs_CZ CP852" + echo "hr CP852" + echo "hr_HR CP852" + echo "hu CP852" + echo "hu_HU CP852" + echo "pl CP852" + echo "pl_PL CP852" + echo "ro CP852" + echo "ro_RO CP852" + echo "sk CP852" + echo "sk_SK CP852" + echo "sl CP852" + echo "sl_SI CP852" + echo "sq CP852" + echo "sq_AL CP852" + echo "sr CP852" # CP852 or CP866 or CP855 ?? + echo "sr_YU CP852" # CP852 or CP866 or CP855 ?? + # ISO-8859-3 languages + echo "mt CP850" + echo "mt_MT CP850" + # ISO-8859-5 languages + echo "be CP866" + echo "be_BE CP866" + echo "bg CP866" # not CP855 ?? + echo "bg_BG CP866" # not CP855 ?? + echo "mk CP866" # not CP855 ?? + echo "mk_MK CP866" # not CP855 ?? + echo "ru KOI8-R" # not CP866 ?? + echo "ru_RU KOI8-R" # not CP866 ?? + # ISO-8859-6 languages + echo "ar CP864" + echo "ar_AE CP864" + echo "ar_DZ CP864" + echo "ar_EG CP864" + echo "ar_IQ CP864" + echo "ar_IR CP864" + echo "ar_JO CP864" + echo "ar_KW CP864" + echo "ar_MA CP864" + echo "ar_OM CP864" + echo "ar_QA CP864" + echo "ar_SA CP864" + echo "ar_SY CP864" + # ISO-8859-7 languages + echo "el CP869" + echo "el_GR CP869" + # ISO-8859-8 languages + echo "he CP862" + echo "he_IL CP862" + # ISO-8859-9 languages + echo "tr CP857" + echo "tr_TR CP857" + # Japanese + echo "ja CP932" + echo "ja_JP CP932" + # Chinese + echo "zh_CN GBK" + echo "zh_TW CP950" # not CP938 ?? + # Korean + echo "kr CP949" # not CP934 ?? + echo "kr_KR CP949" # not CP934 ?? + # Thai + echo "th CP874" + echo "th_TH CP874" + # Other + echo "eo CP850" + echo "eo_EO CP850" + ;; +esac diff --git a/intl/dcigettext.c b/intl/dcigettext.c new file mode 100644 index 00000000..8456550d --- /dev/null +++ b/intl/dcigettext.c @@ -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 ("/", _PC_PATH_MAX)) +#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 && defined HAVE_LOCALE_NULL) + 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/intl/dcngettext.c b/intl/dcngettext.c new file mode 100644 index 00000000..e5da2577 --- /dev/null +++ b/intl/dcngettext.c @@ -0,0 +1,59 @@ +/* Implementation of the dcngettext(3) 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. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "gettextP.h" +#ifdef _LIBC +# include <libintl.h> +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ + +/* 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 DCNGETTEXT __dcngettext +# define DCIGETTEXT __dcigettext +#else +# define DCNGETTEXT dcngettext__ +# define DCIGETTEXT dcigettext__ +#endif + +/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY + locale. */ +char * +DCNGETTEXT (domainname, msgid1, msgid2, n, category) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; + int category; +{ + return DCIGETTEXT (domainname, msgid1, msgid2, 1, n, category); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__dcngettext, dcngettext); +#endif diff --git a/intl/dngettext.c b/intl/dngettext.c new file mode 100644 index 00000000..79aaa9ae --- /dev/null +++ b/intl/dngettext.c @@ -0,0 +1,60 @@ +/* Implementation of the dngettext(3) function. + Copyright (C) 1995-1997, 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. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <locale.h> + +#include "gettextP.h" +#ifdef _LIBC +# include <libintl.h> +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ + +/* 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 DNGETTEXT __dngettext +# define DCNGETTEXT __dcngettext +#else +# define DNGETTEXT dngettext__ +# define DCNGETTEXT dcngettext__ +#endif + +/* Look up MSGID in the DOMAINNAME message catalog of the current + LC_MESSAGES locale and skip message according to the plural form. */ +char * +DNGETTEXT (domainname, msgid1, msgid2, n) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + return DCNGETTEXT (domainname, msgid1, msgid2, n, LC_MESSAGES); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__dngettext, dngettext); +#endif diff --git a/intl/libgnuintl.h b/intl/libgnuintl.h new file mode 100644 index 00000000..577001a4 --- /dev/null +++ b/intl/libgnuintl.h @@ -0,0 +1,127 @@ +/* Message catalogs for internationalization. + Copyright (C) 1995-1997, 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. */ + +#ifndef _LIBINTL_H +#define _LIBINTL_H 1 + +#include <locale.h> + +/* The LC_MESSAGES locale category is the category used by the functions + gettext() and dgettext(). It is specified in POSIX, but not in ANSI C. + On systems that don't define it, use an arbitrary value instead. + On Solaris, <locale.h> defines __LOCALE_H then includes <libintl.h> (i.e. + this file!) and then only defines LC_MESSAGES. To avoid a redefinition + warning, don't define LC_MESSAGES in this case. */ +#if !defined LC_MESSAGES && !defined __LOCALE_H +# define LC_MESSAGES 1729 +#endif + +/* We define an additional symbol to signal that we use the GNU + implementation of gettext. */ +#define __USE_GNU_GETTEXT 1 + +/* Resolve a platform specific conflict on DJGPP. GNU gettext takes + precedence over _conio_gettext. */ +#ifdef __DJGPP__ +# undef gettext +# define gettext gettext +#endif + +#ifndef PARAMS +# if __STDC__ || defined __cplusplus +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Look up MSGID in the current default message catalog for the current + LC_MESSAGES locale. If not found, returns MSGID itself (the default + text). */ +extern char *gettext PARAMS ((const char *__msgid)); + +/* Look up MSGID in the DOMAINNAME message catalog for the current + LC_MESSAGES locale. */ +extern char *dgettext PARAMS ((const char *__domainname, const char *__msgid)); + +/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY + locale. */ +extern char *dcgettext PARAMS ((const char *__domainname, const char *__msgid, + int __category)); + + +/* Similar to `gettext' but select the plural form corresponding to the + number N. */ +extern char *ngettext PARAMS ((const char *__msgid1, const char *__msgid2, + unsigned long int __n)); + +/* Similar to `dgettext' but select the plural form corresponding to the + number N. */ +extern char *dngettext PARAMS ((const char *__domainname, const char *__msgid1, + const char *__msgid2, unsigned long int __n)); + +/* Similar to `dcgettext' but select the plural form corresponding to the + number N. */ +extern char *dcngettext PARAMS ((const char *__domainname, const char *__msgid1, + const char *__msgid2, unsigned long int __n, + int __category)); + + +/* Set the current default message catalog to DOMAINNAME. + If DOMAINNAME is null, return the current default. + If DOMAINNAME is "", reset to the default of "messages". */ +extern char *textdomain PARAMS ((const char *__domainname)); + +/* Specify that the DOMAINNAME message catalog will be found + in DIRNAME rather than in the system locale data base. */ +extern char *bindtextdomain PARAMS ((const char *__domainname, + const char *__dirname)); + +/* Specify the character encoding in which the messages from the + DOMAINNAME message catalog will be returned. */ +extern char *bind_textdomain_codeset PARAMS ((const char *__domainname, + const char *__codeset)); + + +/* Optimized version of the functions above. */ +#if defined __OPTIMIZED +/* These are macros, but could also be inline functions. */ + +# define gettext(msgid) \ + dgettext (NULL, msgid) + +# define dgettext(domainname, msgid) \ + dcgettext (domainname, msgid, LC_MESSAGES) + +# define ngettext(msgid1, msgid2, n) \ + dngettext (NULL, msgid1, msgid2, n) + +# define dngettext(domainname, msgid1, msgid2, n) \ + dcngettext (domainname, msgid1, msgid2, n, LC_MESSAGES) + +#endif /* Optimizing. */ + + +#ifdef __cplusplus +} +#endif + +#endif /* libintl.h */ diff --git a/intl/localcharset.c b/intl/localcharset.c new file mode 100644 index 00000000..22e09e41 --- /dev/null +++ b/intl/localcharset.c @@ -0,0 +1,271 @@ +/* Determine a canonical name for the current locale's character encoding. + + Copyright (C) 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 Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library 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. */ + +/* Written by Bruno Haible <haible@clisp.cons.org>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if HAVE_STDDEF_H +# include <stddef.h> +#endif + +#include <stdio.h> +#if HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +#endif +#if HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#if defined _WIN32 || defined __WIN32__ +# undef WIN32 /* avoid warning on mingw32 */ +# define WIN32 +#endif + +#ifndef WIN32 +# if HAVE_LANGINFO_CODESET +# include <langinfo.h> +# else +# if HAVE_SETLOCALE +# include <locale.h> +# endif +# endif +#else /* WIN32 */ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + +#ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +#endif + +#ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +#endif + +/* The following static variable is declared 'volatile' to avoid a + possible multithread problem in the function get_charset_aliases. If we + are running in a threaded environment, and if two threads initialize + 'charset_aliases' simultaneously, both will produce the same value, + and everything will be ok if the two assignments to 'charset_aliases' + are atomic. But I don't know what will happen if the two assignments mix. */ +#if __STDC__ != 1 +# define volatile /* empty */ +#endif +/* Pointer to the contents of the charset.alias file, if it has already been + read, else NULL. Its format is: + ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */ +static char * volatile charset_aliases; + +/* Return a pointer to the contents of the charset.alias file. */ +static const char * +get_charset_aliases () +{ + char *cp; + + cp = charset_aliases; + if (cp == NULL) + { +#ifndef WIN32 + FILE *fp; + const char *dir = LIBDIR; + const char *base = "charset.alias"; + char *file_name; + + /* Concatenate dir and base into freshly allocated file_name. */ + { + size_t dir_len = strlen (dir); + size_t base_len = strlen (base); + int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1])); + file_name = (char *) malloc (dir_len + add_slash + base_len + 1); + if (file_name != NULL) + { + memcpy (file_name, dir, dir_len); + if (add_slash) + file_name[dir_len] = DIRECTORY_SEPARATOR; + memcpy (file_name + dir_len + add_slash, base, base_len + 1); + } + } + + if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL) + /* Out of memory or file not found, treat it as empty. */ + cp = ""; + else + { + /* Parse the file's contents. */ + int c; + char buf1[50+1]; + char buf2[50+1]; + char *res_ptr = NULL; + size_t res_size = 0; + size_t l1, l2; + + for (;;) + { + c = getc (fp); + if (c == EOF) + break; + if (c == '\n' || c == ' ' || c == '\t') + continue; + if (c == '#') + { + /* Skip comment, to end of line. */ + do + c = getc (fp); + while (!(c == EOF || c == '\n')); + if (c == EOF) + break; + continue; + } + ungetc (c, fp); + if (fscanf(fp, "%50s %50s", buf1, buf2) < 2) + break; + l1 = strlen (buf1); + l2 = strlen (buf2); + if (res_size == 0) + { + res_size = l1 + 1 + l2 + 1; + res_ptr = malloc (res_size + 1); + } + else + { + res_size += l1 + 1 + l2 + 1; + res_ptr = realloc (res_ptr, res_size + 1); + } + if (res_ptr == NULL) + { + /* Out of memory. */ + res_size = 0; + break; + } + strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1); + strcpy (res_ptr + res_size - (l2 + 1), buf2); + } + fclose (fp); + if (res_size == 0) + cp = ""; + else + { + *(res_ptr + res_size) = '\0'; + cp = res_ptr; + } + } + + if (file_name != NULL) + free (file_name); + +#else /* WIN32 */ + + /* To avoid the troubles of installing a separate file in the same + directory as the DLL and of retrieving the DLL's directory at + runtime, simply inline the aliases here. */ + + cp = "CP936" "\0" "GBK" "\0" + "CP1361" "\0" "JOHAB" "\0"; +#endif + + charset_aliases = cp; + } + + return cp; +} + +/* Determine the current locale's character encoding, and canonicalize it + into one of the canonical names listed in config.charset. + The result must not be freed; it is statically allocated. + If the canonical name cannot be determined, the result is a non-canonical + name. */ + +#ifdef STATIC +STATIC +#endif +const char * +locale_charset () +{ + const char *codeset; + const char *aliases; + +#ifndef WIN32 + +# if HAVE_LANGINFO_CODESET + + /* Most systems support nl_langinfo (CODESET) nowadays. */ + codeset = nl_langinfo (CODESET); + +# else + + /* On old systems which lack it, use setlocale or getenv. */ + const char *locale = NULL; + + /* But most old systems don't have a complete set of locales. Some + (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't + use setlocale here; it would return "C" when it doesn't support the + locale name the user has set. */ +# if HAVE_SETLOCALE && 0 + locale = setlocale (LC_CTYPE, NULL); +# endif + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_CTYPE"); + if (locale == NULL || locale[0] == '\0') + locale = getenv ("LANG"); + } + } + + /* On some old systems, one used to set locale = "iso8859_1". On others, + you set it to "language_COUNTRY.charset". In any case, we resolve it + through the charset.alias file. */ + codeset = locale; + +# endif + +#else /* WIN32 */ + + static char buf[2 + 10 + 1]; + + /* Win32 has a function returning the locale's codepage as a number. */ + sprintf (buf, "CP%u", GetACP ()); + codeset = buf; + +#endif + + if (codeset == NULL) + /* The canonical name cannot be determined. */ + codeset = ""; + + /* Resolve alias. */ + for (aliases = get_charset_aliases (); + *aliases != '\0'; + aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1) + if (strcmp (codeset, aliases) == 0 + || (aliases[0] == '*' && aliases[1] == '\0')) + { + codeset = aliases + strlen (aliases) + 1; + break; + } + + return codeset; +} diff --git a/intl/locale.alias b/intl/locale.alias new file mode 100644 index 00000000..48940f74 --- /dev/null +++ b/intl/locale.alias @@ -0,0 +1,77 @@ +# Locale name alias data base. +# Copyright (C) 1996,1997,1998,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. + +# The format of this file is the same as for the corresponding file of +# the X Window System, which normally can be found in +# /usr/lib/X11/locale/locale.alias +# A single line contains two fields: an alias and a substitution value. +# All entries are case independent. + +# Note: This file is far from being complete. If you have a value for +# your own site which you think might be useful for others too, share +# it with the rest of us. Send it using the `glibcbug' script to +# bugs@gnu.org. + +# Packages using this file: + +bokmal no_NO.ISO-8859-1 +bokmål no_NO.ISO-8859-1 +catalan ca_ES.ISO-8859-1 +croatian hr_HR.ISO-8859-2 +czech cs_CZ.ISO-8859-2 +danish da_DK.ISO-8859-1 +dansk da_DK.ISO-8859-1 +deutsch de_DE.ISO-8859-1 +dutch nl_NL.ISO-8859-1 +eesti et_EE.ISO-8859-1 +estonian et_EE.ISO-8859-1 +finnish fi_FI.ISO-8859-1 +français fr_FR.ISO-8859-1 +french fr_FR.ISO-8859-1 +galego gl_ES.ISO-8859-1 +galician gl_ES.ISO-8859-1 +german de_DE.ISO-8859-1 +greek el_GR.ISO-8859-7 +hebrew iw_IL.ISO-8859-8 +hrvatski hr_HR.ISO-8859-2 +hungarian hu_HU.ISO-8859-2 +icelandic is_IS.ISO-8859-1 +italian it_IT.ISO-8859-1 +japanese ja_JP.eucJP +japanese.euc ja_JP.eucJP +ja_JP ja_JP.eucJP +ja_JP.ujis ja_JP.eucJP +japanese.sjis ja_JP.SJIS +korean ko_KR.eucKR +korean.euc ko_KR.eucKR +ko_KR ko_KR.eucKR +lithuanian lt_LT.ISO-8859-13 +nb_NO no_NO.ISO-8859-1 +nb_NO.ISO-8859-1 no_NO.ISO-8859-1 +norwegian no_NO.ISO-8859-1 +nynorsk nn_NO.ISO-8859-1 +polish pl_PL.ISO-8859-2 +portuguese pt_PT.ISO-8859-1 +romanian ro_RO.ISO-8859-2 +russian ru_RU.ISO-8859-5 +slovak sk_SK.ISO-8859-2 +slovene sl_SI.ISO-8859-2 +slovenian sl_SI.ISO-8859-2 +spanish es_ES.ISO-8859-1 +swedish sv_SE.ISO-8859-1 +thai th_TH.TIS-620 +turkish tr_TR.ISO-8859-9 diff --git a/intl/ngettext.c b/intl/ngettext.c new file mode 100644 index 00000000..8b1fa02f --- /dev/null +++ b/intl/ngettext.c @@ -0,0 +1,67 @@ +/* Implementation of ngettext(3) function. + Copyright (C) 1995, 1997, 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. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# define __need_NULL +# include <stddef.h> +#else +# include <stdlib.h> /* Just for NULL. */ +#endif + +#include "gettextP.h" +#ifdef _LIBC +# include <libintl.h> +#else +# include "libgnuintl.h" +#endif + +#include <locale.h> + +/* @@ end of prolog @@ */ + +/* 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 NGETTEXT __ngettext +# define DCNGETTEXT __dcngettext +#else +# define NGETTEXT ngettext__ +# define DCNGETTEXT dcngettext__ +#endif + +/* Look up MSGID in the current default message catalog for the current + LC_MESSAGES locale. If not found, returns MSGID itself (the default + text). */ +char * +NGETTEXT (msgid1, msgid2, n) + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + return DCNGETTEXT (NULL, msgid1, msgid2, n, LC_MESSAGES); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__ngettext, ngettext); +#endif diff --git a/intl/plural.c b/intl/plural.c new file mode 100644 index 00000000..81913356 --- /dev/null +++ b/intl/plural.c @@ -0,0 +1,1325 @@ + +/* A Bison parser, made from plural.y + by GNU Bison version 1.28 */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse __gettextparse +#define yylex __gettextlex +#define yyerror __gettexterror +#define yylval __gettextlval +#define yychar __gettextchar +#define yydebug __gettextdebug +#define yynerrs __gettextnerrs +#define EQUOP2 257 +#define CMPOP2 258 +#define ADDOP2 259 +#define MULOP2 260 +#define NUMBER 261 + +#line 1 "plural.y" + +/* Expression parsing for plural form selection. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Written by Ulrich Drepper <drepper@cygnus.com>, 2000. + + 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. */ + +/* The bison generated parser uses alloca. AIX 3 forces us to put this + declaration at the beginning of the file. The declaration in bison's + skeleton file comes too late. This must come before <config.h> + because <config.h> may include arbitrary system headers. */ +#if defined _AIX && !defined __GNUC__ + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include "gettextP.h" + +/* 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 FREE_EXPRESSION __gettext_free_exp +#else +# define FREE_EXPRESSION gettext_free_exp__ +# define __gettextparse gettextparse__ +#endif + +#define YYLEX_PARAM &((struct parse_args *) arg)->cp +#define YYPARSE_PARAM arg + +#line 52 "plural.y" +typedef union { + unsigned long int num; + enum operator op; + struct expression *exp; +} YYSTYPE; +#line 58 "plural.y" + +/* Prototypes for local functions. */ +static struct expression *new_exp PARAMS ((int nargs, enum operator op, + struct expression * const *args)); +static inline struct expression *new_exp_0 PARAMS ((enum operator op)); +static inline struct expression *new_exp_1 PARAMS ((enum operator op, + struct expression *right)); +static struct expression *new_exp_2 PARAMS ((enum operator op, + struct expression *left, + struct expression *right)); +static inline struct expression *new_exp_3 PARAMS ((enum operator op, + struct expression *bexp, + struct expression *tbranch, + struct expression *fbranch)); +static int yylex PARAMS ((YYSTYPE *lval, const char **pexp)); +static void yyerror PARAMS ((const char *str)); + +/* Allocation of expressions. */ + +static struct expression * +new_exp (nargs, op, args) + int nargs; + enum operator op; + struct expression * const *args; +{ + int i; + struct expression *newp; + + /* If any of the argument could not be malloc'ed, just return NULL. */ + for (i = nargs - 1; i >= 0; i--) + if (args[i] == NULL) + goto fail; + + /* Allocate a new expression. */ + newp = (struct expression *) malloc (sizeof (*newp)); + if (newp != NULL) + { + newp->nargs = nargs; + newp->operation = op; + for (i = nargs - 1; i >= 0; i--) + newp->val.args[i] = args[i]; + return newp; + } + + fail: + for (i = nargs - 1; i >= 0; i--) + FREE_EXPRESSION (args[i]); + + return NULL; +} + +static inline struct expression * +new_exp_0 (op) + enum operator op; +{ + return new_exp (0, op, NULL); +} + +static inline struct expression * +new_exp_1 (op, right) + enum operator op; + struct expression *right; +{ + struct expression *args[1]; + + args[0] = right; + return new_exp (1, op, args); +} + +static struct expression * +new_exp_2 (op, left, right) + enum operator op; + struct expression *left; + struct expression *right; +{ + struct expression *args[2]; + + args[0] = left; + args[1] = right; + return new_exp (2, op, args); +} + +static inline struct expression * +new_exp_3 (op, bexp, tbranch, fbranch) + enum operator op; + struct expression *bexp; + struct expression *tbranch; + struct expression *fbranch; +{ + struct expression *args[3]; + + args[0] = bexp; + args[1] = tbranch; + args[2] = fbranch; + return new_exp (3, op, args); +} + +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 27 +#define YYFLAG -32768 +#define YYNTBASE 16 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 261 ? yytranslate[x] : 18) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 10, 2, 2, 2, 2, 5, 2, 14, + 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 12, 2, 2, + 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 6, 7, 8, 9, + 11 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 2, 8, 12, 16, 20, 24, 28, 32, 35, + 37, 39 +}; + +static const short yyrhs[] = { 17, + 0, 17, 3, 17, 12, 17, 0, 17, 4, 17, + 0, 17, 5, 17, 0, 17, 6, 17, 0, 17, + 7, 17, 0, 17, 8, 17, 0, 17, 9, 17, + 0, 10, 17, 0, 13, 0, 11, 0, 14, 17, + 15, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 177, 185, 189, 193, 197, 201, 205, 209, 213, 217, + 221, 226 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","'?'","'|'", +"'&'","EQUOP2","CMPOP2","ADDOP2","MULOP2","'!'","NUMBER","':'","'n'","'('","')'", +"start","exp", NULL +}; +#endif + +static const short yyr1[] = { 0, + 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17 +}; + +static const short yyr2[] = { 0, + 1, 5, 3, 3, 3, 3, 3, 3, 2, 1, + 1, 3 +}; + +static const short yydefact[] = { 0, + 0, 11, 10, 0, 1, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 0, 3, 4, 5, 6, + 7, 8, 0, 2, 0, 0, 0 +}; + +static const short yydefgoto[] = { 25, + 5 +}; + +static const short yypact[] = { -9, + -9,-32768,-32768, -9, 34,-32768, 11, -9, -9, -9, + -9, -9, -9, -9,-32768, 24, 39, 43, 16, 26, + -3,-32768, -9, 34, 21, 53,-32768 +}; + +static const short yypgoto[] = {-32768, + -1 +}; + + +#define YYLAST 53 + + +static const short yytable[] = { 6, + 1, 2, 7, 3, 4, 14, 16, 17, 18, 19, + 20, 21, 22, 8, 9, 10, 11, 12, 13, 14, + 26, 24, 12, 13, 14, 15, 8, 9, 10, 11, + 12, 13, 14, 13, 14, 23, 8, 9, 10, 11, + 12, 13, 14, 10, 11, 12, 13, 14, 11, 12, + 13, 14, 27 +}; + +static const short yycheck[] = { 1, + 10, 11, 4, 13, 14, 9, 8, 9, 10, 11, + 12, 13, 14, 3, 4, 5, 6, 7, 8, 9, + 0, 23, 7, 8, 9, 15, 3, 4, 5, 6, + 7, 8, 9, 8, 9, 12, 3, 4, 5, 6, + 7, 8, 9, 5, 6, 7, 8, 9, 6, 7, + 8, 9, 0 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/home/haible/gnu/arch/linuxlibc6/share/bison.simple" +/* This file comes from bison-1.28. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 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. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include <alloca.h> +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include <malloc.h> +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include <malloc.h> */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 217 "/home/haible/gnu/arch/linuxlibc6/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 178 "plural.y" +{ + if (yyvsp[0].exp == NULL) + YYABORT; + ((struct parse_args *) arg)->res = yyvsp[0].exp; + ; + break;} +case 2: +#line 186 "plural.y" +{ + yyval.exp = new_exp_3 (qmop, yyvsp[-4].exp, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 3: +#line 190 "plural.y" +{ + yyval.exp = new_exp_2 (lor, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 4: +#line 194 "plural.y" +{ + yyval.exp = new_exp_2 (land, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 5: +#line 198 "plural.y" +{ + yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 6: +#line 202 "plural.y" +{ + yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 7: +#line 206 "plural.y" +{ + yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 8: +#line 210 "plural.y" +{ + yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); + ; + break;} +case 9: +#line 214 "plural.y" +{ + yyval.exp = new_exp_1 (lnot, yyvsp[0].exp); + ; + break;} +case 10: +#line 218 "plural.y" +{ + yyval.exp = new_exp_0 (var); + ; + break;} +case 11: +#line 222 "plural.y" +{ + if ((yyval.exp = new_exp_0 (num)) != NULL) + yyval.exp->val.num = yyvsp[0].num; + ; + break;} +case 12: +#line 227 "plural.y" +{ + yyval.exp = yyvsp[-1].exp; + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 543 "/home/haible/gnu/arch/linuxlibc6/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} +#line 232 "plural.y" + + +void +internal_function +FREE_EXPRESSION (exp) + struct expression *exp; +{ + if (exp == NULL) + return; + + /* Handle the recursive case. */ + switch (exp->nargs) + { + case 3: + FREE_EXPRESSION (exp->val.args[2]); + /* FALLTHROUGH */ + case 2: + FREE_EXPRESSION (exp->val.args[1]); + /* FALLTHROUGH */ + case 1: + FREE_EXPRESSION (exp->val.args[0]); + /* FALLTHROUGH */ + default: + break; + } + + free (exp); +} + + +static int +yylex (lval, pexp) + YYSTYPE *lval; + const char **pexp; +{ + const char *exp = *pexp; + int result; + + while (1) + { + if (exp[0] == '\0') + { + *pexp = exp; + return YYEOF; + } + + if (exp[0] != ' ' && exp[0] != '\t') + break; + + ++exp; + } + + result = *exp++; + switch (result) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + unsigned long int n = result - '0'; + while (exp[0] >= '0' && exp[0] <= '9') + { + n *= 10; + n += exp[0] - '0'; + ++exp; + } + lval->num = n; + result = NUMBER; + } + break; + + case '=': + if (exp[0] == '=') + { + ++exp; + lval->op = equal; + result = EQUOP2; + } + else + result = YYERRCODE; + break; + + case '!': + if (exp[0] == '=') + { + ++exp; + lval->op = not_equal; + result = EQUOP2; + } + break; + + case '&': + case '|': + if (exp[0] == result) + ++exp; + else + result = YYERRCODE; + break; + + case '<': + if (exp[0] == '=') + { + ++exp; + lval->op = less_or_equal; + } + else + lval->op = less_than; + result = CMPOP2; + break; + + case '>': + if (exp[0] == '=') + { + ++exp; + lval->op = greater_or_equal; + } + else + lval->op = greater_than; + result = CMPOP2; + break; + + case '*': + lval->op = mult; + result = MULOP2; + break; + + case '/': + lval->op = divide; + result = MULOP2; + break; + + case '%': + lval->op = module; + result = MULOP2; + break; + + case '+': + lval->op = plus; + result = ADDOP2; + break; + + case '-': + lval->op = minus; + result = ADDOP2; + break; + + case 'n': + case '?': + case ':': + case '(': + case ')': + /* Nothing, just return the character. */ + break; + + case ';': + case '\n': + case '\0': + /* Be safe and let the user call this function again. */ + --exp; + result = YYEOF; + break; + + default: + result = YYERRCODE; +#if YYDEBUG != 0 + --exp; +#endif + break; + } + + *pexp = exp; + + return result; +} + + +static void +yyerror (str) + const char *str; +{ + /* Do nothing. We don't print error messages here. */ +} diff --git a/intl/plural.y b/intl/plural.y new file mode 100644 index 00000000..42ffa0eb --- /dev/null +++ b/intl/plural.y @@ -0,0 +1,412 @@ +%{ +/* Expression parsing for plural form selection. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Written by Ulrich Drepper <drepper@cygnus.com>, 2000. + + 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. */ + +/* The bison generated parser uses alloca. AIX 3 forces us to put this + declaration at the beginning of the file. The declaration in bison's + skeleton file comes too late. This must come before <config.h> + because <config.h> may include arbitrary system headers. */ +#if defined _AIX && !defined __GNUC__ + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include "gettextP.h" + +/* 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 FREE_EXPRESSION __gettext_free_exp +#else +# define FREE_EXPRESSION gettext_free_exp__ +# define __gettextparse gettextparse__ +#endif + +#define YYLEX_PARAM &((struct parse_args *) arg)->cp +#define YYPARSE_PARAM arg +%} +%pure_parser +%expect 10 + +%union { + unsigned long int num; + enum operator op; + struct expression *exp; +} + +%{ +/* Prototypes for local functions. */ +static struct expression *new_exp PARAMS ((int nargs, enum operator op, + struct expression * const *args)); +static inline struct expression *new_exp_0 PARAMS ((enum operator op)); +static inline struct expression *new_exp_1 PARAMS ((enum operator op, + struct expression *right)); +static struct expression *new_exp_2 PARAMS ((enum operator op, + struct expression *left, + struct expression *right)); +static inline struct expression *new_exp_3 PARAMS ((enum operator op, + struct expression *bexp, + struct expression *tbranch, + struct expression *fbranch)); +static int yylex PARAMS ((YYSTYPE *lval, const char **pexp)); +static void yyerror PARAMS ((const char *str)); + +/* Allocation of expressions. */ + +static struct expression * +new_exp (nargs, op, args) + int nargs; + enum operator op; + struct expression * const *args; +{ + int i; + struct expression *newp; + + /* If any of the argument could not be malloc'ed, just return NULL. */ + for (i = nargs - 1; i >= 0; i--) + if (args[i] == NULL) + goto fail; + + /* Allocate a new expression. */ + newp = (struct expression *) malloc (sizeof (*newp)); + if (newp != NULL) + { + newp->nargs = nargs; + newp->operation = op; + for (i = nargs - 1; i >= 0; i--) + newp->val.args[i] = args[i]; + return newp; + } + + fail: + for (i = nargs - 1; i >= 0; i--) + FREE_EXPRESSION (args[i]); + + return NULL; +} + +static inline struct expression * +new_exp_0 (op) + enum operator op; +{ + return new_exp (0, op, NULL); +} + +static inline struct expression * +new_exp_1 (op, right) + enum operator op; + struct expression *right; +{ + struct expression *args[1]; + + args[0] = right; + return new_exp (1, op, args); +} + +static struct expression * +new_exp_2 (op, left, right) + enum operator op; + struct expression *left; + struct expression *right; +{ + struct expression *args[2]; + + args[0] = left; + args[1] = right; + return new_exp (2, op, args); +} + +static inline struct expression * +new_exp_3 (op, bexp, tbranch, fbranch) + enum operator op; + struct expression *bexp; + struct expression *tbranch; + struct expression *fbranch; +{ + struct expression *args[3]; + + args[0] = bexp; + args[1] = tbranch; + args[2] = fbranch; + return new_exp (3, op, args); +} + +%} + +/* This declares that all operators have the same associativity and the + precedence order as in C. See [Harbison, Steele: C, A Reference Manual]. + There is no unary minus and no bitwise operators. + Operators with the same syntactic behaviour have been merged into a single + token, to save space in the array generated by bison. */ +%right '?' /* ? */ +%left '|' /* || */ +%left '&' /* && */ +%left EQUOP2 /* == != */ +%left CMPOP2 /* < > <= >= */ +%left ADDOP2 /* + - */ +%left MULOP2 /* * / % */ +%right '!' /* ! */ + +%token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2 +%token <num> NUMBER +%type <exp> exp + +%% + +start: exp + { + if ($1 == NULL) + YYABORT; + ((struct parse_args *) arg)->res = $1; + } + ; + +exp: exp '?' exp ':' exp + { + $$ = new_exp_3 (qmop, $1, $3, $5); + } + | exp '|' exp + { + $$ = new_exp_2 (lor, $1, $3); + } + | exp '&' exp + { + $$ = new_exp_2 (land, $1, $3); + } + | exp EQUOP2 exp + { + $$ = new_exp_2 ($2, $1, $3); + } + | exp CMPOP2 exp + { + $$ = new_exp_2 ($2, $1, $3); + } + | exp ADDOP2 exp + { + $$ = new_exp_2 ($2, $1, $3); + } + | exp MULOP2 exp + { + $$ = new_exp_2 ($2, $1, $3); + } + | '!' exp + { + $$ = new_exp_1 (lnot, $2); + } + | 'n' + { + $$ = new_exp_0 (var); + } + | NUMBER + { + if (($$ = new_exp_0 (num)) != NULL) + $$->val.num = $1; + } + | '(' exp ')' + { + $$ = $2; + } + ; + +%% + +void +internal_function +FREE_EXPRESSION (exp) + struct expression *exp; +{ + if (exp == NULL) + return; + + /* Handle the recursive case. */ + switch (exp->nargs) + { + case 3: + FREE_EXPRESSION (exp->val.args[2]); + /* FALLTHROUGH */ + case 2: + FREE_EXPRESSION (exp->val.args[1]); + /* FALLTHROUGH */ + case 1: + FREE_EXPRESSION (exp->val.args[0]); + /* FALLTHROUGH */ + default: + break; + } + + free (exp); +} + + +static int +yylex (lval, pexp) + YYSTYPE *lval; + const char **pexp; +{ + const char *exp = *pexp; + int result; + + while (1) + { + if (exp[0] == '\0') + { + *pexp = exp; + return YYEOF; + } + + if (exp[0] != ' ' && exp[0] != '\t') + break; + + ++exp; + } + + result = *exp++; + switch (result) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + unsigned long int n = result - '0'; + while (exp[0] >= '0' && exp[0] <= '9') + { + n *= 10; + n += exp[0] - '0'; + ++exp; + } + lval->num = n; + result = NUMBER; + } + break; + + case '=': + if (exp[0] == '=') + { + ++exp; + lval->op = equal; + result = EQUOP2; + } + else + result = YYERRCODE; + break; + + case '!': + if (exp[0] == '=') + { + ++exp; + lval->op = not_equal; + result = EQUOP2; + } + break; + + case '&': + case '|': + if (exp[0] == result) + ++exp; + else + result = YYERRCODE; + break; + + case '<': + if (exp[0] == '=') + { + ++exp; + lval->op = less_or_equal; + } + else + lval->op = less_than; + result = CMPOP2; + break; + + case '>': + if (exp[0] == '=') + { + ++exp; + lval->op = greater_or_equal; + } + else + lval->op = greater_than; + result = CMPOP2; + break; + + case '*': + lval->op = mult; + result = MULOP2; + break; + + case '/': + lval->op = divide; + result = MULOP2; + break; + + case '%': + lval->op = module; + result = MULOP2; + break; + + case '+': + lval->op = plus; + result = ADDOP2; + break; + + case '-': + lval->op = minus; + result = ADDOP2; + break; + + case 'n': + case '?': + case ':': + case '(': + case ')': + /* Nothing, just return the character. */ + break; + + case ';': + case '\n': + case '\0': + /* Be safe and let the user call this function again. */ + --exp; + result = YYEOF; + break; + + default: + result = YYERRCODE; +#if YYDEBUG != 0 + --exp; +#endif + break; + } + + *pexp = exp; + + return result; +} + + +static void +yyerror (str) + const char *str; +{ + /* Do nothing. We don't print error messages here. */ +} diff --git a/intl/ref-add.sin b/intl/ref-add.sin new file mode 100644 index 00000000..167374e3 --- /dev/null +++ b/intl/ref-add.sin @@ -0,0 +1,31 @@ +# Add this package to a list of references stored in a text file. +# +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library 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. +# +# Written by Bruno Haible <haible@clisp.cons.org>. +# +/^# Packages using this file: / { + s/# Packages using this file:// + ta + :a + s/ @PACKAGE@ / @PACKAGE@ / + tb + s/ $/ @PACKAGE@ / + :b + s/^/# Packages using this file:/ +} diff --git a/intl/ref-del.sin b/intl/ref-del.sin new file mode 100644 index 00000000..613cf37f --- /dev/null +++ b/intl/ref-del.sin @@ -0,0 +1,26 @@ +# Remove this package from a list of references stored in a text file. +# +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU Library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library 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. +# +# Written by Bruno Haible <haible@clisp.cons.org>. +# +/^# Packages using this file: / { + s/# Packages using this file:// + s/ @PACKAGE@ / / + s/^/# Packages using this file:/ +} |