diff options
Diffstat (limited to 'intl')
51 files changed, 2405 insertions, 1421 deletions
diff --git a/intl/ChangeLog b/intl/ChangeLog index 751291929..fd4940c52 100644 --- a/intl/ChangeLog +++ b/intl/ChangeLog @@ -1,4 +1,4 @@ -2004-01-29 GNU <[email protected]> +2006-07-21 GNU <[email protected]> - * Version 0.14.1 released. + * Version 0.15 released. diff --git a/intl/Makefile.in b/intl/Makefile.in index 05f15329e..c1d5fbde5 100644 --- a/intl/Makefile.in +++ b/intl/Makefile.in @@ -1,5 +1,5 @@ # Makefile for directory with message catalog handling library of GNU gettext -# Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. +# Copyright (C) 1995-1998, 2000-2006 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 @@ -13,7 +13,7 @@ # # 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, +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. PACKAGE = @PACKAGE@ @@ -24,6 +24,17 @@ SHELL = /bin/sh srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = .. + +# The VPATH variables allows builds with $builddir != $srcdir, assuming a +# 'make' program that supports VPATH (such as GNU make). This line is removed +# by autoconf automatically when "$(srcdir)" = ".". +# In this directory, the VPATH handling is particular: +# 1. If INTL_LIBTOOL_SUFFIX_PREFIX is 'l' (indicating a build with libtool), +# the .c -> .lo rules carefully use $(srcdir), so that VPATH can be omitted. +# 2. If PACKAGE = gettext-tools, VPATH _must_ be omitted, because otherwise +# 'make' does the wrong thing if GNU gettext was configured with +# "./configure --srcdir=`pwd`", namely it gets confused by the .lo and .la +# files it finds in srcdir = ../../gettext-runtime/intl. VPATH = $(srcdir) prefix = @prefix@ @@ -31,6 +42,7 @@ exec_prefix = @exec_prefix@ transform = @program_transform_name@ libdir = @libdir@ includedir = @includedir@ +datarootdir = @datarootdir@ datadir = @datadir@ localedir = $(datadir)/locale gettextsrcdir = $(datadir)/gettext/intl @@ -39,8 +51,8 @@ subdir = intl INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) +mkinstalldirs = @install_sh@ -d +mkdir_p = @mkdir_p@ l = @INTL_LIBTOOL_SUFFIX_PREFIX@ @@ -51,15 +63,19 @@ RANLIB = @RANLIB@ YACC = @INTLBISON@ -y -d YFLAGS = --name-prefix=__gettext +# -DBUILDING_LIBINTL: Change expansion of LIBINTL_DLL_EXPORTED macro. +# -DBUILDING_DLL: Change expansion of RELOCATABLE_DLL_EXPORTED macro. DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ --DLIBDIR=\"$(libdir)\" -DIN_LIBINTL \ +-DLIBDIR=\"$(libdir)\" -DBUILDING_LIBINTL -DBUILDING_DLL -DIN_LIBINTL \ -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \ -Dset_relocation_prefix=libintl_set_relocation_prefix \ -Drelocate=libintl_relocate \ -DDEPENDS_ON_LIBICONV=1 @DEFS@ CPPFLAGS = @CPPFLAGS@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ +CFLAGS = @CFLAGS@ @CFLAG_VISIBILITY@ +LDFLAGS = @LDFLAGS@ $(LDFLAGS_@WOE32DLL@) +LDFLAGS_yes = -Wl,--export-all-symbols +LDFLAGS_no = LIBS = @LIBS@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) @@ -72,6 +88,7 @@ HEADERS = \ plural-exp.h \ eval-plural.h \ localcharset.h \ + lock.h \ relocatable.h \ xsize.h \ printf-args.h printf-args.c \ @@ -85,6 +102,7 @@ SOURCES = \ dgettext.c \ gettext.c \ finddomain.c \ + hash-string.c \ loadmsgcat.c \ localealias.c \ textdomain.c \ @@ -97,12 +115,16 @@ SOURCES = \ plural.y \ plural-exp.c \ localcharset.c \ + lock.c \ relocatable.c \ + langprefs.c \ localename.c \ log.c \ printf.c \ + version.c \ osdep.c \ os2compat.c \ + intl-exports.c \ intl-compat.c OBJECTS = \ bindtextdom.$lo \ @@ -110,6 +132,7 @@ OBJECTS = \ dgettext.$lo \ gettext.$lo \ finddomain.$lo \ + hash-string.$lo \ loadmsgcat.$lo \ localealias.$lo \ textdomain.$lo \ @@ -122,14 +145,18 @@ OBJECTS = \ plural.$lo \ plural-exp.$lo \ localcharset.$lo \ + lock.$lo \ relocatable.$lo \ + langprefs.$lo \ localename.$lo \ log.$lo \ printf.$lo \ + version.$lo \ osdep.$lo \ intl-compat.$lo DISTFILES.common = Makefile.in \ -config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) +config.charset locale.alias ref-add.sin ref-del.sin export.h \ +$(HEADERS) $(SOURCES) DISTFILES.generated = plural.c DISTFILES.normal = VERSION DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc \ @@ -152,7 +179,7 @@ libintl.a libgnuintl.a: $(OBJECTS) libintl.la libgnuintl.la: $(OBJECTS) $(LIBTOOL) --mode=link \ $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ - $(OBJECTS) @LTLIBICONV@ $(LIBS) -lc \ + $(OBJECTS) @LTLIBICONV@ @INTL_MACOSX_LIBS@ $(LIBS) @LTLIBTHREAD@ -lc \ -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ -rpath $(libdir) \ -no-undefined @@ -162,9 +189,9 @@ libintl.la libgnuintl.la: $(OBJECTS) # according to the libtool documentation, section "Library interface versions". # Maintainers of other packages that include the intl directory must *not* # change these values. -LTV_CURRENT=7 +LTV_CURRENT=8 LTV_REVISION=0 -LTV_AGE=4 +LTV_AGE=0 .SUFFIXES: .SUFFIXES: .c .y .o .lo .sin .sed @@ -186,6 +213,8 @@ gettext.lo: $(srcdir)/gettext.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c finddomain.lo: $(srcdir)/finddomain.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c +hash-string.lo: $(srcdir)/hash-string.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/hash-string.c loadmsgcat.lo: $(srcdir)/loadmsgcat.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c localealias.lo: $(srcdir)/localealias.c @@ -210,14 +239,20 @@ plural-exp.lo: $(srcdir)/plural-exp.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c localcharset.lo: $(srcdir)/localcharset.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c +lock.lo: $(srcdir)/lock.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/lock.c relocatable.lo: $(srcdir)/relocatable.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c +langprefs.lo: $(srcdir)/langprefs.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/langprefs.c localename.lo: $(srcdir)/localename.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c log.lo: $(srcdir)/log.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c printf.lo: $(srcdir)/printf.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/printf.c +version.lo: $(srcdir)/version.c + $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/version.c osdep.lo: $(srcdir)/osdep.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c intl-compat.lo: $(srcdir)/intl-compat.c @@ -233,14 +268,29 @@ ref-del.sed: $(srcdir)/ref-del.sin INCLUDES = -I. -I$(srcdir) -I.. libgnuintl.h: $(srcdir)/libgnuintl.h.in - sed -e 's,@''HAVE_POSIX_PRINTF''@,@HAVE_POSIX_PRINTF@,g' \ + sed -e '/IN_LIBGLOCALE/d' \ + -e 's,@''HAVE_POSIX_PRINTF''@,@HAVE_POSIX_PRINTF@,g' \ -e 's,@''HAVE_ASPRINTF''@,@HAVE_ASPRINTF@,g' \ -e 's,@''HAVE_SNPRINTF''@,@HAVE_SNPRINTF@,g' \ -e 's,@''HAVE_WPRINTF''@,@HAVE_WPRINTF@,g' \ - < $(srcdir)/libgnuintl.h.in > libgnuintl.h - -libintl.h: libgnuintl.h - cp libgnuintl.h libintl.h + < $(srcdir)/libgnuintl.h.in \ + | if test '@WOE32DLL@' = yes; then \ + sed -e 's/extern \([^()]*\);/extern __declspec (dllimport) \1;/'; \ + else \ + cat; \ + fi \ + | sed -e 's/extern \([^"]\)/extern LIBINTL_DLL_EXPORTED \1/' \ + -e "/#define _LIBINTL_H/r $(srcdir)/export.h" \ + | sed -e 's,@''HAVE_VISIBILITY''@,@HAVE_VISIBILITY@,g' \ + > libgnuintl.h + +libintl.h: $(srcdir)/libgnuintl.h.in + sed -e '/IN_LIBGLOCALE/d' \ + -e 's,@''HAVE_POSIX_PRINTF''@,@HAVE_POSIX_PRINTF@,g' \ + -e 's,@''HAVE_ASPRINTF''@,@HAVE_ASPRINTF@,g' \ + -e 's,@''HAVE_SNPRINTF''@,@HAVE_SNPRINTF@,g' \ + -e 's,@''HAVE_WPRINTF''@,@HAVE_WPRINTF@,g' \ + < $(srcdir)/libgnuintl.h.in > libintl.h charset.alias: $(srcdir)/config.charset $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ @@ -257,7 +307,7 @@ install: install-exec install-data install-exec: all if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ $(LIBTOOL) --mode=install \ $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ @@ -271,8 +321,9 @@ install-exec: all : ; \ fi if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ + && test '@USE_INCLUDED_LIBINTL@' = no \ + && test @GLIBC2@ != no; then \ + $(mkdir_p) $(DESTDIR)$(libdir); \ $(LIBTOOL) --mode=install \ $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \ rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ @@ -283,7 +334,7 @@ install-exec: all : ; \ fi if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ + test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \ temp=$(DESTDIR)$(libdir)/t-charset.alias; \ dest=$(DESTDIR)$(libdir)/charset.alias; \ if test -f $(DESTDIR)$(libdir)/charset.alias; then \ @@ -299,7 +350,7 @@ install-exec: all rm -f $$temp; \ fi; \ fi; \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ + $(mkdir_p) $(DESTDIR)$(localedir); \ test -f $(DESTDIR)$(localedir)/locale.alias \ && orig=$(DESTDIR)$(localedir)/locale.alias \ || orig=$(srcdir)/locale.alias; \ @@ -313,7 +364,7 @@ install-exec: all fi install-data: all if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ @@ -341,24 +392,25 @@ install-strip: install installdirs: if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ else \ : ; \ fi if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ + && test '@USE_INCLUDED_LIBINTL@' = no \ + && test @GLIBC2@ != no; then \ + $(mkdir_p) $(DESTDIR)$(libdir); \ else \ : ; \ fi if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ + test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \ + $(mkdir_p) $(DESTDIR)$(localedir); \ else \ : ; \ fi if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ else \ : ; \ fi @@ -376,7 +428,8 @@ uninstall: : ; \ fi if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ + && test '@USE_INCLUDED_LIBINTL@' = no \ + && test @GLIBC2@ != no; then \ rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ else \ : ; \ @@ -419,14 +472,20 @@ info dvi ps pdf html: $(OBJECTS): ../config.h libgnuintl.h bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h -dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h +hash-string.$lo dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h dcigettext.$lo: $(srcdir)/eval-plural.h localcharset.$lo: $(srcdir)/localcharset.h +bindtextdom.$lo dcigettext.$lo finddomain.$lo loadmsgcat.$lo localealias.$lo lock.$lo log.$lo: $(srcdir)/lock.h localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h printf.$lo: $(srcdir)/printf-args.h $(srcdir)/printf-args.c $(srcdir)/printf-parse.h $(srcdir)/wprintf-parse.h $(srcdir)/xsize.h $(srcdir)/printf-parse.c $(srcdir)/vasnprintf.h $(srcdir)/vasnwprintf.h $(srcdir)/vasnprintf.c +# A bison-2.1 generated plural.c includes <libintl.h> if ENABLE_NLS. +PLURAL_DEPS_yes = libintl.h +PLURAL_DEPS_no = +plural.$lo: $(PLURAL_DEPS_@USE_INCLUDED_LIBINTL@) + tags: TAGS TAGS: $(HEADERS) $(SOURCES) @@ -478,7 +537,7 @@ dist distdir: Makefile $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - cp -p $$dir/$$file $(distdir); \ + cp -p $$dir/$$file $(distdir) || test $$file = Makefile.in || exit 1; \ done; \ fi @@ -486,7 +545,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status # This would be more efficient, but doesn't work any more with autoconf-2.57, # when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used. -# cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status +# cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/intl/VERSION b/intl/VERSION index b4b846ca7..fb7452c29 100644 --- a/intl/VERSION +++ b/intl/VERSION @@ -1 +1 @@ -GNU gettext library from gettext-0.14.1 +GNU gettext library from gettext-0.15 diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c index dcdc40085..d1b1f9028 100644 --- a/intl/bindtextdom.c +++ b/intl/bindtextdom.c @@ -1,5 +1,5 @@ /* Implementation of the bindtextdomain(3) function - Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -24,21 +24,21 @@ #include <stdlib.h> #include <string.h> +#include "gettextP.h" #ifdef _LIBC # include <libintl.h> #else # include "libgnuintl.h" #endif -#include "gettextP.h" +/* Handle multi-threaded applications. */ #ifdef _LIBC -/* We have to handle multi-threaded applications. */ # include <bits/libc-lock.h> +# define gl_rwlock_define __libc_rwlock_define +# define gl_rwlock_wrlock __libc_rwlock_wrlock +# define gl_rwlock_unlock __libc_rwlock_unlock #else -/* Provide dummy implementation if this is outside glibc. */ -# define __libc_rwlock_define(CLASS, NAME) -# define __libc_rwlock_wrlock(NAME) -# define __libc_rwlock_unlock(NAME) +# include "lock.h" #endif /* The internal variables in the standalone libintl.a must have different @@ -59,16 +59,14 @@ /* Contains the default location of the message catalogs. */ extern const char _nl_default_dirname[]; #ifdef _LIBC -extern const char _nl_default_dirname_internal[] attribute_hidden; -#else -# define INTUSE(name) name +libc_hidden_proto (_nl_default_dirname) #endif /* List with bindings of specific domains. */ extern struct binding *_nl_domain_bindings; /* Lock variable to protect the global data in the gettext implementation. */ -__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) +gl_rwlock_define (extern, _nl_state_lock attribute_hidden) /* Names for the libintl functions are a problem. They must not clash @@ -109,7 +107,7 @@ set_binding_values (const char *domainname, return; } - __libc_rwlock_wrlock (_nl_state_lock); + gl_rwlock_wrlock (_nl_state_lock); modified = 0; @@ -144,8 +142,8 @@ set_binding_values (const char *domainname, char *result = binding->dirname; if (strcmp (dirname, result) != 0) { - if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0) - result = (char *) INTUSE(_nl_default_dirname); + if (strcmp (dirname, _nl_default_dirname) == 0) + result = (char *) _nl_default_dirname; else { #if defined _LIBC || defined HAVE_STRDUP @@ -160,7 +158,7 @@ set_binding_values (const char *domainname, if (__builtin_expect (result != NULL, 1)) { - if (binding->dirname != INTUSE(_nl_default_dirname)) + if (binding->dirname != _nl_default_dirname) free (binding->dirname); binding->dirname = result; @@ -201,7 +199,6 @@ set_binding_values (const char *domainname, free (binding->codeset); binding->codeset = result; - binding->codeset_cntr++; modified = 1; } } @@ -214,7 +211,7 @@ set_binding_values (const char *domainname, { /* Simply return the default values. */ if (dirnamep) - *dirnamep = INTUSE(_nl_default_dirname); + *dirnamep = _nl_default_dirname; if (codesetp) *codesetp = NULL; } @@ -236,11 +233,11 @@ set_binding_values (const char *domainname, if (dirname == NULL) /* The default value. */ - dirname = INTUSE(_nl_default_dirname); + dirname = _nl_default_dirname; else { - if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0) - dirname = INTUSE(_nl_default_dirname); + if (strcmp (dirname, _nl_default_dirname) == 0) + dirname = _nl_default_dirname; else { char *result; @@ -263,9 +260,7 @@ set_binding_values (const char *domainname, } else /* The default value. */ - new_binding->dirname = (char *) INTUSE(_nl_default_dirname); - - new_binding->codeset_cntr = 0; + new_binding->dirname = (char *) _nl_default_dirname; if (codesetp) { @@ -287,7 +282,6 @@ set_binding_values (const char *domainname, memcpy (result, codeset, len); #endif codeset = result; - new_binding->codeset_cntr++; } *codesetp = codeset; new_binding->codeset = (char *) codeset; @@ -319,7 +313,7 @@ set_binding_values (const char *domainname, if (0) { failed_codeset: - if (new_binding->dirname != INTUSE(_nl_default_dirname)) + if (new_binding->dirname != _nl_default_dirname) free (new_binding->dirname); failed_dirname: free (new_binding); @@ -335,7 +329,7 @@ set_binding_values (const char *domainname, if (modified) ++_nl_msg_cat_cntr; - __libc_rwlock_unlock (_nl_state_lock); + gl_rwlock_unlock (_nl_state_lock); } /* Specify that the DOMAINNAME message catalog will be found diff --git a/intl/config.charset b/intl/config.charset index 43d45fb75..e8c258b3f 100755 --- a/intl/config.charset +++ b/intl/config.charset @@ -1,7 +1,7 @@ #! /bin/sh # Output a system dependent table of character encoding aliases. # -# Copyright (C) 2000-2004 Free Software Foundation, Inc. +# Copyright (C) 2000-2004, 2006 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 @@ -15,7 +15,7 @@ # # 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, +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. # # The table consists of lines of the form @@ -31,21 +31,21 @@ # The current list of GNU canonical charset names is as follows. # # name MIME? used by which systems -# ASCII, ANSI_X3.4-1968 glibc solaris freebsd darwin -# ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd darwin -# ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd darwin +# ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin +# ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd darwin +# ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd darwin # ISO-8859-3 Y glibc solaris -# ISO-8859-4 Y osf solaris freebsd darwin -# ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd darwin +# ISO-8859-4 Y osf solaris freebsd netbsd darwin +# ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd darwin # ISO-8859-6 Y glibc aix hpux solaris -# ISO-8859-7 Y glibc aix hpux irix osf solaris +# ISO-8859-7 Y glibc aix hpux irix osf solaris netbsd darwin # ISO-8859-8 Y glibc aix hpux osf solaris -# ISO-8859-9 Y glibc aix hpux irix osf solaris -# ISO-8859-13 glibc +# ISO-8859-9 Y glibc aix hpux irix osf solaris darwin +# ISO-8859-13 glibc netbsd darwin # ISO-8859-14 glibc -# ISO-8859-15 glibc aix osf solaris freebsd -# KOI8-R Y glibc solaris freebsd darwin -# KOI8-U Y glibc freebsd darwin +# ISO-8859-15 glibc aix osf solaris freebsd darwin +# KOI8-R Y glibc solaris freebsd netbsd darwin +# KOI8-U Y glibc freebsd netbsd darwin # KOI8-T glibc # CP437 dos # CP775 dos @@ -58,7 +58,7 @@ # CP862 dos # CP864 dos # CP865 dos -# CP866 freebsd darwin dos +# CP866 freebsd netbsd darwin dos # CP869 dos # CP874 woe32 dos # CP922 aix @@ -71,22 +71,22 @@ # CP1125 dos # CP1129 aix # CP1250 woe32 -# CP1251 glibc solaris darwin woe32 +# CP1251 glibc solaris netbsd darwin woe32 # CP1252 aix woe32 # CP1253 woe32 # CP1254 woe32 # CP1255 glibc woe32 # CP1256 woe32 # CP1257 woe32 -# GB2312 Y glibc aix hpux irix solaris freebsd darwin -# EUC-JP Y glibc aix hpux irix osf solaris freebsd darwin -# EUC-KR Y glibc aix hpux irix osf solaris freebsd darwin -# EUC-TW glibc aix hpux irix osf solaris -# BIG5 Y glibc aix hpux osf solaris freebsd darwin +# GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin +# EUC-JP Y glibc aix hpux irix osf solaris freebsd netbsd darwin +# EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin +# EUC-TW glibc aix hpux irix osf solaris netbsd +# BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin # BIG5-HKSCS glibc solaris # GBK glibc aix osf solaris woe32 dos -# GB18030 glibc solaris -# SHIFT_JIS Y hpux osf solaris freebsd darwin +# GB18030 glibc solaris netbsd +# SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin # JOHAB glibc solaris woe32 # TIS-620 glibc aix hpux osf solaris # VISCII Y glibc @@ -100,7 +100,7 @@ # HP-KANA8 hpux # DEC-KANJI osf # DEC-HANYU osf -# UTF-8 Y glibc aix hpux osf solaris +# UTF-8 Y glibc aix hpux osf solaris netbsd darwin # # Note: Names which are not marked as being a MIME name should not be used in # Internet protocols for information interchange (mail, news, etc.). @@ -388,6 +388,8 @@ case "$os" in 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-13 ISO-8859-13" echo "ISO8859-15 ISO-8859-15" echo "eucCN GB2312" echo "eucJP EUC-JP" @@ -396,7 +398,7 @@ case "$os" in echo "BIG5 BIG5" echo "SJIS SHIFT_JIS" ;; - darwin*) + darwin[56]*) # Darwin 6.8 doesn't have nl_langinfo(CODESET); therefore # localcharset.c falls back to using the full locale name # from the environment variables. @@ -437,6 +439,36 @@ case "$os" in echo "ja_JP.SJIS SHIFT_JIS" echo "ko_KR.EUC EUC-KR" ;; + darwin*) + # Darwin 7.5 has nl_langinfo(CODESET), but it is useless: + # - It returns the empty string when LANG is set to a locale of the + # form ll_CC, although ll_CC/LC_CTYPE is a symlink to an UTF-8 + # LC_CTYPE file. + # - The environment variables LANG, LC_CTYPE, LC_ALL are not set by + # the system; nl_langinfo(CODESET) returns "US-ASCII" in this case. + # - The documentation says: + # "... all code that calls BSD system routines should ensure + # that the const *char parameters of these routines are in UTF-8 + # encoding. All BSD system functions expect their string + # parameters to be in UTF-8 encoding and nothing else." + # It also says + # "An additional caveat is that string parameters for files, + # paths, and other file-system entities must be in canonical + # UTF-8. In a canonical UTF-8 Unicode string, all decomposable + # characters are decomposed ..." + # but this is not true: You can pass non-decomposed UTF-8 strings + # to file system functions, and it is the OS which will convert + # them to decomposed UTF-8 before accessing the file system. + # - The Apple Terminal application displays UTF-8 by default. + # - However, other applications are free to use different encodings: + # - xterm uses ISO-8859-1 by default. + # - TextEdit uses MacRoman by default. + # We prefer UTF-8 over decomposed UTF-8-MAC because one should + # minimize the use of decomposed Unicode. Unfortunately, through the + # Darwin file system, decomposed UTF-8 strings are leaked into user + # space nevertheless. + echo "* UTF-8" + ;; beos*) # BeOS has a single locale, and it has UTF-8 encoding. echo "* UTF-8" @@ -450,7 +482,7 @@ case "$os" in 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 <[email protected]>" + echo "# Juan Manuel Guerrero <[email protected]>" echo "# and Bruno Haible <[email protected]>." echo "#" echo "C ASCII" diff --git a/intl/dcgettext.c b/intl/dcgettext.c index 850acdee9..c2a63f08e 100644 --- a/intl/dcgettext.c +++ b/intl/dcgettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/dcigettext.c b/intl/dcigettext.c index 35238e2cb..583976821 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -1,5 +1,5 @@ /* Implementation of the internal dcigettext function. - Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's <string.h> to provide a prototype for mempcpy(). @@ -27,6 +27,9 @@ # include <config.h> #endif +/* NL_LOCALE_NAME does not work in glibc-2.4. Ignore it. */ +#undef HAVE_NL_LOCALE_NAME + #include <sys/types.h> #ifdef __GNUC__ @@ -87,26 +90,31 @@ extern int errno; # include <sys/param.h> #endif +#if !defined _LIBC && HAVE_NL_LOCALE_NAME +# include <langinfo.h> +#endif + #include "gettextP.h" #include "plural-exp.h" #ifdef _LIBC # include <libintl.h> #else +# ifdef IN_LIBGLOCALE +# include <libintl.h> +# endif # include "libgnuintl.h" #endif #include "hash-string.h" -/* Thread safetyness. */ +/* Handle multi-threaded applications. */ #ifdef _LIBC # include <bits/libc-lock.h> +# define gl_rwlock_define_initialized __libc_rwlock_define_initialized +# define gl_rwlock_rdlock __libc_rwlock_rdlock +# define gl_rwlock_wrlock __libc_rwlock_wrlock +# define gl_rwlock_unlock __libc_rwlock_unlock #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) +# include "lock.h" #endif /* Alignment of types. */ @@ -200,8 +208,8 @@ static void *mempcpy (void *dest, const void *src, size_t n); 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 */ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Win32, Cygwin, OS/2, DOS */ # define ISSLASH(C) ((C) == '/' || (C) == '\\') # define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ @@ -216,16 +224,31 @@ static void *mempcpy (void *dest, const void *src, size_t n); # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) #endif +/* Whether to support different locales in different threads. */ +#if defined _LIBC || HAVE_NL_LOCALE_NAME || (HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS) || defined IN_LIBGLOCALE +# define HAVE_PER_THREAD_LOCALE +#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; + const char *domainname; /* The category. */ int category; +#ifdef HAVE_PER_THREAD_LOCALE + /* Name of the relevant locale category, or "" for the global locale. */ + const char *localename; +#endif + +#ifdef IN_LIBGLOCALE + /* The character encoding. */ + const char *encoding; +#endif + /* State of the catalog counter at the point the string was found. */ int counter; @@ -245,6 +268,8 @@ struct known_translation_t #if defined HAVE_TSEARCH || defined _LIBC # include <search.h> +gl_rwlock_define_initialized (static, tree_lock) + static void *root; # ifdef _LIBC @@ -267,57 +292,86 @@ transcmp (const void *p1, const void *p2) { 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; + { +#ifdef HAVE_PER_THREAD_LOCALE + result = strcmp (s1->localename, s2->localename); + if (result == 0) +#endif + { +#ifdef IN_LIBGLOCALE + result = strcmp (s1->encoding, s2->encoding); + if (result == 0) +#endif + /* 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 -#ifndef INTVARDEF -# define INTVARDEF(name) -#endif -#ifndef INTUSE -# define INTUSE(name) name -#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[] attribute_hidden = "messages"; +#ifndef IN_LIBGLOCALE /* Value used as the default domain for gettext(3). */ const char *_nl_current_default_domain attribute_hidden = _nl_default_default_domain; +#endif /* Contains the default location of the message catalogs. */ #if defined __EMX__ extern const char _nl_default_dirname[]; #else +# ifdef _LIBC +extern const char _nl_default_dirname[]; +libc_hidden_proto (_nl_default_dirname) +# endif const char _nl_default_dirname[] = LOCALEDIR; -INTVARDEF (_nl_default_dirname) +# ifdef _LIBC +libc_hidden_data_def (_nl_default_dirname) +# endif #endif +#ifndef IN_LIBGLOCALE /* List with bindings of specific domains created by bindtextdomain() calls. */ struct binding *_nl_domain_bindings; +#endif /* Prototypes for local functions. */ static char *plural_lookup (struct loaded_l10nfile *domain, unsigned long int n, const char *translation, size_t translation_len) internal_function; + +#ifdef IN_LIBGLOCALE +static const char *guess_category_value (int category, + const char *categoryname, + const char *localename) + internal_function; +#else static const char *guess_category_value (int category, const char *categoryname) internal_function; +#endif + #ifdef _LIBC # include "../locale/localeinfo.h" -# define category_to_name(category) _nl_category_names[category] +# define category_to_name(category) \ + _nl_category_names.str + _nl_category_name_idxs[category] #else static const char *category_to_name (int category) internal_function; #endif +#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE +static const char *get_output_charset (struct binding *domainbinding) + internal_function; +#endif /* For those loosing systems which don't have `alloca' we have to add @@ -383,9 +437,7 @@ typedef unsigned char transmem_block_t; #endif /* Lock variable to protect the global data in the gettext implementation. */ -#ifdef _LIBC -__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden) -#endif +gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden) /* Checking whether the binaries runs SUID must be done and glibc provides easier methods therefore we make a difference here. */ @@ -423,9 +475,18 @@ static int enable_secure; /* 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. */ +#ifdef IN_LIBGLOCALE +char * +gl_dcigettext (const char *domainname, + const char *msgid1, const char *msgid2, + int plural, unsigned long int n, + int category, + const char *localename, const char *encoding) +#else char * DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, int plural, unsigned long int n, int category) +#endif { #ifndef HAVE_ALLOCA struct block_list *block_list = NULL; @@ -434,7 +495,8 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, struct binding *binding; const char *categoryname; const char *categoryvalue; - char *dirname, *xdomainname; + const char *dirname; + char *xdomainname; char *single_locale; char *retval; size_t retlen; @@ -443,6 +505,9 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, struct known_translation_t *search; struct known_translation_t **foundp = NULL; size_t msgid_len; +# if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE + const char *localename; +# endif #endif size_t domainname_len; @@ -459,7 +524,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, : n == 1 ? (char *) msgid1 : (char *) msgid2); #endif - __libc_rwlock_rdlock (_nl_state_lock); + gl_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 @@ -481,10 +546,45 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, 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->domainname = domainname; search->category = category; +# ifdef HAVE_PER_THREAD_LOCALE +# ifndef IN_LIBGLOCALE +# ifdef _LIBC + localename = __current_locale_name (category); +# else +# if HAVE_NL_LOCALE_NAME + /* NL_LOCALE_NAME is public glibc API introduced in glibc-2.4. */ + localename = nl_langinfo (NL_LOCALE_NAME (category)); +# else +# if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS + /* The __names field is not public glibc API and must therefore not be used + in code that is installed in public locations. */ + { + locale_t thread_locale = uselocale (NULL); + if (thread_locale != LC_GLOBAL_LOCALE) + localename = thread_locale->__names[category]; + else + localename = ""; + } +# endif +# endif +# endif +# endif + search->localename = localename; +# ifdef IN_LIBGLOCALE + search->encoding = encoding; +# endif +# endif + + /* Since tfind/tsearch manage a balanced tree, concurrent tfind and + tsearch calls can be fatal. */ + gl_rwlock_rdlock (tree_lock); foundp = (struct known_translation_t **) tfind (search, &root, transcmp); + + gl_rwlock_unlock (tree_lock); + freea (search); if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) { @@ -495,7 +595,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, else retval = (char *) (*foundp)->translation; - __libc_rwlock_unlock (_nl_state_lock); + gl_rwlock_unlock (_nl_state_lock); return retval; } #endif @@ -507,6 +607,12 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, DETERMINE_SECURE; /* First find matching binding. */ +#ifdef IN_LIBGLOCALE + /* We can use a trivial binding, since _nl_find_msg will ignore it anyway, + and _nl_load_domain and _nl_find_domain just pass it through. */ + binding = NULL; + dirname = bindtextdomain (domainname, NULL); +#else for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next) { int compare = strcmp (domainname, binding->domainname); @@ -522,44 +628,55 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, } if (binding == NULL) - dirname = (char *) INTUSE(_nl_default_dirname); - else if (IS_ABSOLUTE_PATH (binding->dirname)) - dirname = binding->dirname; + dirname = _nl_default_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; + dirname = binding->dirname; +#endif + if (!IS_ABSOLUTE_PATH (dirname)) + { + /* We have a relative path. Make it absolute now. */ + size_t dirname_len = strlen (dirname) + 1; + size_t path_max; + char *resolved_dirname; + char *ret; - path_max = (unsigned int) PATH_MAX; - path_max += 2; /* The getcwd docs say to do this. */ + 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); + for (;;) + { + resolved_dirname = (char *) alloca (path_max + dirname_len); + ADD_BLOCK (block_list, tmp_dirname); - __set_errno (0); - ret = getcwd (dirname, path_max); - if (ret != NULL || errno != ERANGE) - break; + __set_errno (0); + ret = getcwd (resolved_dirname, path_max); + if (ret != NULL || errno != ERANGE) + break; - path_max += path_max / 2; - path_max += PATH_INCR; - } + 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. */ - goto return_untranslated; + if (ret == NULL) + /* We cannot get the current working directory. Don't signal an + error but simply return the default string. */ + goto return_untranslated; - stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname); + stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname); + dirname = resolved_dirname; + } +#ifndef IN_LIBGLOCALE } +#endif /* Now determine the symbolic name of CATEGORY and its value. */ categoryname = category_to_name (category); +#ifdef IN_LIBGLOCALE + categoryvalue = guess_category_value (category, categoryname, localename); +#else categoryvalue = guess_category_value (category, categoryname); +#endif domainname_len = strlen (domainname); xdomainname = (char *) alloca (strlen (categoryname) @@ -617,7 +734,11 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, if (domain != NULL) { - retval = _nl_find_msg (domain, binding, msgid1, &retlen); +#if defined IN_LIBGLOCALE + retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen); +#else + retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen); +#endif if (retval == NULL) { @@ -625,8 +746,13 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, for (cnt = 0; domain->successor[cnt] != NULL; ++cnt) { +#if defined IN_LIBGLOCALE + retval = _nl_find_msg (domain->successor[cnt], binding, + encoding, msgid1, &retlen); +#else retval = _nl_find_msg (domain->successor[cnt], binding, - msgid1, &retlen); + msgid1, 1, &retlen); +#endif if (retval != NULL) { @@ -636,6 +762,12 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, } } + /* Returning -1 means that some resource problem exists + (likely memory) and that the strings could not be + converted. Return the original strings. */ + if (__builtin_expect (retval == (char *) -1, 0)) + break; + if (retval != NULL) { /* Found the translation of MSGID1 in domain DOMAIN: @@ -645,25 +777,49 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, if (foundp == NULL) { /* Create a new entry and add it to the search tree. */ + size_t size; struct known_translation_t *newp; - newp = (struct known_translation_t *) - malloc (offsetof (struct known_translation_t, msgid) - + msgid_len + domainname_len + 1); + size = offsetof (struct known_translation_t, msgid) + + msgid_len + domainname_len + 1; +# ifdef HAVE_PER_THREAD_LOCALE + size += strlen (localename) + 1; +# endif + newp = (struct known_translation_t *) malloc (size); if (newp != NULL) { - newp->domainname = - mempcpy (newp->msgid, msgid1, msgid_len); - memcpy (newp->domainname, domainname, domainname_len + 1); + char *new_domainname; +# ifdef HAVE_PER_THREAD_LOCALE + char *new_localename; +# endif + + new_domainname = mempcpy (newp->msgid, msgid1, msgid_len); + memcpy (new_domainname, domainname, domainname_len + 1); +# ifdef HAVE_PER_THREAD_LOCALE + new_localename = new_domainname + domainname_len + 1; + strcpy (new_localename, localename); +# endif + newp->domainname = new_domainname; newp->category = category; +# ifdef HAVE_PER_THREAD_LOCALE + newp->localename = new_localename; +# endif +# ifdef IN_LIBGLOCALE + newp->encoding = encoding; +# endif newp->counter = _nl_msg_cat_cntr; newp->domain = domain; newp->translation = retval; newp->translation_length = retlen; + gl_rwlock_wrlock (tree_lock); + /* Insert the entry in the search tree. */ foundp = (struct known_translation_t **) tsearch (newp, &root, transcmp); + + gl_rwlock_unlock (tree_lock); + if (foundp == NULL || __builtin_expect (*foundp != newp, 0)) /* The insert failed. */ @@ -685,7 +841,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, if (plural) retval = plural_lookup (domain, n, retval, retlen); - __libc_rwlock_unlock (_nl_state_lock); + gl_rwlock_unlock (_nl_state_lock); return retval; } } @@ -694,7 +850,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, return_untranslated: /* Return the untranslated MSGID. */ FREE_BLOCKS (block_list); - __libc_rwlock_unlock (_nl_state_lock); + gl_rwlock_unlock (_nl_state_lock); #ifndef _LIBC if (!ENABLE_SECURE) { @@ -716,11 +872,24 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, } +/* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING. + Return it if found. Return NULL if not found or in case of a conversion + failure (problem in the particular message catalog). Return (char *) -1 + in case of a memory allocation failure during conversion (only if + ENCODING != NULL resp. CONVERT == true). */ char * internal_function +#ifdef IN_LIBGLOCALE _nl_find_msg (struct loaded_l10nfile *domain_file, - struct binding *domainbinding, const char *msgid, + struct binding *domainbinding, const char *encoding, + const char *msgid, size_t *lengthp) +#else +_nl_find_msg (struct loaded_l10nfile *domain_file, + struct binding *domainbinding, + const char *msgid, int convert, + size_t *lengthp) +#endif { struct loaded_domain *domain; nls_uint32 nstrings; @@ -728,7 +897,7 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, char *result; size_t resultlen; - if (domain_file->decided == 0) + if (domain_file->decided <= 0) _nl_load_domain (domain_file, domainbinding); if (domain_file->data == NULL) @@ -743,7 +912,7 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, { /* Use the hashing table. */ nls_uint32 len = strlen (msgid); - nls_uint32 hash_val = hash_string (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)); @@ -826,195 +995,345 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, } #if defined _LIBC || HAVE_ICONV - if (domain->codeset_cntr - != (domainbinding != NULL ? domainbinding->codeset_cntr : 0)) +# ifdef IN_LIBGLOCALE + if (encoding != NULL) +# else + if (convert) +# endif { - /* 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); - } + /* We are supposed to do a conversion. */ +# ifndef IN_LIBGLOCALE + const char *encoding = get_output_charset (domainbinding); +# endif + + /* Search whether a table with converted translations for this + encoding has already been allocated. */ + size_t nconversions = domain->nconversions; + struct converted_domain *convd = NULL; + size_t i; + + for (i = nconversions; i > 0; ) + { + i--; + if (strcmp (domain->conversions[i].encoding, encoding) == 0) + { + convd = &domain->conversions[i]; + break; + } + } - if ( + if (convd == NULL) + { + /* Allocate a table for the converted translations for this + encoding. */ + struct converted_domain *new_conversions = + (struct converted_domain *) + (domain->conversions != NULL + ? realloc (domain->conversions, + (nconversions + 1) * sizeof (struct converted_domain)) + : malloc ((nconversions + 1) * sizeof (struct converted_domain))); + + if (__builtin_expect (new_conversions == NULL, 0)) + /* Nothing we can do, no more memory. We cannot use the + translation because it might be encoded incorrectly. */ + return (char *) -1; + + domain->conversions = new_conversions; + + /* Copy the 'encoding' string to permanent storage. */ + encoding = strdup (encoding); + if (__builtin_expect (encoding == NULL, 0)) + /* Nothing we can do, no more memory. We cannot use the + translation because it might be encoded incorrectly. */ + return (char *) -1; + + convd = &new_conversions[nconversions]; + convd->encoding = encoding; + + /* Find out about the character set the file is encoded with. + This can be found (in textual form) in the entry "". If this + entry does not exist or if this does not contain the 'charset=' + information, we will assume the charset matches the one the + current locale and we don't have to perform any conversion. */ # ifdef _LIBC - domain->conv != (__gconv_t) -1 + convd->conv = (__gconv_t) -1; # else # if HAVE_ICONV - domain->conv != (iconv_t) -1 + convd->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 (nstrings + domain->n_sysdep_strings, - 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) + { + char *nullentry; + size_t nullentrylen; + + /* Get the header entry. This is a recursion, but it doesn't + reallocate domain->conversions because we pass + encoding = NULL or convert = 0, respectively. */ + nullentry = +# ifdef IN_LIBGLOCALE + _nl_find_msg (domain_file, domainbinding, NULL, "", + &nullentrylen); +# else + _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen); +# endif + + if (nullentry != NULL) + { + const char *charsetstr; + + charsetstr = strstr (nullentry, "charset="); + if (charsetstr != NULL) + { + size_t len; + char *charset; + const char *outcharset; + + charsetstr += strlen ("charset="); + len = strcspn (charsetstr, " \t\n"); + + charset = (char *) alloca (len + 1); +# if defined _LIBC || HAVE_MEMPCPY + *((char *) mempcpy (charset, charsetstr, len)) = '\0'; +# else + memcpy (charset, charsetstr, len); + charset[len] = '\0'; +# endif + + outcharset = encoding; + +# ifdef _LIBC + /* We always want to use transliteration. */ + outcharset = norm_add_slashes (outcharset, "TRANSLIT"); + charset = norm_add_slashes (charset, ""); + int r = __gconv_open (outcharset, charset, &convd->conv, + GCONV_AVOID_NOCONV); + if (__builtin_expect (r != __GCONV_OK, 0)) + { + /* If the output encoding is the same there is + nothing to do. Otherwise do not use the + translation at all. */ + if (__builtin_expect (r != __GCONV_NOCONV, 1)) + return NULL; + + convd->conv = (__gconv_t) -1; + } +# else +# if HAVE_ICONV + /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, + we want to use transliteration. */ +# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \ + || _LIBICONV_VERSION >= 0x0105 + if (strchr (outcharset, '/') == NULL) + { + char *tmp; + + len = strlen (outcharset); + tmp = (char *) alloca (len + 10 + 1); + memcpy (tmp, outcharset, len); + memcpy (tmp + len, "//TRANSLIT", 10 + 1); + outcharset = tmp; + + convd->conv = iconv_open (outcharset, charset); + + freea (outcharset); + } + else +# endif + convd->conv = iconv_open (outcharset, charset); +# endif +# endif + + freea (charset); + } + } + } + convd->conv_tab = NULL; + /* Here domain->conversions is still == new_conversions. */ + domain->nconversions++; + } + + if ( +# ifdef _LIBC + convd->conv != (__gconv_t) -1 +# else +# if HAVE_ICONV + convd->conv != (iconv_t) -1 +# endif +# endif + ) { - /* 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) + /* 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 (convd->conv_tab == NULL + && ((convd->conv_tab = + (char **) calloc (nstrings + domain->n_sysdep_strings, + sizeof (char *))) + == NULL)) + /* Mark that we didn't succeed allocating a table. */ + convd->conv_tab = (char **) -1; + + if (__builtin_expect (convd->conv_tab == (char **) -1, 0)) + /* Nothing we can do, no more memory. We cannot use the + translation because it might be encoded incorrectly. */ + return (char *) -1; + + if (convd->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; + static unsigned char *freemem; + static size_t freemem_size; - const unsigned char *inbuf; - unsigned char *outbuf; - int malloc_count; + const unsigned char *inbuf; + unsigned char *outbuf; + int malloc_count; # ifndef _LIBC - transmem_block_t *transmem_list = NULL; + transmem_block_t *transmem_list = NULL; # endif - __libc_lock_lock (lock); + __libc_lock_lock (lock); - inbuf = (const unsigned char *) result; - outbuf = freemem + sizeof (size_t); + inbuf = (const unsigned char *) result; + outbuf = freemem + sizeof (size_t); - malloc_count = 0; - while (1) - { - transmem_block_t *newmem; + malloc_count = 0; + while (1) + { + transmem_block_t *newmem; # ifdef _LIBC - size_t non_reversible; - int res; + size_t non_reversible; + int res; - if (freemem_size < sizeof (size_t)) - goto resize_freemem; + 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); + res = __gconv (convd->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_OK || res == __GCONV_EMPTY_INPUT) + break; - if (res != __GCONV_FULL_OUTPUT) - { - __libc_lock_unlock (lock); - goto converted; - } + if (res != __GCONV_FULL_OUTPUT) + { + /* We should not use the translation at all, it + is incorrectly encoded. */ + __libc_lock_unlock (lock); + return NULL; + } - inbuf = result; + inbuf = (const unsigned char *) 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; - } + 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 (convd->conv, + (ICONV_CONST char **) &inptr, &inleft, + &outptr, &outleft) + != (size_t) (-1)) + { + outbuf = (unsigned char *) outptr; + break; + } + if (errno != E2BIG) + { + __libc_lock_unlock (lock); + return NULL; + } # 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); + 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; + if (newmem != NULL) + transmem_list = transmem_list->next; + else + { + struct transmem_list *old = transmem_list; + + transmem_list = transmem_list->next; + free (old); + } +# endif + } else { - struct transmem_list *old = transmem_list; - - transmem_list = transmem_list->next; - free (old); + 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); + return (char *) -1; } -# 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; + /* 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); + freemem = (unsigned char *) newmem->data; + freemem_size -= offsetof (struct transmem_list, data); # else - transmem_list = newmem; - freemem = newmem; + transmem_list = newmem; + freemem = newmem; # endif - outbuf = freemem + sizeof (size_t); + 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); + convd->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); } - /* 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 convd->conv_tab[act] contains the translation of all + the plural variants. */ + result = convd->conv_tab[act] + sizeof (size_t); + resultlen = *(size_t *) convd->conv_tab[act]; } - - /* 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 */ @@ -1122,31 +1441,73 @@ category_to_name (int category) } #endif -/* Guess value of current locale from value of the environment variables. */ +/* Guess value of current locale from value of the environment variables + or system-dependent defaults. */ static const char * internal_function +#ifdef IN_LIBGLOCALE +guess_category_value (int category, const char *categoryname, + const char *locale) + +#else guess_category_value (int category, const char *categoryname) +#endif { 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; +#ifndef IN_LIBGLOCALE + const char *locale; +# ifndef _LIBC + const char *language_default; + int locale_defaulted; +# endif +#endif - /* We have to proceed with the POSIX methods of looking to `LC_ALL', + /* We use the settings in the following order: + 1. The value of the environment variable 'LANGUAGE'. This is a GNU + extension. Its value can be a colon-separated list of locale names. + 2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'. + More precisely, the first among these that is set to a non-empty value. + This is how POSIX specifies it. The value is a single locale name. + 3. A system-dependent preference list of languages. Its value can be a + colon-separated list of locale names. + 4. A system-dependent default locale name. + This way: + - System-dependent settings can be overridden by environment variables. + - If the system provides both a list of languages and a default locale, + the former is used. */ + +#ifndef IN_LIBGLOCALE + /* Fetch the locale name, through the POSIX method of looking to `LC_ALL', `LC_xxx', and `LANG'. On some systems this can be done by the `setlocale' function itself. */ -#ifdef _LIBC - retval = __current_locale_name (category); -#else - retval = _nl_locale_name (category, categoryname); +# ifdef _LIBC + locale = __current_locale_name (category); +# else +# if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS + /* The __names field is not public glibc API and must therefore not be used + in code that is installed in public locations. */ + locale_t thread_locale = uselocale (NULL); + if (thread_locale != LC_GLOBAL_LOCALE) + { + locale = thread_locale->__names[category]; + locale_defaulted = 0; + } + else +# endif + { + locale = _nl_locale_name_posix (category, categoryname); + locale_defaulted = 0; + if (locale == NULL) + { + locale = _nl_locale_name_default (); + locale_defaulted = 1; + } + } +# endif #endif - /* Ignore LANGUAGE if the locale is set to "C" because + /* Ignore LANGUAGE and its system-dependent analogon if the locale is set + to "C" because 1. "C" locale usually uses the ASCII encoding, and most international messages use non-ASCII characters. These characters get displayed as question marks (if using glibc's iconv()) or as invalid 8-bit @@ -1154,9 +1515,83 @@ guess_category_value (int category, const char *categoryname) characters to ASCII). In any case, the output is ugly. 2. The precise output of some programs in the "C" locale is specified by POSIX and should not depend on environment variables like - "LANGUAGE". We allow such programs to use gettext(). */ - return language != NULL && strcmp (retval, "C") != 0 ? language : retval; + "LANGUAGE" or system-dependent information. We allow such programs + to use gettext(). */ + if (strcmp (locale, "C") == 0) + return locale; + + /* The highest priority value is the value of the 'LANGUAGE' environment + variable. */ + language = getenv ("LANGUAGE"); + if (language != NULL && language[0] != '\0') + return language; +#if !defined IN_LIBGLOCALE && !defined _LIBC + /* The next priority value is the locale name, if not defaulted. */ + if (locale_defaulted) + { + /* The next priority value is the default language preferences list. */ + language_default = _nl_language_preferences_default (); + if (language_default != NULL) + return language_default; + } + /* The least priority value is the locale name, if defaulted. */ +#endif + return locale; +} + +#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE +/* Returns the output charset. */ +static const char * +internal_function +get_output_charset (struct binding *domainbinding) +{ + /* The output charset should normally be determined by the locale. But + sometimes the locale is not used or not correctly set up, so we provide + a possibility for the user to override this: the OUTPUT_CHARSET + environment variable. Moreover, the value specified through + bind_textdomain_codeset overrides both. */ + if (domainbinding != NULL && domainbinding->codeset != NULL) + return domainbinding->codeset; + else + { + /* For speed reasons, we look at the value of OUTPUT_CHARSET only + once. This is a user variable that is not supposed to change + during a program run. */ + static char *output_charset_cache; + static int output_charset_cached; + + if (!output_charset_cached) + { + const char *value = getenv ("OUTPUT_CHARSET"); + + if (value != NULL && value[0] != '\0') + { + size_t len = strlen (value) + 1; + char *value_copy = (char *) malloc (len); + + if (value_copy != NULL) + memcpy (value_copy, value, len); + output_charset_cache = value_copy; + } + output_charset_cached = 1; + } + + if (output_charset_cache != NULL) + return output_charset_cache; + else + { +# ifdef _LIBC + return _NL_CURRENT (LC_CTYPE, CODESET); +# else +# if HAVE_ICONV + extern const char *locale_charset (void); + return locale_charset (); +# endif +# endif + } + } } +#endif /* @@ begin of epilog @@ */ @@ -1194,7 +1629,7 @@ libc_freeres_fn (free_mem) { struct binding *oldp = _nl_domain_bindings; _nl_domain_bindings = _nl_domain_bindings->next; - if (oldp->dirname != INTUSE(_nl_default_dirname)) + if (oldp->dirname != _nl_default_dirname) /* Yes, this is a pointer comparison. */ free (oldp->dirname); free (oldp->codeset); diff --git a/intl/dcngettext.c b/intl/dcngettext.c index 48a3e09e0..eb368336c 100644 --- a/intl/dcngettext.c +++ b/intl/dcngettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/dgettext.c b/intl/dgettext.c index b64b0f5d3..9b0d0de6c 100644 --- a/intl/dgettext.c +++ b/intl/dgettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/dngettext.c b/intl/dngettext.c index 7815637f0..3278438fe 100644 --- a/intl/dngettext.c +++ b/intl/dngettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/eval-plural.h b/intl/eval-plural.h index 01bd5af5f..dacd003db 100644 --- a/intl/eval-plural.h +++ b/intl/eval-plural.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef STATIC diff --git a/intl/explodename.c b/intl/explodename.c index 52c25e727..8d3e1463d 100644 --- a/intl/explodename.c +++ b/intl/explodename.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-1998, 2000-2001, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1995-1998, 2000-2001, 2003, 2005 Free Software Foundation, Inc. Contributed by Ulrich Drepper <[email protected]>, 1995. This program is free software; you can redistribute it and/or modify it @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -37,11 +37,15 @@ /* @@ end of prolog @@ */ -char * +/* Split a locale name NAME into a leading language part and all the + rest. Return a pointer to the first character after the language, + i.e. to the first byte of the rest. */ +static char *_nl_find_language (const char *name); + +static char * _nl_find_language (const char *name) { - while (name[0] != '\0' && name[0] != '_' && name[0] != '@' - && name[0] != '+' && name[0] != ',') + while (name[0] != '\0' && name[0] != '_' && name[0] != '@' && name[0] != '.') ++name; return (char *) name; @@ -52,10 +56,8 @@ int _nl_explode_name (char *name, const char **language, const char **modifier, const char **territory, const char **codeset, - const char **normalized_codeset, const char **special, - const char **sponsor, const char **revision) + const char **normalized_codeset) { - enum { undecided, xpg, cen } syntax; char *cp; int mask; @@ -63,15 +65,10 @@ _nl_explode_name (char *name, *territory = NULL; *codeset = NULL; *normalized_codeset = NULL; - *special = NULL; - *sponsor = NULL; - *revision = NULL; /* Now we determine the single parts of the locale name. First - look for the language. Termination symbols are `_' and `@' if - we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ + look for the language. Termination symbols are `_', '.', and `@'. */ mask = 0; - syntax = undecided; *language = cp = name; cp = _nl_find_language (*language); @@ -79,22 +76,23 @@ _nl_explode_name (char *name, /* This does not make sense: language has to be specified. Use this entry as it is without exploding. Perhaps it is an alias. */ cp = strchr (*language, '\0'); - else if (cp[0] == '_') + else { - /* Next is the territory. */ - cp[0] = '\0'; - *territory = ++cp; + if (cp[0] == '_') + { + /* Next is the territory. */ + cp[0] = '\0'; + *territory = ++cp; - while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@' - && cp[0] != '+' && cp[0] != ',' && cp[0] != '_') - ++cp; + while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@') + ++cp; - mask |= TERRITORY; + mask |= XPG_TERRITORY; + } if (cp[0] == '.') { /* Next is the codeset. */ - syntax = xpg; cp[0] = '\0'; *codeset = ++cp; @@ -115,71 +113,21 @@ _nl_explode_name (char *name, } } - if (cp[0] == '@' || (syntax != xpg && cp[0] == '+')) + if (cp[0] == '@') { /* Next is the modifier. */ - syntax = cp[0] == '@' ? xpg : cen; cp[0] = '\0'; *modifier = ++cp; - while (syntax == cen && cp[0] != '\0' && cp[0] != '+' - && cp[0] != ',' && cp[0] != '_') - ++cp; - - mask |= XPG_MODIFIER | CEN_AUDIENCE; - } - - if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_')) - { - syntax = cen; - - if (cp[0] == '+') - { - /* Next is special application (CEN syntax). */ - cp[0] = '\0'; - *special = ++cp; - - while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_') - ++cp; - - mask |= CEN_SPECIAL; - } - - if (cp[0] == ',') - { - /* Next is sponsor (CEN syntax). */ - cp[0] = '\0'; - *sponsor = ++cp; - - while (cp[0] != '\0' && cp[0] != '_') - ++cp; - - mask |= CEN_SPONSOR; - } - - if (cp[0] == '_') - { - /* Next is revision (CEN syntax). */ - cp[0] = '\0'; - *revision = ++cp; - - mask |= CEN_REVISION; - } + if (cp[0] != '\0') + mask |= XPG_MODIFIER; } - /* For CEN syntax values it might be important to have the - separator character in the file name, not for XPG syntax. */ - if (syntax == xpg) - { - if (*territory != NULL && (*territory)[0] == '\0') - mask &= ~TERRITORY; - - if (*codeset != NULL && (*codeset)[0] == '\0') - mask &= ~XPG_CODESET; + if (*territory != NULL && (*territory)[0] == '\0') + mask &= ~XPG_TERRITORY; - if (*modifier != NULL && (*modifier)[0] == '\0') - mask &= ~XPG_MODIFIER; - } + if (*codeset != NULL && (*codeset)[0] == '\0') + mask &= ~XPG_CODESET; return mask; } diff --git a/intl/finddomain.c b/intl/finddomain.c index 4992a8c9e..a25bebcb9 100644 --- a/intl/finddomain.c +++ b/intl/finddomain.c @@ -1,5 +1,5 @@ /* Handle list of needed message catalogs - Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2001, 2003-2006 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 1995. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -37,6 +37,17 @@ # include "libgnuintl.h" #endif +/* Handle multi-threaded applications. */ +#ifdef _LIBC +# include <bits/libc-lock.h> +# define gl_rwlock_define_initialized __libc_rwlock_define_initialized +# define gl_rwlock_rdlock __libc_rwlock_rdlock +# define gl_rwlock_wrlock __libc_rwlock_wrlock +# define gl_rwlock_unlock __libc_rwlock_unlock +#else +# include "lock.h" +#endif + /* @@ end of prolog @@ */ /* List of already loaded domains. */ static struct loaded_l10nfile *_nl_loaded_domains; @@ -56,44 +67,41 @@ _nl_find_domain (const char *dirname, char *locale, const char *territory; const char *codeset; const char *normalized_codeset; - const char *special; - const char *sponsor; - const char *revision; const char *alias_value; int mask; /* LOCALE can consist of up to four recognized parts for the XPG syntax: - language[_territory[.codeset]][@modifier] - - and six parts for the CEN syntax: - - language[_territory][+audience][+special][,[sponsor][_revision]] + language[_territory][.codeset][@modifier] Beside the first part all of them are allowed to be missing. If the full specified locale is not found, the less specific one are looked for. The various parts will be stripped off according to the following order: - (1) revision - (2) sponsor - (3) special - (4) codeset - (5) normalized codeset - (6) territory - (7) audience/modifier + (1) codeset + (2) normalized codeset + (3) territory + (4) modifier */ + /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ + gl_rwlock_define_initialized (static, lock); + gl_rwlock_rdlock (lock); + /* If we have already tested for this locale entry there has to be one data set in the list of loaded domains. */ retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, strlen (dirname) + 1, 0, locale, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, domainname, 0); + NULL, NULL, domainname, 0); + + gl_rwlock_unlock (lock); + if (retval != NULL) { /* We know something about this locale. */ int cnt; - if (retval->decided == 0) + if (retval->decided <= 0) _nl_load_domain (retval, domainbinding); if (retval->data != NULL) @@ -101,13 +109,14 @@ _nl_find_domain (const char *dirname, char *locale, for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) { - if (retval->successor[cnt]->decided == 0) + if (retval->successor[cnt]->decided <= 0) _nl_load_domain (retval->successor[cnt], domainbinding); if (retval->successor[cnt]->data != NULL) break; } - return cnt >= 0 ? retval : NULL; + + return retval; /* NOTREACHED */ } @@ -132,30 +141,34 @@ _nl_find_domain (const char *dirname, char *locale, } /* Now we determine the single parts of the locale name. First - look for the language. Termination symbols are `_' and `@' if - we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ + look for the language. Termination symbols are `_', '.', and `@'. */ mask = _nl_explode_name (locale, &language, &modifier, &territory, - &codeset, &normalized_codeset, &special, - &sponsor, &revision); + &codeset, &normalized_codeset); + + /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ + gl_rwlock_wrlock (lock); /* Create all possible locale entries which might be interested in generalization. */ retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, strlen (dirname) + 1, mask, language, territory, - codeset, normalized_codeset, modifier, special, - sponsor, revision, domainname, 1); + codeset, normalized_codeset, modifier, + domainname, 1); + + gl_rwlock_unlock (lock); + if (retval == NULL) /* This means we are out of core. */ return NULL; - if (retval->decided == 0) + if (retval->decided <= 0) _nl_load_domain (retval, domainbinding); if (retval->data == NULL) { int cnt; for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) { - if (retval->successor[cnt]->decided == 0) + if (retval->successor[cnt]->decided <= 0) _nl_load_domain (retval->successor[cnt], domainbinding); if (retval->successor[cnt]->data != NULL) break; @@ -175,7 +188,10 @@ _nl_find_domain (const char *dirname, char *locale, #ifdef _LIBC -libc_freeres_fn (free_mem) +/* This is called from iconv/gconv_db.c's free_mem, as locales must + be freed before freeing gconv steps arrays. */ +void __libc_freeres_fn_section +_nl_finddomain_subfreeres () { struct loaded_l10nfile *runp = _nl_loaded_domains; diff --git a/intl/gettext.c b/intl/gettext.c index 92c42faa7..d82d439c0 100644 --- a/intl/gettext.c +++ b/intl/gettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/gettextP.h b/intl/gettextP.h index 4d66c3de3..8be38d2d7 100644 --- a/intl/gettextP.h +++ b/intl/gettextP.h @@ -1,5 +1,5 @@ /* Header describing internals of libintl library. - Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2005 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 1995. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GETTEXTP_H @@ -30,6 +30,52 @@ # endif #endif +#ifdef _LIBC +extern char *__gettext (const char *__msgid); +extern char *__dgettext (const char *__domainname, const char *__msgid); +extern char *__dcgettext (const char *__domainname, const char *__msgid, + int __category); +extern char *__ngettext (const char *__msgid1, const char *__msgid2, + unsigned long int __n); +extern char *__dngettext (const char *__domainname, + const char *__msgid1, const char *__msgid2, + unsigned long int n); +extern char *__dcngettext (const char *__domainname, + const char *__msgid1, const char *__msgid2, + unsigned long int __n, int __category); +extern char *__dcigettext (const char *__domainname, + const char *__msgid1, const char *__msgid2, + int __plural, unsigned long int __n, + int __category); +extern char *__textdomain (const char *__domainname); +extern char *__bindtextdomain (const char *__domainname, + const char *__dirname); +extern char *__bind_textdomain_codeset (const char *__domainname, + const char *__codeset); +extern void _nl_finddomain_subfreeres (void) attribute_hidden; +extern void _nl_unload_domain (struct loaded_domain *__domain) + internal_function attribute_hidden; +#else +/* Declare the exported libintl_* functions, in a way that allows us to + call them under their real name. */ +# undef _INTL_REDIRECT_INLINE +# undef _INTL_REDIRECT_MACROS +# define _INTL_REDIRECT_MACROS +# include "libgnuintl.h" +# ifdef IN_LIBGLOCALE +extern char *gl_dcigettext (const char *__domainname, + const char *__msgid1, const char *__msgid2, + int __plural, unsigned long int __n, + int __category, + const char *__localename, const char *__encoding); +# else +extern char *libintl_dcigettext (const char *__domainname, + const char *__msgid1, const char *__msgid2, + int __plural, unsigned long int __n, + int __category); +# endif +#endif + #include "loadinfo.h" #include "gmo.h" /* Get nls_uint32. */ @@ -77,6 +123,26 @@ struct sysdep_string_desc const char *pointer; }; +/* Cache of translated strings after charset conversion. + Note: The strings are converted to the target encoding only on an as-needed + basis. */ +struct converted_domain +{ + /* The target encoding name. */ + const char *encoding; + /* The descriptor for conversion from the message catalog's encoding to + this target encoding. */ +#ifdef _LIBC + __gconv_t conv; +#else +# if HAVE_ICONV + iconv_t conv; +# endif +#endif + /* The table of translated strings after charset conversion. */ + char **conv_tab; +}; + /* The representation of an opened message catalog. */ struct loaded_domain { @@ -112,15 +178,9 @@ struct loaded_domain /* 1 if the hash table uses a different endianness than this machine. */ int must_swap_hash_tab; - int codeset_cntr; -#ifdef _LIBC - __gconv_t conv; -#else -# if HAVE_ICONV - iconv_t conv; -# endif -#endif - char **conv_tab; + /* Cache of charset conversions of the translated strings. */ + struct converted_domain *conversions; + size_t nconversions; struct expression *plural; unsigned long int nplurals; @@ -140,7 +200,6 @@ struct binding { struct binding *next; char *dirname; - int codeset_cntr; /* Incremented each time codeset changes. */ char *codeset; char domainname[ZERO]; }; @@ -148,9 +207,17 @@ struct binding /* A counter which is incremented each time some previous translations become invalid. This variable is part of the external ABI of the GNU libintl. */ -extern int _nl_msg_cat_cntr; +#ifdef IN_LIBGLOCALE +# include <glocale/config.h> +extern LIBGLOCALE_DLL_EXPORTED int _nl_msg_cat_cntr; +#else +extern LIBINTL_DLL_EXPORTED int _nl_msg_cat_cntr; +#endif #ifndef _LIBC +const char *_nl_language_preferences_default (void); +const char *_nl_locale_name_posix (int category, const char *categoryname); +const char *_nl_locale_name_default (void); const char *_nl_locale_name (int category, const char *categoryname); #endif @@ -161,53 +228,18 @@ struct loaded_l10nfile *_nl_find_domain (const char *__dirname, char *__locale, void _nl_load_domain (struct loaded_l10nfile *__domain, struct binding *__domainbinding) internal_function; -void _nl_unload_domain (struct loaded_domain *__domain) - internal_function; -const char *_nl_init_domain_conv (struct loaded_l10nfile *__domain_file, - struct loaded_domain *__domain, - struct binding *__domainbinding) - internal_function; -void _nl_free_domain_conv (struct loaded_domain *__domain) - internal_function; +#ifdef IN_LIBGLOCALE char *_nl_find_msg (struct loaded_l10nfile *domain_file, - struct binding *domainbinding, const char *msgid, + struct binding *domainbinding, const char *encoding, + const char *msgid, size_t *lengthp) internal_function; - -#ifdef _LIBC -extern char *__gettext (const char *__msgid); -extern char *__dgettext (const char *__domainname, const char *__msgid); -extern char *__dcgettext (const char *__domainname, const char *__msgid, - int __category); -extern char *__ngettext (const char *__msgid1, const char *__msgid2, - unsigned long int __n); -extern char *__dngettext (const char *__domainname, - const char *__msgid1, const char *__msgid2, - unsigned long int n); -extern char *__dcngettext (const char *__domainname, - const char *__msgid1, const char *__msgid2, - unsigned long int __n, int __category); -extern char *__dcigettext (const char *__domainname, - const char *__msgid1, const char *__msgid2, - int __plural, unsigned long int __n, - int __category); -extern char *__textdomain (const char *__domainname); -extern char *__bindtextdomain (const char *__domainname, - const char *__dirname); -extern char *__bind_textdomain_codeset (const char *__domainname, - const char *__codeset); #else -/* Declare the exported libintl_* functions, in a way that allows us to - call them under their real name. */ -# undef _INTL_REDIRECT_INLINE -# undef _INTL_REDIRECT_MACROS -# define _INTL_REDIRECT_MACROS -# include "libgnuintl.h" -extern char *libintl_dcigettext (const char *__domainname, - const char *__msgid1, const char *__msgid2, - int __plural, unsigned long int __n, - int __category); +char *_nl_find_msg (struct loaded_l10nfile *domain_file, + struct binding *domainbinding, const char *msgid, + int convert, size_t *lengthp) + internal_function; #endif /* @@ begin of epilog @@ */ diff --git a/intl/gmo.h b/intl/gmo.h index e7c9cc14b..26515feb2 100644 --- a/intl/gmo.h +++ b/intl/gmo.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GETTEXT_H diff --git a/intl/hash-string.h b/intl/hash-string.h index 093e3b1c1..98c07e4a7 100644 --- a/intl/hash-string.h +++ b/intl/hash-string.h @@ -1,5 +1,5 @@ /* Description of GNU message catalog format: string hashing function. - Copyright (C) 1995, 1997-1998, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995, 1997-1998, 2000-2003, 2005 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ end of prolog @@ */ @@ -22,27 +22,15 @@ #define HASHWORDBITS 32 +#ifndef _LIBC +# ifdef IN_LIBINTL +# define __hash_string libintl_hash_string +# else +# define __hash_string hash_string +# endif +#endif + /* Defines the so called `hashpjw' function by P.J. Weinberger [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, 1986, 1987 Bell Telephone Laboratories, Inc.] */ -static inline unsigned long int -hash_string (const char *str_param) -{ - unsigned long int hval, g; - const char *str = str_param; - - /* Compute the hash value for the given string. */ - hval = 0; - while (*str != '\0') - { - hval <<= 4; - hval += (unsigned char) *str++; - g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); - if (g != 0) - { - hval ^= g >> (HASHWORDBITS - 8); - hval ^= g; - } - } - return hval; -} +extern unsigned long int __hash_string (const char *str_param); diff --git a/intl/intl-compat.c b/intl/intl-compat.c index 96f9d955d..9b9ecbb64 100644 --- a/intl/intl-compat.c +++ b/intl/intl-compat.c @@ -1,6 +1,6 @@ /* intl-compat.c - Stub functions to call gettext functions from GNU gettext Library. - Copyright (C) 1995, 2000-2003 Software Foundation, Inc. + Copyright (C) 1995, 2000-2003, 2005 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 @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -49,7 +49,9 @@ /* When building a DLL, we must export some functions. Note that because the functions are only defined for binary backward compatibility, we don't need to use __declspec(dllimport) in any case. */ -#if defined _MSC_VER && BUILDING_DLL +#if HAVE_VISIBILITY && BUILDING_DLL +# define DLL_EXPORTED __attribute__((__visibility__("default"))) +#elif defined _MSC_VER && BUILDING_DLL # define DLL_EXPORTED __declspec(dllexport) #else # define DLL_EXPORTED diff --git a/intl/l10nflist.c b/intl/l10nflist.c index eb995aafa..365aeb708 100644 --- a/intl/l10nflist.c +++ b/intl/l10nflist.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc. +/* Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc. Contributed by Ulrich Drepper <[email protected]>, 1995. This program is free software; you can redistribute it and/or modify it @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's <string.h> to provide a prototype for stpcpy(). @@ -67,8 +67,8 @@ static char *stpcpy (char *dest, const char *src); IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, it may be concatenated to a directory pathname. */ -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ - /* Win32, OS/2, DOS */ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Win32, Cygwin, OS/2, DOS */ # define ISSLASH(C) ((C) == '/' || (C) == '\\') # define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ @@ -82,7 +82,12 @@ static char *stpcpy (char *dest, const char *src); /* Define function which are usually not available. */ -#if !defined _LIBC && !defined HAVE___ARGZ_COUNT +#ifdef _LIBC +# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len) +#elif defined HAVE_ARGZ_COUNT +# undef __argz_count +# define __argz_count argz_count +#else /* Returns the number of strings in ARGZ. */ static size_t argz_count__ (const char *argz, size_t len) @@ -99,13 +104,15 @@ argz_count__ (const char *argz, size_t len) } # undef __argz_count # define __argz_count(argz, len) argz_count__ (argz, len) -#else -# ifdef _LIBC -# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len) -# endif -#endif /* !_LIBC && !HAVE___ARGZ_COUNT */ +#endif /* !_LIBC && !HAVE_ARGZ_COUNT */ -#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY +#ifdef _LIBC +# define __argz_stringify(argz, len, sep) \ + INTUSE(__argz_stringify) (argz, len, sep) +#elif defined HAVE_ARGZ_STRINGIFY +# undef __argz_stringify +# define __argz_stringify argz_stringify +#else /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's except the last into the character SEP. */ static void @@ -122,14 +129,13 @@ argz_stringify__ (char *argz, size_t len, int sep) } # undef __argz_stringify # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) -#else -# ifdef _LIBC -# define __argz_stringify(argz, len, sep) \ - INTUSE(__argz_stringify) (argz, len, sep) -# endif -#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ +#endif /* !_LIBC && !HAVE_ARGZ_STRINGIFY */ -#if !defined _LIBC && !defined HAVE___ARGZ_NEXT +#ifdef _LIBC +#elif defined HAVE_ARGZ_NEXT +# undef __argz_next +# define __argz_next argz_next +#else static char * argz_next__ (char *argz, size_t argz_len, const char *entry) { @@ -148,7 +154,7 @@ argz_next__ (char *argz, size_t argz_len, const char *entry) } # undef __argz_next # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) -#endif /* !_LIBC && !HAVE___ARGZ_NEXT */ +#endif /* !_LIBC && !HAVE_ARGZ_NEXT */ /* Return number of bits set in X. */ @@ -170,8 +176,7 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, const char *dirlist, size_t dirlist_len, int mask, const char *language, const char *territory, const char *codeset, const char *normalized_codeset, - const char *modifier, const char *special, - const char *sponsor, const char *revision, + const char *modifier, const char *filename, int do_allocate) { char *abs_filename; @@ -190,23 +195,14 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, /* Allocate room for the full file name. */ abs_filename = (char *) malloc (dirlist_len + strlen (language) - + ((mask & TERRITORY) != 0 + + ((mask & XPG_TERRITORY) != 0 ? strlen (territory) + 1 : 0) + ((mask & XPG_CODESET) != 0 ? strlen (codeset) + 1 : 0) + ((mask & XPG_NORM_CODESET) != 0 ? strlen (normalized_codeset) + 1 : 0) - + (((mask & XPG_MODIFIER) != 0 - || (mask & CEN_AUDIENCE) != 0) + + ((mask & XPG_MODIFIER) != 0 ? strlen (modifier) + 1 : 0) - + ((mask & CEN_SPECIAL) != 0 - ? strlen (special) + 1 : 0) - + (((mask & CEN_SPONSOR) != 0 - || (mask & CEN_REVISION) != 0) - ? (1 + ((mask & CEN_SPONSOR) != 0 - ? strlen (sponsor) : 0) - + ((mask & CEN_REVISION) != 0 - ? strlen (revision) + 1 : 0)) : 0) + 1 + strlen (filename) + 1); if (abs_filename == NULL) @@ -224,7 +220,7 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, cp = stpcpy (cp, language); - if ((mask & TERRITORY) != 0) + if ((mask & XPG_TERRITORY) != 0) { *cp++ = '_'; cp = stpcpy (cp, territory); @@ -239,29 +235,11 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, *cp++ = '.'; cp = stpcpy (cp, normalized_codeset); } - if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) + if ((mask & XPG_MODIFIER) != 0) { - /* This component can be part of both syntaces but has different - leading characters. For CEN we use `+', else `@'. */ - *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; + *cp++ = '@'; cp = stpcpy (cp, modifier); } - if ((mask & CEN_SPECIAL) != 0) - { - *cp++ = '+'; - cp = stpcpy (cp, special); - } - if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) - { - *cp++ = ','; - if ((mask & CEN_SPONSOR) != 0) - cp = stpcpy (cp, sponsor); - if ((mask & CEN_REVISION) != 0) - { - *cp++ = '_'; - cp = stpcpy (cp, revision); - } - } *cp++ = '/'; stpcpy (cp, filename); @@ -301,7 +279,10 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0)) * sizeof (struct loaded_l10nfile *))); if (retval == NULL) - return NULL; + { + free (abs_filename); + return NULL; + } retval->filename = abs_filename; @@ -332,8 +313,7 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, normalized_codeset. */ for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt) if ((cnt & ~mask) == 0 - && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) - && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) + && !((cnt & XPG_CODESET) != 0 && (cnt & XPG_NORM_CODESET) != 0)) { if (dirlist_count > 1) { @@ -345,15 +325,14 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, retval->successor[entries++] = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt, language, territory, codeset, - normalized_codeset, modifier, special, - sponsor, revision, filename, 1); + normalized_codeset, modifier, filename, + 1); } else retval->successor[entries++] = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, cnt, language, territory, codeset, - normalized_codeset, modifier, special, - sponsor, revision, filename, 1); + normalized_codeset, modifier, filename, 1); } retval->successor[entries] = NULL; diff --git a/intl/libgnuintl.h.in b/intl/libgnuintl.h.in index 3be7eb990..1a053f3af 100644 --- a/intl/libgnuintl.h.in +++ b/intl/libgnuintl.h.in @@ -1,5 +1,5 @@ /* Message catalogs for internationalization. - Copyright (C) 1995-1997, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1997, 2000-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LIBINTL_H @@ -39,7 +39,7 @@ /* Provide information about the supported file formats. Returns the maximum minor revision number supported for a given major revision. */ #define __GNU_GETTEXT_SUPPORTED_REVISION(major) \ - ((major) == 0 ? 1 : -1) + ((major) == 0 || (major) == 1 ? 1 : -1) /* Resolve a platform specific conflict on DJGPP. GNU gettext takes precedence over _conio_gettext. */ @@ -52,6 +52,11 @@ extern "C" { #endif +/* Version number: (major<<16) + (minor<<8) + subminor */ +#define LIBINTL_VERSION 0x000F00 +extern int libintl_version; + + /* We redirect the functions to those prefixed with "libintl_". This is necessary, because some systems define gettext/textdomain/... in the C library (namely, Solaris 2.4 and newer, and GNU libc 2.0 and newer). @@ -83,7 +88,7 @@ extern "C" { If he doesn't, we choose the method. A third possible method is _INTL_REDIRECT_ASM, supported only by GCC. */ #if !(defined _INTL_REDIRECT_INLINE || defined _INTL_REDIRECT_MACROS) -# if __GNUC__ >= 2 && !defined __APPLE_CC__ && !defined __MINGW32__ && !(__GNUC__ == 2 && defined _AIX) && (defined __STDC__ || defined __cplusplus) +# if __GNUC__ >= 2 && !(__APPLE_CC__ > 1) && !defined __MINGW32__ && !(__GNUC__ == 2 && defined _AIX) && (defined __STDC__ || defined __cplusplus) # define _INTL_REDIRECT_ASM # else # ifdef __cplusplus @@ -102,11 +107,21 @@ extern "C" { # define _INTL_ASM(cname) #endif +/* _INTL_MAY_RETURN_STRING_ARG(n) declares that the given function may return + its n-th argument literally. This enables GCC to warn for example about + printf (gettext ("foo %y")). */ +#if __GNUC__ >= 3 && !(__APPLE_CC__ > 1 && defined __cplusplus) +# define _INTL_MAY_RETURN_STRING_ARG(n) __attribute__ ((__format_arg__ (n))) +#else +# define _INTL_MAY_RETURN_STRING_ARG(n) +#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). */ #ifdef _INTL_REDIRECT_INLINE -extern char *libintl_gettext (const char *__msgid); +extern char *libintl_gettext (const char *__msgid) + _INTL_MAY_RETURN_STRING_ARG (1); static inline char *gettext (const char *__msgid) { return libintl_gettext (__msgid); @@ -116,13 +131,15 @@ static inline char *gettext (const char *__msgid) # define gettext libintl_gettext #endif extern char *gettext (const char *__msgid) - _INTL_ASM (libintl_gettext); + _INTL_ASM (libintl_gettext) + _INTL_MAY_RETURN_STRING_ARG (1); #endif /* Look up MSGID in the DOMAINNAME message catalog for the current LC_MESSAGES locale. */ #ifdef _INTL_REDIRECT_INLINE -extern char *libintl_dgettext (const char *__domainname, const char *__msgid); +extern char *libintl_dgettext (const char *__domainname, const char *__msgid) + _INTL_MAY_RETURN_STRING_ARG (2); static inline char *dgettext (const char *__domainname, const char *__msgid) { return libintl_dgettext (__domainname, __msgid); @@ -132,14 +149,16 @@ static inline char *dgettext (const char *__domainname, const char *__msgid) # define dgettext libintl_dgettext #endif extern char *dgettext (const char *__domainname, const char *__msgid) - _INTL_ASM (libintl_dgettext); + _INTL_ASM (libintl_dgettext) + _INTL_MAY_RETURN_STRING_ARG (2); #endif /* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY locale. */ #ifdef _INTL_REDIRECT_INLINE extern char *libintl_dcgettext (const char *__domainname, const char *__msgid, - int __category); + int __category) + _INTL_MAY_RETURN_STRING_ARG (2); static inline char *dcgettext (const char *__domainname, const char *__msgid, int __category) { @@ -151,7 +170,8 @@ static inline char *dcgettext (const char *__domainname, const char *__msgid, #endif extern char *dcgettext (const char *__domainname, const char *__msgid, int __category) - _INTL_ASM (libintl_dcgettext); + _INTL_ASM (libintl_dcgettext) + _INTL_MAY_RETURN_STRING_ARG (2); #endif @@ -159,7 +179,8 @@ extern char *dcgettext (const char *__domainname, const char *__msgid, number N. */ #ifdef _INTL_REDIRECT_INLINE extern char *libintl_ngettext (const char *__msgid1, const char *__msgid2, - unsigned long int __n); + unsigned long int __n) + _INTL_MAY_RETURN_STRING_ARG (1) _INTL_MAY_RETURN_STRING_ARG (2); static inline char *ngettext (const char *__msgid1, const char *__msgid2, unsigned long int __n) { @@ -171,14 +192,16 @@ static inline char *ngettext (const char *__msgid1, const char *__msgid2, #endif extern char *ngettext (const char *__msgid1, const char *__msgid2, unsigned long int __n) - _INTL_ASM (libintl_ngettext); + _INTL_ASM (libintl_ngettext) + _INTL_MAY_RETURN_STRING_ARG (1) _INTL_MAY_RETURN_STRING_ARG (2); #endif /* Similar to `dgettext' but select the plural form corresponding to the number N. */ #ifdef _INTL_REDIRECT_INLINE extern char *libintl_dngettext (const char *__domainname, const char *__msgid1, - const char *__msgid2, unsigned long int __n); + const char *__msgid2, unsigned long int __n) + _INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3); static inline char *dngettext (const char *__domainname, const char *__msgid1, const char *__msgid2, unsigned long int __n) { @@ -191,7 +214,8 @@ static inline char *dngettext (const char *__domainname, const char *__msgid1, extern char *dngettext (const char *__domainname, const char *__msgid1, const char *__msgid2, unsigned long int __n) - _INTL_ASM (libintl_dngettext); + _INTL_ASM (libintl_dngettext) + _INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3); #endif /* Similar to `dcgettext' but select the plural form corresponding to the @@ -199,7 +223,8 @@ extern char *dngettext (const char *__domainname, #ifdef _INTL_REDIRECT_INLINE extern char *libintl_dcngettext (const char *__domainname, const char *__msgid1, const char *__msgid2, - unsigned long int __n, int __category); + unsigned long int __n, int __category) + _INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3); static inline char *dcngettext (const char *__domainname, const char *__msgid1, const char *__msgid2, unsigned long int __n, int __category) @@ -213,10 +238,13 @@ static inline char *dcngettext (const char *__domainname, extern char *dcngettext (const char *__domainname, const char *__msgid1, const char *__msgid2, unsigned long int __n, int __category) - _INTL_ASM (libintl_dcngettext); + _INTL_ASM (libintl_dcngettext) + _INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3); #endif +#ifndef IN_LIBGLOCALE + /* 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". */ @@ -271,6 +299,8 @@ extern char *bind_textdomain_codeset (const char *__domainname, _INTL_ASM (libintl_bind_textdomain_codeset); #endif +#endif /* IN_LIBGLOCALE */ + /* Support for format strings with positions in *printf(), following the POSIX/XSI specification. @@ -300,6 +330,12 @@ extern int fprintf (FILE *, const char *, ...); extern int vfprintf (FILE *, const char *, va_list); #undef printf +#if defined __NetBSD__ || defined __CYGWIN__ || defined __MINGW32__ +/* Don't break __attribute__((format(printf,M,N))). + This redefinition is only possible because the libc in NetBSD, Cygwin, + mingw does not have a function __printf__. */ +# define libintl_printf __printf__ +#endif #define printf libintl_printf extern int printf (const char *, ...); #undef vprintf diff --git a/intl/loadinfo.h b/intl/loadinfo.h index 65e5ebd1f..a7a197031 100644 --- a/intl/loadinfo.h +++ b/intl/loadinfo.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999, 2000-2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999, 2000-2003, 2005-2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <[email protected]>, 1996. @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LOADINFO_H @@ -36,6 +36,10 @@ # define internal_function #endif +#ifndef LIBINTL_DLL_EXPORTED +# define LIBINTL_DLL_EXPORTED +#endif + /* Tell the compiler when a conditional or integer expression is almost always true or almost always false. */ #ifndef HAVE_BUILTIN_EXPECT @@ -43,7 +47,7 @@ #endif /* Separator in PATH like lists of pathnames. */ -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ +#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__ /* Win32, OS/2, DOS */ # define PATH_SEPARATOR ';' #else @@ -52,17 +56,10 @@ #endif /* Encoding of locale name parts. */ -#define CEN_REVISION 1 -#define CEN_SPONSOR 2 -#define CEN_SPECIAL 4 -#define XPG_NORM_CODESET 8 -#define XPG_CODESET 16 -#define TERRITORY 32 -#define CEN_AUDIENCE 64 -#define XPG_MODIFIER 128 - -#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE) -#define XPG_SPECIFIC (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER) +#define XPG_NORM_CODESET 1 +#define XPG_CODESET 2 +#define XPG_TERRITORY 4 +#define XPG_MODIFIER 8 struct loaded_l10nfile @@ -89,9 +86,9 @@ extern const char *_nl_normalize_codeset (const char *codeset, files of the same kind, sorted in decreasing order of ->filename. DIRLIST and DIRLIST_LEN are an argz list of directories in which to look, containing at least one directory (i.e. DIRLIST_LEN > 0). - MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER, - SPECIAL, SPONSOR, REVISION are the pieces of the locale name, as - produced by _nl_explode_name(). FILENAME is the filename suffix. + MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER + are the pieces of the locale name, as produced by _nl_explode_name(). + FILENAME is the filename suffix. The return value is the lookup result, either found in *L10NFILE_LIST, or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL. If the return value is non-NULL, it is added to *L10NFILE_LIST, and @@ -103,43 +100,33 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list, const char *dirlist, size_t dirlist_len, int mask, const char *language, const char *territory, const char *codeset, const char *normalized_codeset, - const char *modifier, const char *special, - const char *sponsor, const char *revision, + const char *modifier, const char *filename, int do_allocate); /* Lookup the real locale name for a locale alias NAME, or NULL if NAME is not a locale alias (but possibly a real locale name). The return value is statically allocated and must not be freed. */ -extern const char *_nl_expand_alias (const char *name); +/* Part of the libintl ABI only for the sake of the gettext.m4 macro. */ +extern LIBINTL_DLL_EXPORTED const char *_nl_expand_alias (const char *name); /* Split a locale name NAME into its pieces: language, modifier, - territory, codeset, special, sponsor, revision. + territory, codeset. NAME gets destructively modified: NUL bytes are inserted here and there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY, - *CODESET, *SPECIAL, *SPONSOR, *REVISION gets assigned either a - pointer into the old NAME string, or NULL. *NORMALIZED_CODESET - gets assigned the expanded *CODESET, if it is different from *CODESET; - this one is dynamically allocated and has to be freed by the caller. + *CODESET gets assigned either a pointer into the old NAME string, or + NULL. *NORMALIZED_CODESET gets assigned the expanded *CODESET, if it + is different from *CODESET; this one is dynamically allocated and has + to be freed by the caller. The return value is a bitmask, where each bit corresponds to one filled-in value: - XPG_MODIFIER, CEN_AUDIENCE for *MODIFIER, - TERRITORY for *TERRITORY, + XPG_MODIFIER for *MODIFIER, + XPG_TERRITORY for *TERRITORY, XPG_CODESET for *CODESET, - XPG_NORM_CODESET for *NORMALIZED_CODESET, - CEN_SPECIAL for *SPECIAL, - CEN_SPONSOR for *SPONSOR, - CEN_REVISION for *REVISION. + XPG_NORM_CODESET for *NORMALIZED_CODESET. */ extern int _nl_explode_name (char *name, const char **language, const char **modifier, const char **territory, const char **codeset, - const char **normalized_codeset, - const char **special, const char **sponsor, - const char **revision); - -/* Split a locale name NAME into a leading language part and all the - rest. Return a pointer to the first character after the language, - i.e. to the first byte of the rest. */ -extern char *_nl_find_language (const char *name); + const char **normalized_codeset); #endif /* loadinfo.h */ diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c index 99c51b4c5..2520c8c21 100644 --- a/intl/loadmsgcat.c +++ b/intl/loadmsgcat.c @@ -1,5 +1,5 @@ /* Load needed message catalogs. - Copyright (C) 1995-1999, 2000-2004 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2005 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's <string.h> to provide a prototype for mempcpy(). @@ -91,6 +91,14 @@ char *alloca (); #ifdef _LIBC # include "../locale/localeinfo.h" +# include <not-cancel.h> +#endif + +/* Handle multi-threaded applications. */ +#ifdef _LIBC +# include <bits/libc-lock.h> +#else +# include "lock.h" #endif /* Provide fallback values for macros that ought to be defined in <inttypes.h>. @@ -457,11 +465,12 @@ char *alloca (); /* Rename the non ISO C functions. This is required by the standard because some ISO C functions will require linking with this object file and the name space must not be polluted. */ -# define open __open -# define close __close -# define read __read -# define mmap __mmap -# define munmap __munmap +# define open(name, flags) open_not_cancel_2 (name, flags) +# define close(fd) close_not_cancel_no_status (fd) +# define read(fd, buf, n) read_not_cancel (fd, buf, n) +# define mmap(addr, len, prot, flags, fd, offset) \ + __mmap (addr, len, prot, flags, fd, offset) +# define munmap(addr, len) __munmap (addr, len) #endif /* For those losing systems which don't have `alloca' we have to add @@ -764,144 +773,6 @@ get_sysdep_segment_value (const char *name) return NULL; } -/* Initialize the codeset dependent parts of an opened message catalog. - Return the header entry. */ -const char * -internal_function -_nl_init_domain_conv (struct loaded_l10nfile *domain_file, - struct loaded_domain *domain, - struct binding *domainbinding) -{ - /* Find out about the character set the file is encoded with. - This can be found (in textual form) in the entry "". If this - entry does not exist or if this does not contain the `charset=' - information, we will assume the charset matches the one the - current locale and we don't have to perform any conversion. */ - char *nullentry; - size_t nullentrylen; - - /* Preinitialize fields, to avoid recursion during _nl_find_msg. */ - domain->codeset_cntr = - (domainbinding != NULL ? domainbinding->codeset_cntr : 0); -#ifdef _LIBC - domain->conv = (__gconv_t) -1; -#else -# if HAVE_ICONV - domain->conv = (iconv_t) -1; -# endif -#endif - domain->conv_tab = NULL; - - /* Get the header entry. */ - nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen); - - if (nullentry != NULL) - { -#if defined _LIBC || HAVE_ICONV - const char *charsetstr; - - charsetstr = strstr (nullentry, "charset="); - if (charsetstr != NULL) - { - size_t len; - char *charset; - const char *outcharset; - - charsetstr += strlen ("charset="); - len = strcspn (charsetstr, " \t\n"); - - charset = (char *) alloca (len + 1); -# if defined _LIBC || HAVE_MEMPCPY - *((char *) mempcpy (charset, charsetstr, len)) = '\0'; -# else - memcpy (charset, charsetstr, len); - charset[len] = '\0'; -# endif - - /* The output charset should normally be determined by the - locale. But sometimes the locale is not used or not correctly - set up, so we provide a possibility for the user to override - this. Moreover, the value specified through - bind_textdomain_codeset overrides both. */ - if (domainbinding != NULL && domainbinding->codeset != NULL) - outcharset = domainbinding->codeset; - else - { - outcharset = getenv ("OUTPUT_CHARSET"); - if (outcharset == NULL || outcharset[0] == '\0') - { -# ifdef _LIBC - outcharset = _NL_CURRENT (LC_CTYPE, CODESET); -# else -# if HAVE_ICONV - extern const char *locale_charset (void); - outcharset = locale_charset (); -# endif -# endif - } - } - -# ifdef _LIBC - /* We always want to use transliteration. */ - outcharset = norm_add_slashes (outcharset, "TRANSLIT"); - charset = norm_add_slashes (charset, NULL); - if (__gconv_open (outcharset, charset, &domain->conv, - GCONV_AVOID_NOCONV) - != __GCONV_OK) - domain->conv = (__gconv_t) -1; -# else -# if HAVE_ICONV - /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, - we want to use transliteration. */ -# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \ - || _LIBICONV_VERSION >= 0x0105 - if (strchr (outcharset, '/') == NULL) - { - char *tmp; - - len = strlen (outcharset); - tmp = (char *) alloca (len + 10 + 1); - memcpy (tmp, outcharset, len); - memcpy (tmp + len, "//TRANSLIT", 10 + 1); - outcharset = tmp; - - domain->conv = iconv_open (outcharset, charset); - - freea (outcharset); - } - else -# endif - domain->conv = iconv_open (outcharset, charset); -# endif -# endif - - freea (charset); - } -#endif /* _LIBC || HAVE_ICONV */ - } - - return nullentry; -} - -/* Frees the codeset dependent parts of an opened message catalog. */ -void -internal_function -_nl_free_domain_conv (struct loaded_domain *domain) -{ - if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1) - free (domain->conv_tab); - -#ifdef _LIBC - if (domain->conv != (__gconv_t) -1) - __gconv_close (domain->conv); -#else -# if HAVE_ICONV - if (domain->conv != (iconv_t) -1) - iconv_close (domain->conv); -# endif -#endif -} - /* Load the message catalogs specified by FILENAME. If it is no valid message catalog do nothing. */ void @@ -909,7 +780,8 @@ internal_function _nl_load_domain (struct loaded_l10nfile *domain_file, struct binding *domainbinding) { - int fd; + __libc_lock_define_initialized_recursive (static, lock) + int fd = -1; size_t size; #ifdef _LIBC struct stat64 st; @@ -921,8 +793,24 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, struct loaded_domain *domain; int revision; const char *nullentry; + size_t nullentrylen; - domain_file->decided = 1; + __libc_lock_lock_recursive (lock); + if (domain_file->decided != 0) + { + /* There are two possibilities: + + + this is the same thread calling again during this initialization + via _nl_find_msg. We have initialized everything this call needs. + + + this is another thread which tried to initialize this object. + Not necessary anymore since if the lock is available this + is finished. + */ + goto done; + } + + domain_file->decided = -1; domain_file->data = NULL; /* Note that it would be useless to store domainbinding in domain_file @@ -934,12 +822,12 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, specification the locale file name is different for XPG and CEN syntax. */ if (domain_file->filename == NULL) - return; + goto out; /* Try to open the addressed file. */ fd = open (domain_file->filename, O_RDONLY | O_BINARY); if (fd == -1) - return; + goto out; /* We must know about the size of the file. */ if ( @@ -950,11 +838,8 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, #endif || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0) || __builtin_expect (size < sizeof (struct mo_file_header), 0)) - { - /* Something went wrong. */ - close (fd); - return; - } + /* Something went wrong. */ + goto out; #ifdef HAVE_MMAP /* Now we are ready to load the file. If mmap() is available we try @@ -966,6 +851,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, { /* mmap() call was successful. */ close (fd); + fd = -1; use_mmap = 1; } #endif @@ -979,7 +865,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, data = (struct mo_file_header *) malloc (size); if (data == NULL) - return; + goto out; to_read = size; read_ptr = (char *) data; @@ -992,8 +878,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, if (nb == -1 && errno == EINTR) continue; #endif - close (fd); - return; + goto out; } read_ptr += nb; to_read -= nb; @@ -1001,6 +886,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, while (to_read > 0); close (fd); + fd = -1; } /* Using the magic number we can test whether it really is a message @@ -1015,12 +901,12 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, else #endif free (data); - return; + goto out; } domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); if (domain == NULL) - return; + goto out; domain_file->data = domain; domain->data = (char *) data; @@ -1321,7 +1207,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, for (i = 0; i < n_inmem_sysdep_strings; i++) { const char *msgid = inmem_orig_sysdep_tab[i].pointer; - nls_uint32 hash_val = hash_string (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)); @@ -1382,28 +1268,55 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, free (data); free (domain); domain_file->data = NULL; - return; + goto out; } - /* Now initialize the character set converter from the character set - the file is encoded with (found in the header entry) to the domain's - specified character set or the locale's character set. */ - nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding); + /* No caches of converted translations so far. */ + domain->conversions = NULL; + domain->nconversions = 0; - /* Also look for a plural specification. */ + /* Get the header entry and look for a plural specification. */ +#ifdef IN_LIBGLOCALE + nullentry = + _nl_find_msg (domain_file, domainbinding, NULL, "", &nullentrylen); +#else + nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen); +#endif EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals); + + out: + if (fd != -1) + close (fd); + + domain_file->decided = 1; + + done: + __libc_lock_unlock_recursive (lock); } #ifdef _LIBC void -internal_function +internal_function __libc_freeres_fn_section _nl_unload_domain (struct loaded_domain *domain) { + size_t i; + if (domain->plural != &__gettext_germanic_plural) __gettext_free_exp (domain->plural); - _nl_free_domain_conv (domain); + for (i = 0; i < domain->nconversions; i++) + { + struct converted_domain *convd = &domain->conversions[i]; + + free (convd->encoding); + if (convd->conv_tab != NULL && convd->conv_tab != (char **) -1) + free (convd->conv_tab); + if (convd->conv != (__gconv_t) -1) + __gconv_close (convd->conv); + } + if (domain->conversions != NULL) + free (domain->conversions); if (domain->malloced) free (domain->malloced); diff --git a/intl/localcharset.c b/intl/localcharset.c index 4865f1037..e8505bfa9 100644 --- a/intl/localcharset.c +++ b/intl/localcharset.c @@ -1,6 +1,6 @@ /* Determine a canonical name for the current locale's character encoding. - Copyright (C) 2000-2003 Free Software Foundation, Inc. + Copyright (C) 2000-2006 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 @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Bruno Haible <[email protected]>. */ @@ -41,8 +41,7 @@ #endif #if defined _WIN32 || defined __WIN32__ -# undef WIN32 /* avoid warning on mingw32 */ -# define WIN32 +# define WIN32_NATIVE #endif #if defined __EMX__ @@ -50,7 +49,7 @@ # define OS2 #endif -#if !defined WIN32 +#if !defined WIN32_NATIVE # if HAVE_LANGINFO_CODESET # include <langinfo.h> # else @@ -58,7 +57,11 @@ # include <locale.h> # endif # endif -#elif defined WIN32 +# ifdef __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# endif +#elif defined WIN32_NATIVE # define WIN32_LEAN_AND_MEAN # include <windows.h> #endif @@ -73,8 +76,8 @@ # define relocate(pathname) (pathname) #endif -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ - /* Win32, OS/2, DOS */ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Win32, Cygwin, OS/2, DOS */ # define ISSLASH(C) ((C) == '/' || (C) == '\\') #endif @@ -107,19 +110,25 @@ static const char * volatile charset_aliases; /* Return a pointer to the contents of the charset.alias file. */ static const char * -get_charset_aliases () +get_charset_aliases (void) { const char *cp; cp = charset_aliases; if (cp == NULL) { -#if !(defined VMS || defined WIN32) +#if !(defined VMS || defined WIN32_NATIVE || defined __CYGWIN__) FILE *fp; - const char *dir = relocate (LIBDIR); + const char *dir; const char *base = "charset.alias"; char *file_name; + /* Make it possible to override the charset.alias location. This is + necessary for running the testsuite before "make install". */ + dir = getenv ("CHARSETALIASDIR"); + if (dir == NULL || dir[0] == '\0') + dir = relocate (LIBDIR); + /* Concatenate dir and base into freshly allocated file_name. */ { size_t dir_len = strlen (dir); @@ -141,15 +150,17 @@ get_charset_aliases () 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 (;;) { + int c; + char buf1[50+1]; + char buf2[50+1]; + size_t l1, l2; + char *old_res_ptr; + c = getc (fp); if (c == EOF) break; @@ -170,6 +181,7 @@ get_charset_aliases () break; l1 = strlen (buf1); l2 = strlen (buf2); + old_res_ptr = res_ptr; if (res_size == 0) { res_size = l1 + 1 + l2 + 1; @@ -184,6 +196,8 @@ get_charset_aliases () { /* Out of memory. */ res_size = 0; + if (old_res_ptr != NULL) + free (old_res_ptr); break; } strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1); @@ -229,7 +243,7 @@ get_charset_aliases () "DECKOREAN" "\0" "EUC-KR" "\0"; # endif -# if defined WIN32 +# if defined WIN32_NATIVE || defined __CYGWIN__ /* 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. */ @@ -238,6 +252,7 @@ get_charset_aliases () "CP1361" "\0" "JOHAB" "\0" "CP20127" "\0" "ASCII" "\0" "CP20866" "\0" "KOI8-R" "\0" + "CP20936" "\0" "GB2312" "\0" "CP21866" "\0" "KOI8-RU" "\0" "CP28591" "\0" "ISO-8859-1" "\0" "CP28592" "\0" "ISO-8859-2" "\0" @@ -248,7 +263,14 @@ get_charset_aliases () "CP28597" "\0" "ISO-8859-7" "\0" "CP28598" "\0" "ISO-8859-8" "\0" "CP28599" "\0" "ISO-8859-9" "\0" - "CP28605" "\0" "ISO-8859-15" "\0"; + "CP28605" "\0" "ISO-8859-15" "\0" + "CP38598" "\0" "ISO-8859-8" "\0" + "CP51932" "\0" "EUC-JP" "\0" + "CP51936" "\0" "GB2312" "\0" + "CP51949" "\0" "EUC-KR" "\0" + "CP51950" "\0" "EUC-TW" "\0" + "CP54936" "\0" "GB18030" "\0" + "CP65001" "\0" "UTF-8" "\0"; # endif #endif @@ -268,18 +290,65 @@ get_charset_aliases () STATIC #endif const char * -locale_charset () +locale_charset (void) { const char *codeset; const char *aliases; -#if !(defined WIN32 || defined OS2) +#if !(defined WIN32_NATIVE || defined OS2) # if HAVE_LANGINFO_CODESET /* Most systems support nl_langinfo (CODESET) nowadays. */ codeset = nl_langinfo (CODESET); +# ifdef __CYGWIN__ + /* Cygwin 2006 does not have locales. nl_langinfo (CODESET) always + returns "US-ASCII". As long as this is not fixed, return the suffix + of the locale name from the environment variables (if present) or + the codepage as a number. */ + if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0) + { + const char *locale; + static char buf[2 + 10 + 1]; + + locale = getenv ("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_CTYPE"); + if (locale == NULL || locale[0] == '\0') + locale = getenv ("LANG"); + } + if (locale != NULL && locale[0] != '\0') + { + /* If the locale name contains an encoding after the dot, return + it. */ + const char *dot = strchr (locale, '.'); + + if (dot != NULL) + { + const char *modifier; + + dot++; + /* Look for the possible @... trailer and remove it, if any. */ + modifier = strchr (dot, '@'); + if (modifier == NULL) + return dot; + if (modifier - dot < sizeof (buf)) + { + memcpy (buf, dot, modifier - dot); + buf [modifier - dot] = '\0'; + return buf; + } + } + } + + /* Woe32 has a function returning the locale's codepage as a number. */ + sprintf (buf, "CP%u", GetACP ()); + codeset = buf; + } +# endif + # else /* On old systems which lack it, use setlocale or getenv. */ @@ -310,7 +379,7 @@ locale_charset () # endif -#elif defined WIN32 +#elif defined WIN32_NATIVE static char buf[2 + 10 + 1]; diff --git a/intl/localcharset.h b/intl/localcharset.h index 3b137e73c..129e4a4a3 100644 --- a/intl/localcharset.h +++ b/intl/localcharset.h @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LOCALCHARSET_H diff --git a/intl/locale.alias b/intl/locale.alias index bd6bb2562..faa696918 100644 --- a/intl/locale.alias +++ b/intl/locale.alias @@ -13,7 +13,7 @@ # # 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, +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. # The format of this file is the same as for the corresponding file of diff --git a/intl/localealias.c b/intl/localealias.c index 2eaf8813e..26122a011 100644 --- a/intl/localealias.c +++ b/intl/localealias.c @@ -1,5 +1,5 @@ /* Handle aliases for locale names. - Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2001, 2003, 2005 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's <string.h> to provide a prototype for mempcpy(). @@ -81,11 +81,13 @@ char *alloca (); # endif # define HAVE_MEMPCPY 1 # define HAVE___FSETLOCKING 1 +#endif -/* We need locking here since we can be called from different places. */ +/* Handle multi-threaded applications. */ +#ifdef _LIBC # include <bits/libc-lock.h> - -__libc_lock_define_initialized (static, lock); +#else +# include "lock.h" #endif #ifndef internal_function @@ -120,6 +122,9 @@ __libc_lock_define_initialized (static, lock); #endif +__libc_lock_define_initialized (static, lock) + + struct alias_map { const char *alias; @@ -155,9 +160,7 @@ _nl_expand_alias (const char *name) const char *result = NULL; size_t added; -#ifdef _LIBC __libc_lock_lock (lock); -#endif if (locale_alias_path == NULL) locale_alias_path = LOCALE_ALIAS_PATH; @@ -204,9 +207,7 @@ _nl_expand_alias (const char *name) } while (added != 0); -#ifdef _LIBC __libc_lock_unlock (lock); -#endif return result; } @@ -230,7 +231,13 @@ read_alias_file (const char *fname, int fname_len) memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile); #endif +#ifdef _LIBC + /* Note the file is opened with cancellation in the I/O functions + disabled. */ + fp = fopen (relocate (full_fname), "rc"); +#else fp = fopen (relocate (full_fname), "r"); +#endif freea (full_fname); if (fp == NULL) return 0; @@ -254,11 +261,15 @@ read_alias_file (const char *fname, int fname_len) char *alias; char *value; char *cp; + int complete_line; if (FGETS (buf, sizeof buf, fp) == NULL) /* EOF reached. */ break; + /* Determine whether the line is complete. */ + complete_line = strchr (buf, '\n') != NULL; + cp = buf; /* Ignore leading white space. */ while (isspace ((unsigned char) cp[0])) @@ -280,9 +291,6 @@ read_alias_file (const char *fname, int fname_len) if (cp[0] != '\0') { - size_t alias_len; - size_t value_len; - value = cp++; while (cp[0] != '\0' && !isspace ((unsigned char) cp[0])) ++cp; @@ -298,60 +306,75 @@ read_alias_file (const char *fname, int fname_len) else if (cp[0] != '\0') *cp++ = '\0'; - if (nmap >= maxmap) - if (__builtin_expect (extend_alias_table (), 0)) - return added; +#ifdef IN_LIBGLOCALE + /* glibc's locale.alias contains entries for ja_JP and ko_KR + that make it impossible to use a Japanese or Korean UTF-8 + locale under the name "ja_JP" or "ko_KR". Ignore these + entries. */ + if (strchr (alias, '_') == NULL) +#endif + { + size_t alias_len; + size_t value_len; - alias_len = strlen (alias) + 1; - value_len = strlen (value) + 1; + if (nmap >= maxmap) + if (__builtin_expect (extend_alias_table (), 0)) + goto out; - if (string_space_act + alias_len + value_len > string_space_max) - { - /* Increase size of memory pool. */ - size_t new_size = (string_space_max - + (alias_len + value_len > 1024 - ? alias_len + value_len : 1024)); - char *new_pool = (char *) realloc (string_space, new_size); - if (new_pool == NULL) - return added; - - if (__builtin_expect (string_space != new_pool, 0)) - { - size_t i; + alias_len = strlen (alias) + 1; + value_len = strlen (value) + 1; - for (i = 0; i < nmap; i++) + if (string_space_act + alias_len + value_len > string_space_max) + { + /* Increase size of memory pool. */ + size_t new_size = (string_space_max + + (alias_len + value_len > 1024 + ? alias_len + value_len : 1024)); + char *new_pool = (char *) realloc (string_space, new_size); + if (new_pool == NULL) + goto out; + + if (__builtin_expect (string_space != new_pool, 0)) { - map[i].alias += new_pool - string_space; - map[i].value += new_pool - string_space; + size_t i; + + for (i = 0; i < nmap; i++) + { + map[i].alias += new_pool - string_space; + map[i].value += new_pool - string_space; + } } - } - string_space = new_pool; - string_space_max = new_size; - } + string_space = new_pool; + string_space_max = new_size; + } - map[nmap].alias = memcpy (&string_space[string_space_act], - alias, alias_len); - string_space_act += alias_len; + map[nmap].alias = memcpy (&string_space[string_space_act], + alias, alias_len); + string_space_act += alias_len; - map[nmap].value = memcpy (&string_space[string_space_act], - value, value_len); - string_space_act += value_len; + map[nmap].value = memcpy (&string_space[string_space_act], + value, value_len); + string_space_act += value_len; - ++nmap; - ++added; + ++nmap; + ++added; + } } } /* Possibly not the whole line fits into the buffer. Ignore the rest of the line. */ - while (strchr (buf, '\n') == NULL) - if (FGETS (buf, sizeof buf, fp) == NULL) - /* Make sure the inner loop will be left. The outer loop - will exit at the `feof' test. */ - break; + if (! complete_line) + do + if (FGETS (buf, sizeof buf, fp) == NULL) + /* Make sure the inner loop will be left. The outer loop + will exit at the `feof' test. */ + break; + while (strchr (buf, '\n') == NULL); } + out: /* Should we test for ferror()? I think we have to silently ignore errors. --drepper */ fclose (fp); diff --git a/intl/localename.c b/intl/localename.c index 5662e54ff..1b8b99a1a 100644 --- a/intl/localename.c +++ b/intl/localename.c @@ -1,5 +1,5 @@ /* Determine the current selected locale. - Copyright (C) 1995-1999, 2000-2004 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2006 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 @@ -13,11 +13,12 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Ulrich Drepper <[email protected]>, 1995. */ /* Win32 code written by Tor Lillqvist <[email protected]>. */ +/* MacOS X code written by Bruno Haible <[email protected]>. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -26,12 +27,21 @@ #include <stdlib.h> #include <locale.h> +#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +# include <string.h> +# include <CoreFoundation/CFString.h> +# if HAVE_CFLOCALECOPYCURRENT +# include <CoreFoundation/CFLocale.h> +# elif HAVE_CFPREFERENCESCOPYAPPVALUE +# include <CoreFoundation/CFPreferences.h> +# endif +#endif + #if defined _WIN32 || defined __WIN32__ -# undef WIN32 /* avoid warning on mingw32 */ -# define WIN32 +# define WIN32_NATIVE #endif -#ifdef WIN32 +#ifdef WIN32_NATIVE # define WIN32_LEAN_AND_MEAN # include <windows.h> /* List of language codes, sorted by value: @@ -683,6 +693,280 @@ # endif #endif +# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE +/* MacOS X 10.2 or newer */ + +/* Canonicalize a MacOS X locale name to a Unix locale name. + NAME is a sufficiently large buffer. + On input, it contains the MacOS X locale name. + On output, it contains the Unix locale name. */ +void +_nl_locale_name_canonicalize (char *name) +{ + /* This conversion is based on a posting by + Deborah GoldSmith <[email protected]> on 2005-03-08, + http://lists.apple.com/archives/carbon-dev/2005/Mar/msg00293.html */ + + /* Convert legacy (NeXTstep inherited) English names to Unix (ISO 639 and + ISO 3166) names. Prior to MacOS X 10.3, there is no API for doing this. + Therefore we do it ourselves, using a table based on the results of the + MacOS X 10.3.8 function + CFLocaleCreateCanonicalLocaleIdentifierFromString(). */ + typedef struct { const char legacy[21+1]; const char unixy[5+1]; } + legacy_entry; + static const legacy_entry legacy_table[] = { + { "Afrikaans", "af" }, + { "Albanian", "sq" }, + { "Amharic", "am" }, + { "Arabic", "ar" }, + { "Armenian", "hy" }, + { "Assamese", "as" }, + { "Aymara", "ay" }, + { "Azerbaijani", "az" }, + { "Basque", "eu" }, + { "Belarusian", "be" }, + { "Belorussian", "be" }, + { "Bengali", "bn" }, + { "Brazilian Portugese", "pt_BR" }, + { "Brazilian Portuguese", "pt_BR" }, + { "Breton", "br" }, + { "Bulgarian", "bg" }, + { "Burmese", "my" }, + { "Byelorussian", "be" }, + { "Catalan", "ca" }, + { "Chewa", "ny" }, + { "Chichewa", "ny" }, + { "Chinese", "zh" }, + { "Chinese, Simplified", "zh_CN" }, + { "Chinese, Traditional", "zh_TW" }, + { "Chinese, Tradtional", "zh_TW" }, + { "Croatian", "hr" }, + { "Czech", "cs" }, + { "Danish", "da" }, + { "Dutch", "nl" }, + { "Dzongkha", "dz" }, + { "English", "en" }, + { "Esperanto", "eo" }, + { "Estonian", "et" }, + { "Faroese", "fo" }, + { "Farsi", "fa" }, + { "Finnish", "fi" }, + { "Flemish", "nl_BE" }, + { "French", "fr" }, + { "Galician", "gl" }, + { "Gallegan", "gl" }, + { "Georgian", "ka" }, + { "German", "de" }, + { "Greek", "el" }, + { "Greenlandic", "kl" }, + { "Guarani", "gn" }, + { "Gujarati", "gu" }, + { "Hawaiian", "haw" }, /* Yes, "haw", not "cpe". */ + { "Hebrew", "he" }, + { "Hindi", "hi" }, + { "Hungarian", "hu" }, + { "Icelandic", "is" }, + { "Indonesian", "id" }, + { "Inuktitut", "iu" }, + { "Irish", "ga" }, + { "Italian", "it" }, + { "Japanese", "ja" }, + { "Javanese", "jv" }, + { "Kalaallisut", "kl" }, + { "Kannada", "kn" }, + { "Kashmiri", "ks" }, + { "Kazakh", "kk" }, + { "Khmer", "km" }, + { "Kinyarwanda", "rw" }, + { "Kirghiz", "ky" }, + { "Korean", "ko" }, + { "Kurdish", "ku" }, + { "Latin", "la" }, + { "Latvian", "lv" }, + { "Lithuanian", "lt" }, + { "Macedonian", "mk" }, + { "Malagasy", "mg" }, + { "Malay", "ms" }, + { "Malayalam", "ml" }, + { "Maltese", "mt" }, + { "Manx", "gv" }, + { "Marathi", "mr" }, + { "Moldavian", "mo" }, + { "Mongolian", "mn" }, + { "Nepali", "ne" }, + { "Norwegian", "nb" }, /* Yes, "nb", not the obsolete "no". */ + { "Nyanja", "ny" }, + { "Nynorsk", "nn" }, + { "Oriya", "or" }, + { "Oromo", "om" }, + { "Panjabi", "pa" }, + { "Pashto", "ps" }, + { "Persian", "fa" }, + { "Polish", "pl" }, + { "Portuguese", "pt" }, + { "Portuguese, Brazilian", "pt_BR" }, + { "Punjabi", "pa" }, + { "Pushto", "ps" }, + { "Quechua", "qu" }, + { "Romanian", "ro" }, + { "Ruanda", "rw" }, + { "Rundi", "rn" }, + { "Russian", "ru" }, + { "Sami", "se_NO" }, /* Not just "se". */ + { "Sanskrit", "sa" }, + { "Scottish", "gd" }, + { "Serbian", "sr" }, + { "Simplified Chinese", "zh_CN" }, + { "Sindhi", "sd" }, + { "Sinhalese", "si" }, + { "Slovak", "sk" }, + { "Slovenian", "sl" }, + { "Somali", "so" }, + { "Spanish", "es" }, + { "Sundanese", "su" }, + { "Swahili", "sw" }, + { "Swedish", "sv" }, + { "Tagalog", "tl" }, + { "Tajik", "tg" }, + { "Tajiki", "tg" }, + { "Tamil", "ta" }, + { "Tatar", "tt" }, + { "Telugu", "te" }, + { "Thai", "th" }, + { "Tibetan", "bo" }, + { "Tigrinya", "ti" }, + { "Tongan", "to" }, + { "Traditional Chinese", "zh_TW" }, + { "Turkish", "tr" }, + { "Turkmen", "tk" }, + { "Uighur", "ug" }, + { "Ukrainian", "uk" }, + { "Urdu", "ur" }, + { "Uzbek", "uz" }, + { "Vietnamese", "vi" }, + { "Welsh", "cy" }, + { "Yiddish", "yi" } + }; + + /* Convert new-style locale names with language tags (ISO 639 and ISO 15924) + to Unix (ISO 639 and ISO 3166) names. */ + typedef struct { const char langtag[7+1]; const char unixy[12+1]; } + langtag_entry; + static const langtag_entry langtag_table[] = { + /* MacOS X has "az-Arab", "az-Cyrl", "az-Latn". + The default script for az on Unix is Latin. */ + { "az-Latn", "az" }, + /* MacOS X has "ga-dots". Does not yet exist on Unix. */ + { "ga-dots", "ga" }, + /* MacOS X has "kk-Cyrl". Does not yet exist on Unix. */ + /* MacOS X has "mn-Cyrl", "mn-Mong". + The default script for mn on Unix is Cyrillic. */ + { "mn-Cyrl", "mn" }, + /* MacOS X has "ms-Arab", "ms-Latn". + The default script for ms on Unix is Latin. */ + { "ms-Latn", "ms" }, + /* MacOS X has "tg-Cyrl". + The default script for tg on Unix is Cyrillic. */ + { "tg-Cyrl", "tg" }, + /* MacOS X has "tk-Cyrl". Does not yet exist on Unix. */ + /* MacOS X has "tt-Cyrl". + The default script for tt on Unix is Cyrillic. */ + { "tt-Cyrl", "tt" }, + /* MacOS X has "zh-Hans", "zh-Hant". + Country codes are used to distinguish these on Unix. */ + { "zh-Hans", "zh_CN" }, + { "zh-Hant", "zh_TW" } + }; + + /* Convert script names (ISO 15924) to Unix conventions. + See http://www.unicode.org/iso15924/iso15924-codes.html */ + typedef struct { const char script[4+1]; const char unixy[9+1]; } + script_entry; + static const script_entry script_table[] = { + { "Arab", "arabic" }, + { "Cyrl", "cyrillic" }, + { "Mong", "mongolian" } + }; + + /* Step 1: Convert using legacy_table. */ + if (name[0] >= 'A' && name[0] <= 'Z') + { + unsigned int i1, i2; + i1 = 0; + i2 = sizeof (legacy_table) / sizeof (legacy_entry); + while (i2 - i1 > 1) + { + /* At this point we know that if name occurs in legacy_table, + its index must be >= i1 and < i2. */ + unsigned int i = (i1 + i2) >> 1; + const legacy_entry *p = &legacy_table[i]; + if (strcmp (name, p->legacy) < 0) + i2 = i; + else + i1 = i; + } + if (strcmp (name, legacy_table[i1].legacy) == 0) + { + strcpy (name, legacy_table[i1].unixy); + return; + } + } + + /* Step 2: Convert using langtag_table and script_table. */ + if (strlen (name) == 7 && name[2] == '-') + { + unsigned int i1, i2; + i1 = 0; + i2 = sizeof (langtag_table) / sizeof (langtag_entry); + while (i2 - i1 > 1) + { + /* At this point we know that if name occurs in langtag_table, + its index must be >= i1 and < i2. */ + unsigned int i = (i1 + i2) >> 1; + const langtag_entry *p = &langtag_table[i]; + if (strcmp (name, p->langtag) < 0) + i2 = i; + else + i1 = i; + } + if (strcmp (name, langtag_table[i1].langtag) == 0) + { + strcpy (name, langtag_table[i1].unixy); + return; + } + + i1 = 0; + i2 = sizeof (script_table) / sizeof (script_entry); + while (i2 - i1 > 1) + { + /* At this point we know that if (name + 3) occurs in script_table, + its index must be >= i1 and < i2. */ + unsigned int i = (i1 + i2) >> 1; + const script_entry *p = &script_table[i]; + if (strcmp (name + 3, p->script) < 0) + i2 = i; + else + i1 = i; + } + if (strcmp (name + 3, script_table[i1].script) == 0) + { + name[2] = '@'; + strcpy (name + 3, script_table[i1].unixy); + return; + } + } + + /* Step 3: Convert new-style dash to Unix underscore. */ + { + char *p; + for (p = name; *p != '\0'; p++) + if (*p == '-') + *p = '_'; + } +} + +#endif + /* XPG3 defines the result of 'setlocale (category, NULL)' as: "Directs 'setlocale()' to query 'category' and return the current setting of 'local'." @@ -700,135 +984,183 @@ The result must not be freed; it is statically allocated. */ const char * -_nl_locale_name (int category, const char *categoryname) +_nl_locale_name_posix (int category, const char *categoryname) { - const char *retval; - -#ifndef WIN32 - /* Use 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 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. */ - retval = "C"; - } - } -# endif - - return retval; - -#else /* WIN32 */ - - /* Return an XPG style locale name language[_territory][@modifier]. - Don't even bother determining the codeset; it's not useful in this - context, because message catalogs are not specific to a single - codeset. */ - - LCID lcid; - LANGID langid; - int primary, sub; +#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL + return setlocale (category, NULL); +#else + const char *retval; - /* Let the user override the system settings through environment - variables, as on POSIX systems. */ + /* Setting of LC_ALL overrides all other. */ retval = getenv ("LC_ALL"); if (retval != NULL && retval[0] != '\0') return retval; + /* Next comes the name of the desired category. */ retval = getenv (categoryname); if (retval != NULL && retval[0] != '\0') return retval; + /* Last possibility is the LANG environment variable. */ retval = getenv ("LANG"); if (retval != NULL && retval[0] != '\0') return retval; - /* Use native Win32 API locale ID. */ - lcid = GetThreadLocale (); + return NULL; +#endif +} - /* Strip off the sorting rules, keep only the language part. */ - langid = LANGIDFROMLCID (lcid); +const char * +_nl_locale_name_default (void) +{ + /* POSIX:2001 says: + "All implementations shall define a locale as the default locale, to be + invoked when no environment variables are set, or set to the empty + string. This default locale can be the POSIX locale or any other + implementation-defined locale. Some implementations may provide + facilities for local installation administrators to set the default + locale, customizing it for each location. POSIX:2001 does not require + such a facility. */ - /* Split into language and territory part. */ - primary = PRIMARYLANGID (langid); - sub = SUBLANGID (langid); +#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined(WIN32_NATIVE)) - /* Dispatch on language. - See also http://www.unicode.org/unicode/onlinedat/languages.html . - For details about languages, see http://www.ethnologue.com/ . */ - switch (primary) - { - case LANG_AFRIKAANS: return "af_ZA"; - case LANG_ALBANIAN: return "sq_AL"; - case LANG_AMHARIC: return "am_ET"; - case LANG_ARABIC: - switch (sub) - { - case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA"; - case SUBLANG_ARABIC_IRAQ: return "ar_IQ"; - case SUBLANG_ARABIC_EGYPT: return "ar_EG"; - case SUBLANG_ARABIC_LIBYA: return "ar_LY"; - case SUBLANG_ARABIC_ALGERIA: return "ar_DZ"; - case SUBLANG_ARABIC_MOROCCO: return "ar_MA"; - case SUBLANG_ARABIC_TUNISIA: return "ar_TN"; - case SUBLANG_ARABIC_OMAN: return "ar_OM"; - case SUBLANG_ARABIC_YEMEN: return "ar_YE"; - case SUBLANG_ARABIC_SYRIA: return "ar_SY"; - case SUBLANG_ARABIC_JORDAN: return "ar_JO"; - case SUBLANG_ARABIC_LEBANON: return "ar_LB"; - case SUBLANG_ARABIC_KUWAIT: return "ar_KW"; - case SUBLANG_ARABIC_UAE: return "ar_AE"; - case SUBLANG_ARABIC_BAHRAIN: return "ar_BH"; - case SUBLANG_ARABIC_QATAR: return "ar_QA"; - } - return "ar"; - case LANG_ARMENIAN: return "hy_AM"; - case LANG_ASSAMESE: return "as_IN"; - case LANG_AZERI: - switch (sub) - { - /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */ - case SUBLANG_AZERI_LATIN: return "az_AZ@latin"; - case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic"; - } - return "az"; - case LANG_BASQUE: - return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */ - case LANG_BELARUSIAN: return "be_BY"; - case LANG_BENGALI: - switch (sub) - { - case SUBLANG_BENGALI_INDIA: return "bn_IN"; - case SUBLANG_BENGALI_BANGLADESH: return "bn_BD"; - } - return "bn"; - case LANG_BULGARIAN: return "bg_BG"; - case LANG_BURMESE: return "my_MM"; - case LANG_CAMBODIAN: return "km_KH"; - case LANG_CATALAN: return "ca_ES"; - case LANG_CHEROKEE: return "chr_US"; - case LANG_CHINESE: - switch (sub) - { - case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW"; - case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN"; - case SUBLANG_CHINESE_HONGKONG: return "zh_HK"; - case SUBLANG_CHINESE_SINGAPORE: return "zh_SG"; - case SUBLANG_CHINESE_MACAU: return "zh_MO"; - } - return "zh"; - case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN + /* The system does not have a way of setting the locale, other than the + POSIX specified environment variables. We use C as default locale. */ + return "C"; + +#else + + /* Return an XPG style locale name language[_territory][@modifier]. + Don't even bother determining the codeset; it's not useful in this + context, because message catalogs are not specific to a single + codeset. */ + +# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE + /* MacOS X 10.2 or newer */ + { + /* Cache the locale name, since CoreFoundation calls are expensive. */ + static const char *cached_localename; + + if (cached_localename == NULL) + { + char namebuf[256]; +# if HAVE_CFLOCALECOPYCURRENT /* MacOS X 10.3 or newer */ + CFLocaleRef locale = CFLocaleCopyCurrent (); + CFStringRef name = CFLocaleGetIdentifier (locale); + + if (CFStringGetCString (name, namebuf, sizeof(namebuf), + kCFStringEncodingASCII)) + { + _nl_locale_name_canonicalize (namebuf); + cached_localename = strdup (namebuf); + } + CFRelease (locale); +# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */ + CFTypeRef value = + CFPreferencesCopyAppValue (CFSTR ("AppleLocale"), + kCFPreferencesCurrentApplication); + if (value != NULL + && CFGetTypeID (value) == CFStringGetTypeID () + && CFStringGetCString ((CFStringRef)value, namebuf, sizeof(namebuf), + kCFStringEncodingASCII)) + { + _nl_locale_name_canonicalize (namebuf); + cached_localename = strdup (namebuf); + } +# endif + if (cached_localename == NULL) + cached_localename = "C"; + } + return cached_localename; + } + +# endif + +# if defined(WIN32_NATIVE) /* WIN32, not Cygwin */ + { + LCID lcid; + LANGID langid; + int primary, sub; + + /* Use native Win32 API locale ID. */ + lcid = GetThreadLocale (); + + /* Strip off the sorting rules, keep only the language part. */ + langid = LANGIDFROMLCID (lcid); + + /* Split into language and territory part. */ + primary = PRIMARYLANGID (langid); + sub = SUBLANGID (langid); + + /* Dispatch on language. + See also http://www.unicode.org/unicode/onlinedat/languages.html . + For details about languages, see http://www.ethnologue.com/ . */ + switch (primary) + { + case LANG_AFRIKAANS: return "af_ZA"; + case LANG_ALBANIAN: return "sq_AL"; + case LANG_AMHARIC: return "am_ET"; + case LANG_ARABIC: + switch (sub) + { + case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA"; + case SUBLANG_ARABIC_IRAQ: return "ar_IQ"; + case SUBLANG_ARABIC_EGYPT: return "ar_EG"; + case SUBLANG_ARABIC_LIBYA: return "ar_LY"; + case SUBLANG_ARABIC_ALGERIA: return "ar_DZ"; + case SUBLANG_ARABIC_MOROCCO: return "ar_MA"; + case SUBLANG_ARABIC_TUNISIA: return "ar_TN"; + case SUBLANG_ARABIC_OMAN: return "ar_OM"; + case SUBLANG_ARABIC_YEMEN: return "ar_YE"; + case SUBLANG_ARABIC_SYRIA: return "ar_SY"; + case SUBLANG_ARABIC_JORDAN: return "ar_JO"; + case SUBLANG_ARABIC_LEBANON: return "ar_LB"; + case SUBLANG_ARABIC_KUWAIT: return "ar_KW"; + case SUBLANG_ARABIC_UAE: return "ar_AE"; + case SUBLANG_ARABIC_BAHRAIN: return "ar_BH"; + case SUBLANG_ARABIC_QATAR: return "ar_QA"; + } + return "ar"; + case LANG_ARMENIAN: return "hy_AM"; + case LANG_ASSAMESE: return "as_IN"; + case LANG_AZERI: + switch (sub) + { + /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */ + case SUBLANG_AZERI_LATIN: return "az_AZ@latin"; + case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic"; + } + return "az"; + case LANG_BASQUE: + switch (sub) + { + case SUBLANG_DEFAULT: return "eu_ES"; + } + return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */ + case LANG_BELARUSIAN: return "be_BY"; + case LANG_BENGALI: + switch (sub) + { + case SUBLANG_BENGALI_INDIA: return "bn_IN"; + case SUBLANG_BENGALI_BANGLADESH: return "bn_BD"; + } + return "bn"; + case LANG_BULGARIAN: return "bg_BG"; + case LANG_BURMESE: return "my_MM"; + case LANG_CAMBODIAN: return "km_KH"; + case LANG_CATALAN: return "ca_ES"; + case LANG_CHEROKEE: return "chr_US"; + case LANG_CHINESE: + switch (sub) + { + case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW"; + case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN"; + case SUBLANG_CHINESE_HONGKONG: return "zh_HK"; + case SUBLANG_CHINESE_SINGAPORE: return "zh_SG"; + case SUBLANG_CHINESE_MACAU: return "zh_MO"; + } + return "zh"; + case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN * What used to be called Serbo-Croatian * should really now be two separate * languages because of political reasons. @@ -836,307 +1168,332 @@ _nl_locale_name (int category, const char *categoryname) * or Croatian.) * (I can feel those flames coming already.) */ - switch (sub) - { - case SUBLANG_DEFAULT: return "hr_HR"; - case SUBLANG_SERBIAN_LATIN: return "sr_CS"; - case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic"; - } - return "hr"; - case LANG_CZECH: return "cs_CZ"; - case LANG_DANISH: return "da_DK"; - case LANG_DIVEHI: return "dv_MV"; - case LANG_DUTCH: - switch (sub) - { - case SUBLANG_DUTCH: return "nl_NL"; - case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE"; - } - return "nl"; - case LANG_EDO: return "bin_NG"; - case LANG_ENGLISH: - switch (sub) - { - /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought - * English was the language spoken in England. - * Oh well. - */ - case SUBLANG_ENGLISH_US: return "en_US"; - case SUBLANG_ENGLISH_UK: return "en_GB"; - case SUBLANG_ENGLISH_AUS: return "en_AU"; - case SUBLANG_ENGLISH_CAN: return "en_CA"; - case SUBLANG_ENGLISH_NZ: return "en_NZ"; - case SUBLANG_ENGLISH_EIRE: return "en_IE"; - case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA"; - case SUBLANG_ENGLISH_JAMAICA: return "en_JM"; - case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */ - case SUBLANG_ENGLISH_BELIZE: return "en_BZ"; - case SUBLANG_ENGLISH_TRINIDAD: return "en_TT"; - case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW"; - case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH"; - case SUBLANG_ENGLISH_INDONESIA: return "en_ID"; - case SUBLANG_ENGLISH_HONGKONG: return "en_HK"; - case SUBLANG_ENGLISH_INDIA: return "en_IN"; - case SUBLANG_ENGLISH_MALAYSIA: return "en_MY"; - case SUBLANG_ENGLISH_SINGAPORE: return "en_SG"; - } - return "en"; - case LANG_ESTONIAN: return "et_EE"; - case LANG_FAEROESE: return "fo_FO"; - case LANG_FARSI: return "fa_IR"; - case LANG_FINNISH: return "fi_FI"; - case LANG_FRENCH: - switch (sub) - { - case SUBLANG_FRENCH: return "fr_FR"; - case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE"; - case SUBLANG_FRENCH_CANADIAN: return "fr_CA"; - case SUBLANG_FRENCH_SWISS: return "fr_CH"; - case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU"; - case SUBLANG_FRENCH_MONACO: return "fr_MC"; - case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */ - case SUBLANG_FRENCH_REUNION: return "fr_RE"; - case SUBLANG_FRENCH_CONGO: return "fr_CG"; - case SUBLANG_FRENCH_SENEGAL: return "fr_SN"; - case SUBLANG_FRENCH_CAMEROON: return "fr_CM"; - case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI"; - case SUBLANG_FRENCH_MALI: return "fr_ML"; - case SUBLANG_FRENCH_MOROCCO: return "fr_MA"; - case SUBLANG_FRENCH_HAITI: return "fr_HT"; - } - return "fr"; - case LANG_FRISIAN: return "fy_NL"; - case LANG_FULFULDE: - /* Spoken in Nigeria, Guinea, Senegal, Mali, Niger, Cameroon, Benin. */ - return "ff_NG"; - case LANG_GAELIC: - switch (sub) - { - case 0x01: /* SCOTTISH */ return "gd_GB"; - case 0x02: /* IRISH */ return "ga_IE"; - } - return "C"; - case LANG_GALICIAN: return "gl_ES"; - case LANG_GEORGIAN: return "ka_GE"; - case LANG_GERMAN: - switch (sub) - { - case SUBLANG_GERMAN: return "de_DE"; - case SUBLANG_GERMAN_SWISS: return "de_CH"; - case SUBLANG_GERMAN_AUSTRIAN: return "de_AT"; - case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU"; - case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI"; - } - return "de"; - case LANG_GREEK: return "el_GR"; - case LANG_GUARANI: return "gn_PY"; - case LANG_GUJARATI: return "gu_IN"; - case LANG_HAUSA: return "ha_NG"; - case LANG_HAWAIIAN: - /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers) - or Hawaii Creole English ("cpe_US", 600000 speakers)? */ - return "cpe_US"; - case LANG_HEBREW: return "he_IL"; - case LANG_HINDI: return "hi_IN"; - case LANG_HUNGARIAN: return "hu_HU"; - case LANG_IBIBIO: return "nic_NG"; - case LANG_ICELANDIC: return "is_IS"; - case LANG_IGBO: return "ig_NG"; - case LANG_INDONESIAN: return "id_ID"; - case LANG_INUKTITUT: return "iu_CA"; - case LANG_ITALIAN: - switch (sub) - { - case SUBLANG_ITALIAN: return "it_IT"; - case SUBLANG_ITALIAN_SWISS: return "it_CH"; - } - return "it"; - case LANG_JAPANESE: return "ja_JP"; - case LANG_KANNADA: return "kn_IN"; - case LANG_KANURI: return "kr_NG"; - case LANG_KASHMIRI: - switch (sub) - { - case SUBLANG_DEFAULT: return "ks_PK"; - case SUBLANG_KASHMIRI_INDIA: return "ks_IN"; - } - return "ks"; - case LANG_KAZAK: return "kk_KZ"; - case LANG_KONKANI: - /* FIXME: Adjust this when such locales appear on Unix. */ - return "kok_IN"; - case LANG_KOREAN: return "ko_KR"; - case LANG_KYRGYZ: return "ky_KG"; - case LANG_LAO: return "lo_LA"; - case LANG_LATIN: return "la_VA"; - case LANG_LATVIAN: return "lv_LV"; - case LANG_LITHUANIAN: return "lt_LT"; - case LANG_MACEDONIAN: return "mk_MK"; - case LANG_MALAY: - switch (sub) - { - case SUBLANG_MALAY_MALAYSIA: return "ms_MY"; - case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN"; - } - return "ms"; - case LANG_MALAYALAM: return "ml_IN"; - case LANG_MALTESE: return "mt_MT"; - case LANG_MANIPURI: - /* FIXME: Adjust this when such locales appear on Unix. */ - return "mni_IN"; - case LANG_MARATHI: return "mr_IN"; - case LANG_MONGOLIAN: - return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */ - case LANG_NEPALI: - switch (sub) - { - case SUBLANG_DEFAULT: return "ne_NP"; - case SUBLANG_NEPALI_INDIA: return "ne_IN"; - } - return "ne"; - case LANG_NORWEGIAN: - switch (sub) - { - case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO"; - case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO"; - } - return "no"; - case LANG_ORIYA: return "or_IN"; - case LANG_OROMO: return "om_ET"; - case LANG_PAPIAMENTU: return "pap_AN"; - case LANG_PASHTO: - return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */ - case LANG_POLISH: return "pl_PL"; - case LANG_PORTUGUESE: - switch (sub) - { - case SUBLANG_PORTUGUESE: return "pt_PT"; - /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT. - Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */ - case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR"; - } - return "pt"; - case LANG_PUNJABI: - switch (sub) - { - case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */ - case SUBLANG_PUNJABI_PAKISTAN: return "pa_PK"; /* Arabic script */ - } - return "pa"; - case LANG_RHAETO_ROMANCE: return "rm_CH"; - case LANG_ROMANIAN: - switch (sub) - { - case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO"; - case SUBLANG_ROMANIAN_MOLDOVA: return "ro_MD"; - } - return "ro"; - case LANG_RUSSIAN: - return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */ - case LANG_SAAMI: /* actually Northern Sami */ return "se_NO"; - case LANG_SANSKRIT: return "sa_IN"; - case LANG_SINDHI: - switch (sub) - { - case SUBLANG_SINDHI_INDIA: return "sd_IN"; - case SUBLANG_SINDHI_PAKISTAN: return "sd_PK"; - } - return "sd"; - case LANG_SINHALESE: return "si_LK"; - case LANG_SLOVAK: return "sk_SK"; - case LANG_SLOVENIAN: return "sl_SI"; - case LANG_SOMALI: return "so_SO"; - case LANG_SORBIAN: - /* FIXME: Adjust this when such locales appear on Unix. */ - return "wen_DE"; - case LANG_SPANISH: - switch (sub) - { - case SUBLANG_SPANISH: return "es_ES"; - case SUBLANG_SPANISH_MEXICAN: return "es_MX"; - case SUBLANG_SPANISH_MODERN: - return "es_ES@modern"; /* not seen on Unix */ - case SUBLANG_SPANISH_GUATEMALA: return "es_GT"; - case SUBLANG_SPANISH_COSTA_RICA: return "es_CR"; - case SUBLANG_SPANISH_PANAMA: return "es_PA"; - case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO"; - case SUBLANG_SPANISH_VENEZUELA: return "es_VE"; - case SUBLANG_SPANISH_COLOMBIA: return "es_CO"; - case SUBLANG_SPANISH_PERU: return "es_PE"; - case SUBLANG_SPANISH_ARGENTINA: return "es_AR"; - case SUBLANG_SPANISH_ECUADOR: return "es_EC"; - case SUBLANG_SPANISH_CHILE: return "es_CL"; - case SUBLANG_SPANISH_URUGUAY: return "es_UY"; - case SUBLANG_SPANISH_PARAGUAY: return "es_PY"; - case SUBLANG_SPANISH_BOLIVIA: return "es_BO"; - case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV"; - case SUBLANG_SPANISH_HONDURAS: return "es_HN"; - case SUBLANG_SPANISH_NICARAGUA: return "es_NI"; - case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR"; - } - return "es"; - case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */ - case LANG_SWAHILI: return "sw_KE"; - case LANG_SWEDISH: - switch (sub) - { - case SUBLANG_DEFAULT: return "sv_SE"; - case SUBLANG_SWEDISH_FINLAND: return "sv_FI"; - } - return "sv"; - case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */ - case LANG_TAGALOG: return "tl_PH"; - case LANG_TAJIK: return "tg_TJ"; - case LANG_TAMAZIGHT: - switch (sub) - { - /* FIXME: Adjust this when Tamazight locales appear on Unix. */ - case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic"; - case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin"; - } - return "ber_MA"; - case LANG_TAMIL: - return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */ - case LANG_TATAR: return "tt_RU"; - case LANG_TELUGU: return "te_IN"; - case LANG_THAI: return "th_TH"; - case LANG_TIBETAN: return "bo_CN"; - case LANG_TIGRINYA: - switch (sub) - { - case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET"; - case SUBLANG_TIGRINYA_ERITREA: return "ti_ER"; - } - return "ti"; - case LANG_TSONGA: return "ts_ZA"; - case LANG_TSWANA: return "tn_BW"; - case LANG_TURKISH: return "tr_TR"; - case LANG_TURKMEN: return "tk_TM"; - case LANG_UKRAINIAN: return "uk_UA"; - case LANG_URDU: - switch (sub) - { - case SUBLANG_URDU_PAKISTAN: return "ur_PK"; - case SUBLANG_URDU_INDIA: return "ur_IN"; - } - return "ur"; - case LANG_UZBEK: - switch (sub) - { - case SUBLANG_UZBEK_LATIN: return "uz_UZ"; - case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic"; - } - return "uz"; - case LANG_VENDA: return "ve_ZA"; - case LANG_VIETNAMESE: return "vi_VN"; - case LANG_WELSH: return "cy_GB"; - case LANG_XHOSA: return "xh_ZA"; - case LANG_YI: return "sit_CN"; - case LANG_YIDDISH: return "yi_IL"; - case LANG_YORUBA: return "yo_NG"; - case LANG_ZULU: return "zu_ZA"; - default: return "C"; - } - + switch (sub) + { + case SUBLANG_DEFAULT: return "hr_HR"; + case SUBLANG_SERBIAN_LATIN: return "sr_CS"; + case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic"; + } + return "hr"; + case LANG_CZECH: return "cs_CZ"; + case LANG_DANISH: return "da_DK"; + case LANG_DIVEHI: return "dv_MV"; + case LANG_DUTCH: + switch (sub) + { + case SUBLANG_DUTCH: return "nl_NL"; + case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE"; + } + return "nl"; + case LANG_EDO: return "bin_NG"; + case LANG_ENGLISH: + switch (sub) + { + /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought + * English was the language spoken in England. + * Oh well. + */ + case SUBLANG_ENGLISH_US: return "en_US"; + case SUBLANG_ENGLISH_UK: return "en_GB"; + case SUBLANG_ENGLISH_AUS: return "en_AU"; + case SUBLANG_ENGLISH_CAN: return "en_CA"; + case SUBLANG_ENGLISH_NZ: return "en_NZ"; + case SUBLANG_ENGLISH_EIRE: return "en_IE"; + case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA"; + case SUBLANG_ENGLISH_JAMAICA: return "en_JM"; + case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */ + case SUBLANG_ENGLISH_BELIZE: return "en_BZ"; + case SUBLANG_ENGLISH_TRINIDAD: return "en_TT"; + case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW"; + case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH"; + case SUBLANG_ENGLISH_INDONESIA: return "en_ID"; + case SUBLANG_ENGLISH_HONGKONG: return "en_HK"; + case SUBLANG_ENGLISH_INDIA: return "en_IN"; + case SUBLANG_ENGLISH_MALAYSIA: return "en_MY"; + case SUBLANG_ENGLISH_SINGAPORE: return "en_SG"; + } + return "en"; + case LANG_ESTONIAN: return "et_EE"; + case LANG_FAEROESE: return "fo_FO"; + case LANG_FARSI: return "fa_IR"; + case LANG_FINNISH: return "fi_FI"; + case LANG_FRENCH: + switch (sub) + { + case SUBLANG_FRENCH: return "fr_FR"; + case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE"; + case SUBLANG_FRENCH_CANADIAN: return "fr_CA"; + case SUBLANG_FRENCH_SWISS: return "fr_CH"; + case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU"; + case SUBLANG_FRENCH_MONACO: return "fr_MC"; + case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */ + case SUBLANG_FRENCH_REUNION: return "fr_RE"; + case SUBLANG_FRENCH_CONGO: return "fr_CG"; + case SUBLANG_FRENCH_SENEGAL: return "fr_SN"; + case SUBLANG_FRENCH_CAMEROON: return "fr_CM"; + case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI"; + case SUBLANG_FRENCH_MALI: return "fr_ML"; + case SUBLANG_FRENCH_MOROCCO: return "fr_MA"; + case SUBLANG_FRENCH_HAITI: return "fr_HT"; + } + return "fr"; + case LANG_FRISIAN: return "fy_NL"; + case LANG_FULFULDE: + /* Spoken in Nigeria, Guinea, Senegal, Mali, Niger, Cameroon, Benin. */ + return "ff_NG"; + case LANG_GAELIC: + switch (sub) + { + case 0x01: /* SCOTTISH */ return "gd_GB"; + case 0x02: /* IRISH */ return "ga_IE"; + } + return "C"; + case LANG_GALICIAN: return "gl_ES"; + case LANG_GEORGIAN: return "ka_GE"; + case LANG_GERMAN: + switch (sub) + { + case SUBLANG_GERMAN: return "de_DE"; + case SUBLANG_GERMAN_SWISS: return "de_CH"; + case SUBLANG_GERMAN_AUSTRIAN: return "de_AT"; + case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU"; + case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI"; + } + return "de"; + case LANG_GREEK: return "el_GR"; + case LANG_GUARANI: return "gn_PY"; + case LANG_GUJARATI: return "gu_IN"; + case LANG_HAUSA: return "ha_NG"; + case LANG_HAWAIIAN: + /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers) + or Hawaii Creole English ("cpe_US", 600000 speakers)? */ + return "cpe_US"; + case LANG_HEBREW: return "he_IL"; + case LANG_HINDI: return "hi_IN"; + case LANG_HUNGARIAN: return "hu_HU"; + case LANG_IBIBIO: return "nic_NG"; + case LANG_ICELANDIC: return "is_IS"; + case LANG_IGBO: return "ig_NG"; + case LANG_INDONESIAN: return "id_ID"; + case LANG_INUKTITUT: return "iu_CA"; + case LANG_ITALIAN: + switch (sub) + { + case SUBLANG_ITALIAN: return "it_IT"; + case SUBLANG_ITALIAN_SWISS: return "it_CH"; + } + return "it"; + case LANG_JAPANESE: return "ja_JP"; + case LANG_KANNADA: return "kn_IN"; + case LANG_KANURI: return "kr_NG"; + case LANG_KASHMIRI: + switch (sub) + { + case SUBLANG_DEFAULT: return "ks_PK"; + case SUBLANG_KASHMIRI_INDIA: return "ks_IN"; + } + return "ks"; + case LANG_KAZAK: return "kk_KZ"; + case LANG_KONKANI: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "kok_IN"; + case LANG_KOREAN: return "ko_KR"; + case LANG_KYRGYZ: return "ky_KG"; + case LANG_LAO: return "lo_LA"; + case LANG_LATIN: return "la_VA"; + case LANG_LATVIAN: return "lv_LV"; + case LANG_LITHUANIAN: return "lt_LT"; + case LANG_MACEDONIAN: return "mk_MK"; + case LANG_MALAY: + switch (sub) + { + case SUBLANG_MALAY_MALAYSIA: return "ms_MY"; + case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN"; + } + return "ms"; + case LANG_MALAYALAM: return "ml_IN"; + case LANG_MALTESE: return "mt_MT"; + case LANG_MANIPURI: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "mni_IN"; + case LANG_MARATHI: return "mr_IN"; + case LANG_MONGOLIAN: + switch (sub) + { + case SUBLANG_DEFAULT: return "mn_MN"; + } + return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */ + case LANG_NEPALI: + switch (sub) + { + case SUBLANG_DEFAULT: return "ne_NP"; + case SUBLANG_NEPALI_INDIA: return "ne_IN"; + } + return "ne"; + case LANG_NORWEGIAN: + switch (sub) + { + case SUBLANG_NORWEGIAN_BOKMAL: return "nb_NO"; + case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO"; + } + return "no"; + case LANG_ORIYA: return "or_IN"; + case LANG_OROMO: return "om_ET"; + case LANG_PAPIAMENTU: return "pap_AN"; + case LANG_PASHTO: + return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */ + case LANG_POLISH: return "pl_PL"; + case LANG_PORTUGUESE: + switch (sub) + { + case SUBLANG_PORTUGUESE: return "pt_PT"; + /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT. + Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */ + case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR"; + } + return "pt"; + case LANG_PUNJABI: + switch (sub) + { + case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */ + case SUBLANG_PUNJABI_PAKISTAN: return "pa_PK"; /* Arabic script */ + } + return "pa"; + case LANG_RHAETO_ROMANCE: return "rm_CH"; + case LANG_ROMANIAN: + switch (sub) + { + case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO"; + case SUBLANG_ROMANIAN_MOLDOVA: return "ro_MD"; + } + return "ro"; + case LANG_RUSSIAN: + switch (sub) + { + case SUBLANG_DEFAULT: return "ru_RU"; + } + return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */ + case LANG_SAAMI: /* actually Northern Sami */ return "se_NO"; + case LANG_SANSKRIT: return "sa_IN"; + case LANG_SINDHI: + switch (sub) + { + case SUBLANG_SINDHI_INDIA: return "sd_IN"; + case SUBLANG_SINDHI_PAKISTAN: return "sd_PK"; + } + return "sd"; + case LANG_SINHALESE: return "si_LK"; + case LANG_SLOVAK: return "sk_SK"; + case LANG_SLOVENIAN: return "sl_SI"; + case LANG_SOMALI: return "so_SO"; + case LANG_SORBIAN: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "wen_DE"; + case LANG_SPANISH: + switch (sub) + { + case SUBLANG_SPANISH: return "es_ES"; + case SUBLANG_SPANISH_MEXICAN: return "es_MX"; + case SUBLANG_SPANISH_MODERN: + return "es_ES@modern"; /* not seen on Unix */ + case SUBLANG_SPANISH_GUATEMALA: return "es_GT"; + case SUBLANG_SPANISH_COSTA_RICA: return "es_CR"; + case SUBLANG_SPANISH_PANAMA: return "es_PA"; + case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO"; + case SUBLANG_SPANISH_VENEZUELA: return "es_VE"; + case SUBLANG_SPANISH_COLOMBIA: return "es_CO"; + case SUBLANG_SPANISH_PERU: return "es_PE"; + case SUBLANG_SPANISH_ARGENTINA: return "es_AR"; + case SUBLANG_SPANISH_ECUADOR: return "es_EC"; + case SUBLANG_SPANISH_CHILE: return "es_CL"; + case SUBLANG_SPANISH_URUGUAY: return "es_UY"; + case SUBLANG_SPANISH_PARAGUAY: return "es_PY"; + case SUBLANG_SPANISH_BOLIVIA: return "es_BO"; + case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV"; + case SUBLANG_SPANISH_HONDURAS: return "es_HN"; + case SUBLANG_SPANISH_NICARAGUA: return "es_NI"; + case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR"; + } + return "es"; + case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */ + case LANG_SWAHILI: return "sw_KE"; + case LANG_SWEDISH: + switch (sub) + { + case SUBLANG_DEFAULT: return "sv_SE"; + case SUBLANG_SWEDISH_FINLAND: return "sv_FI"; + } + return "sv"; + case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */ + case LANG_TAGALOG: return "tl_PH"; + case LANG_TAJIK: return "tg_TJ"; + case LANG_TAMAZIGHT: + switch (sub) + { + /* FIXME: Adjust this when Tamazight locales appear on Unix. */ + case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic"; + case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin"; + } + return "ber_MA"; + case LANG_TAMIL: + switch (sub) + { + case SUBLANG_DEFAULT: return "ta_IN"; + } + return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */ + case LANG_TATAR: return "tt_RU"; + case LANG_TELUGU: return "te_IN"; + case LANG_THAI: return "th_TH"; + case LANG_TIBETAN: return "bo_CN"; + case LANG_TIGRINYA: + switch (sub) + { + case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET"; + case SUBLANG_TIGRINYA_ERITREA: return "ti_ER"; + } + return "ti"; + case LANG_TSONGA: return "ts_ZA"; + case LANG_TSWANA: return "tn_BW"; + case LANG_TURKISH: return "tr_TR"; + case LANG_TURKMEN: return "tk_TM"; + case LANG_UKRAINIAN: return "uk_UA"; + case LANG_URDU: + switch (sub) + { + case SUBLANG_URDU_PAKISTAN: return "ur_PK"; + case SUBLANG_URDU_INDIA: return "ur_IN"; + } + return "ur"; + case LANG_UZBEK: + switch (sub) + { + case SUBLANG_UZBEK_LATIN: return "uz_UZ"; + case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic"; + } + return "uz"; + case LANG_VENDA: return "ve_ZA"; + case LANG_VIETNAMESE: return "vi_VN"; + case LANG_WELSH: return "cy_GB"; + case LANG_XHOSA: return "xh_ZA"; + case LANG_YI: return "sit_CN"; + case LANG_YIDDISH: return "yi_IL"; + case LANG_YORUBA: return "yo_NG"; + case LANG_ZULU: return "zu_ZA"; + default: return "C"; + } + } +# endif #endif } + +const char * +_nl_locale_name (int category, const char *categoryname) +{ + const char *retval; + + retval = _nl_locale_name_posix (category, categoryname); + if (retval != NULL) + return retval; + + return _nl_locale_name_default (); +} diff --git a/intl/log.c b/intl/log.c index cb6076e80..e3ab5d0e6 100644 --- a/intl/log.c +++ b/intl/log.c @@ -1,5 +1,5 @@ /* Log file output. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2005 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Bruno Haible <[email protected]>. */ @@ -26,6 +26,13 @@ #include <stdlib.h> #include <string.h> +/* Handle multi-threaded applications. */ +#ifdef _LIBC +# include <bits/libc-lock.h> +#else +# include "lock.h" +#endif + /* Print an ASCII string with quotes and escape sequences where needed. */ static void print_escaped (FILE *stream, const char *str) @@ -48,13 +55,14 @@ print_escaped (FILE *stream, const char *str) putc ('"', stream); } -/* Add to the log file an entry denoting a failed translation. */ -void -_nl_log_untranslated (const char *logfilename, const char *domainname, - const char *msgid1, const char *msgid2, int plural) +static char *last_logfilename = NULL; +static FILE *last_logfile = NULL; +__libc_lock_define_initialized (static, lock) + +static inline void +_nl_log_untranslated_locked (const char *logfilename, const char *domainname, + const char *msgid1, const char *msgid2, int plural) { - static char *last_logfilename = NULL; - static FILE *last_logfile = NULL; FILE *logfile; /* Can we reuse the last opened logfile? */ @@ -96,3 +104,13 @@ _nl_log_untranslated (const char *logfilename, const char *domainname, fprintf (logfile, "\nmsgstr \"\"\n"); putc ('\n', logfile); } + +/* Add to the log file an entry denoting a failed translation. */ +void +_nl_log_untranslated (const char *logfilename, const char *domainname, + const char *msgid1, const char *msgid2, int plural) +{ + __libc_lock_lock (lock); + _nl_log_untranslated_locked (logfilename, domainname, msgid1, msgid2, plural); + __libc_lock_unlock (lock); +} diff --git a/intl/ngettext.c b/intl/ngettext.c index e73e00c48..a33529c20 100644 --- a/intl/ngettext.c +++ b/intl/ngettext.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/os2compat.c b/intl/os2compat.c index c8dc33e7c..d041de2af 100644 --- a/intl/os2compat.c +++ b/intl/os2compat.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define OS2_AWARE diff --git a/intl/os2compat.h b/intl/os2compat.h index 4f74e8c03..a18d582cd 100644 --- a/intl/os2compat.h +++ b/intl/os2compat.h @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* When included from os2compat.h we need all the original definitions */ diff --git a/intl/osdep.c b/intl/osdep.c index b37259838..3cc35c03b 100644 --- a/intl/osdep.c +++ b/intl/osdep.c @@ -1,5 +1,5 @@ /* OS dependent parts of libintl. - Copyright (C) 2001-2002 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2006 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 @@ -13,10 +13,12 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if defined __EMX__ +#if defined __CYGWIN__ +# include "intl-exports.c" +#elif defined __EMX__ # include "os2compat.c" #else /* Avoid AIX compiler warning. */ diff --git a/intl/plural-exp.c b/intl/plural-exp.c index 8c04e6426..f518bf1dc 100644 --- a/intl/plural-exp.c +++ b/intl/plural-exp.c @@ -1,5 +1,5 @@ /* Expression parsing for plural form selection. - Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 2000-2001, 2003, 2005 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 2000. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -27,7 +27,7 @@ #include "plural-exp.h" -#if (defined __GNUC__ && !defined __APPLE_CC__) \ +#if (defined __GNUC__ && !(__APPLE_CC__ > 1)) \ || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) /* These structs are the constant expression for the germanic plural diff --git a/intl/plural-exp.h b/intl/plural-exp.h index 49e2c5bfc..dc590d374 100644 --- a/intl/plural-exp.h +++ b/intl/plural-exp.h @@ -1,5 +1,5 @@ /* Expression parsing and evaluation for plural form selection. - Copyright (C) 2000-2003 Free Software Foundation, Inc. + Copyright (C) 2000-2003, 2005 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 2000. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PLURAL_EXP_H @@ -110,7 +110,7 @@ extern void EXTRACT_PLURAL_EXPRESSION (const char *nullentry, unsigned long int *npluralsp) internal_function; -#if !defined (_LIBC) && !defined (IN_LIBINTL) +#if !defined (_LIBC) && !defined (IN_LIBINTL) && !defined (IN_LIBGLOCALE) extern unsigned long int plural_eval (struct expression *pexp, unsigned long int n); #endif diff --git a/intl/plural.c b/intl/plural.c index 72494f9eb..5f73b403f 100644 --- a/intl/plural.c +++ b/intl/plural.c @@ -19,7 +19,7 @@ #line 1 "plural.y" /* Expression parsing for plural form selection. - Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 2000-2001, 2003, 2005 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 2000. This program is free software; you can redistribute it and/or modify it @@ -34,13 +34,14 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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. */ +/* For bison < 2.0, 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. + This can go away once the AM_INTL_SUBDIR macro requires bison >= 2.0. */ #if defined _AIX && !defined __GNUC__ #pragma alloca #endif @@ -51,6 +52,7 @@ #include <stddef.h> #include <stdlib.h> +#include <string.h> #include "plural-exp.h" /* The main function generated by the parser is called __gettextparse, @@ -62,7 +64,7 @@ #define YYLEX_PARAM &((struct parse_args *) arg)->cp #define YYPARSE_PARAM arg -#line 49 "plural.y" +#line 51 "plural.y" #ifndef YYSTYPE typedef union { unsigned long int num; @@ -72,7 +74,7 @@ typedef union { # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif -#line 55 "plural.y" +#line 57 "plural.y" /* Prototypes for local functions. */ static int yylex (YYSTYPE *lval, const char **pexp); @@ -212,8 +214,8 @@ static const short yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const short yyrline[] = { - 0, 150, 158, 162, 166, 170, 174, 178, 182, 186, - 190, 194, 199 + 0, 152, 160, 164, 168, 172, 176, 180, 184, 188, + 192, 196, 201 }; #endif @@ -296,7 +298,7 @@ static const short yycheck[] = #define YYPURE 1 /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/local/share/bison/bison.simple" +#line 3 "bison.simple" /* Skeleton output parser for bison, @@ -609,7 +611,7 @@ yystpcpy (yydest, yysrc) # endif #endif -#line 315 "/usr/local/share/bison/bison.simple" +#line 315 "bison.simple" /* The user can define YYPARSE_PARAM as the name of an argument to be passed @@ -1003,7 +1005,7 @@ yyreduce: switch (yyn) { case 1: -#line 151 "plural.y" +#line 153 "plural.y" { if (yyvsp[0].exp == NULL) YYABORT; @@ -1011,75 +1013,75 @@ case 1: } break; case 2: -#line 159 "plural.y" +#line 161 "plural.y" { yyval.exp = new_exp_3 (qmop, yyvsp[-4].exp, yyvsp[-2].exp, yyvsp[0].exp); } break; case 3: -#line 163 "plural.y" +#line 165 "plural.y" { yyval.exp = new_exp_2 (lor, yyvsp[-2].exp, yyvsp[0].exp); } break; case 4: -#line 167 "plural.y" +#line 169 "plural.y" { yyval.exp = new_exp_2 (land, yyvsp[-2].exp, yyvsp[0].exp); } break; case 5: -#line 171 "plural.y" +#line 173 "plural.y" { yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); } break; case 6: -#line 175 "plural.y" +#line 177 "plural.y" { yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); } break; case 7: -#line 179 "plural.y" +#line 181 "plural.y" { yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); } break; case 8: -#line 183 "plural.y" +#line 185 "plural.y" { yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp); } break; case 9: -#line 187 "plural.y" +#line 189 "plural.y" { yyval.exp = new_exp_1 (lnot, yyvsp[0].exp); } break; case 10: -#line 191 "plural.y" +#line 193 "plural.y" { yyval.exp = new_exp_0 (var); } break; case 11: -#line 195 "plural.y" +#line 197 "plural.y" { if ((yyval.exp = new_exp_0 (num)) != NULL) yyval.exp->val.num = yyvsp[0].num; } break; case 12: -#line 200 "plural.y" +#line 202 "plural.y" { yyval.exp = yyvsp[-1].exp; } break; } -#line 705 "/usr/local/share/bison/bison.simple" +#line 705 "bison.simple" yyvsp -= yylen; @@ -1310,7 +1312,7 @@ yyreturn: #endif return yyresult; } -#line 205 "plural.y" +#line 207 "plural.y" void diff --git a/intl/plural.y b/intl/plural.y index 4d33bd7c7..45d68e949 100644 --- a/intl/plural.y +++ b/intl/plural.y @@ -1,6 +1,6 @@ %{ /* Expression parsing for plural form selection. - Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 2000-2001, 2003, 2005 Free Software Foundation, Inc. Written by Ulrich Drepper <[email protected]>, 2000. This program is free software; you can redistribute it and/or modify it @@ -15,13 +15,14 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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. */ +/* For bison < 2.0, 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. + This can go away once the AM_INTL_SUBDIR macro requires bison >= 2.0. */ #if defined _AIX && !defined __GNUC__ #pragma alloca #endif @@ -32,6 +33,7 @@ #include <stddef.h> #include <stdlib.h> +#include <string.h> #include "plural-exp.h" /* The main function generated by the parser is called __gettextparse, diff --git a/intl/printf-args.c b/intl/printf-args.c index f6f3219e7..47b73d2c1 100644 --- a/intl/printf-args.c +++ b/intl/printf-args.c @@ -1,5 +1,5 @@ /* Decomposed printf argument list. - Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002-2003, 2005-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -80,15 +80,40 @@ printf_fetchargs (va_list args, arguments *a) break; #ifdef HAVE_WINT_T case TYPE_WIDE_CHAR: - ap->a.a_wide_char = va_arg (args, wint_t); + /* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by + default argument promotions", this is not the case in mingw32, + where wint_t is 'unsigned short'. */ + ap->a.a_wide_char = + (sizeof (wint_t) < sizeof (int) + ? va_arg (args, int) + : va_arg (args, wint_t)); break; #endif case TYPE_STRING: ap->a.a_string = va_arg (args, const char *); + /* A null pointer is an invalid argument for "%s", but in practice + it occurs quite frequently in printf statements that produce + debug output. Use a fallback in this case. */ + if (ap->a.a_string == NULL) + ap->a.a_string = "(NULL)"; break; #ifdef HAVE_WCHAR_T case TYPE_WIDE_STRING: ap->a.a_wide_string = va_arg (args, const wchar_t *); + /* A null pointer is an invalid argument for "%ls", but in practice + it occurs quite frequently in printf statements that produce + debug output. Use a fallback in this case. */ + if (ap->a.a_wide_string == NULL) + { + static const wchar_t wide_null_string[] = + { + (wchar_t)'(', + (wchar_t)'N', (wchar_t)'U', (wchar_t)'L', (wchar_t)'L', + (wchar_t)')', + (wchar_t)0 + }; + ap->a.a_wide_string = wide_null_string; + } break; #endif case TYPE_POINTER: diff --git a/intl/printf-args.h b/intl/printf-args.h index f11e64c04..625b8036a 100644 --- a/intl/printf-args.h +++ b/intl/printf-args.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PRINTF_ARGS_H diff --git a/intl/printf-parse.c b/intl/printf-parse.c index d19f903d7..20240e379 100644 --- a/intl/printf-parse.c +++ b/intl/printf-parse.c @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H diff --git a/intl/printf-parse.h b/intl/printf-parse.h index 8aec50e2a..e78533895 100644 --- a/intl/printf-parse.h +++ b/intl/printf-parse.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PRINTF_PARSE_H diff --git a/intl/printf.c b/intl/printf.c index 878646c2d..275968b37 100644 --- a/intl/printf.c +++ b/intl/printf.c @@ -1,5 +1,5 @@ /* Formatted output to strings, using POSIX/XSI format strings with positions. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2006 Free Software Foundation, Inc. Written by Bruno Haible <[email protected]>, 2003. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -61,6 +61,14 @@ char *alloca (); #define STATIC static +/* This needs to be consistent with libgnuintl.h.in. */ +#if defined __NetBSD__ || defined __CYGWIN__ || defined __MINGW32__ +/* Don't break __attribute__((format(printf,M,N))). + This redefinition is only possible because the libc in NetBSD, Cygwin, + mingw does not have a function __printf__. */ +# define libintl_printf __printf__ +#endif + /* Define auxiliary functions declared in "printf-args.h". */ #include "printf-args.c" diff --git a/intl/ref-add.sin b/intl/ref-add.sin index 167374e3c..3678c2892 100644 --- a/intl/ref-add.sin +++ b/intl/ref-add.sin @@ -14,7 +14,7 @@ # # 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, +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. # # Written by Bruno Haible <[email protected]>. diff --git a/intl/ref-del.sin b/intl/ref-del.sin index 613cf37f3..0c12d8e95 100644 --- a/intl/ref-del.sin +++ b/intl/ref-del.sin @@ -14,7 +14,7 @@ # # 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, +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. # # Written by Bruno Haible <[email protected]>. diff --git a/intl/relocatable.c b/intl/relocatable.c index bf7c70854..7cc8daf77 100644 --- a/intl/relocatable.c +++ b/intl/relocatable.c @@ -1,5 +1,5 @@ /* Provide relocatable packages. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003-2005 Free Software Foundation, Inc. Written by Bruno Haible <[email protected]>, 2003. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -45,7 +45,7 @@ # include "xalloc.h" #endif -#if defined _WIN32 || defined __WIN32__ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ # define WIN32_LEAN_AND_MEAN # include <windows.h> #endif @@ -72,20 +72,20 @@ ISSLASH(C) tests whether C is a directory separator character. 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 */ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Win32, Cygwin, 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_PATH_WITH_DIR(P) \ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) -# define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) +# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) #else /* Unix */ # define ISSLASH(C) ((C) == '/') # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) -# define FILESYSTEM_PREFIX_LEN(P) 0 +# define FILE_SYSTEM_PREFIX_LEN(P) 0 #endif /* Original installation prefix. */ @@ -189,7 +189,7 @@ compute_curr_prefix (const char *orig_installprefix, /* Determine the current installation directory. */ { - const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname); + const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname); const char *p = curr_pathname + strlen (curr_pathname); char *q; @@ -216,7 +216,7 @@ compute_curr_prefix (const char *orig_installprefix, const char *rp = rel_installdir + strlen (rel_installdir); const char *cp = curr_installdir + strlen (curr_installdir); const char *cp_base = - curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir); + curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir); while (rp > rel_installdir && cp > cp_base) { @@ -234,8 +234,11 @@ compute_curr_prefix (const char *orig_installprefix, same = true; break; } -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ - /* Win32, OS/2, DOS - case insignificant filesystem */ + /* Do case-insensitive comparison if the filesystem is always or + often case-insensitive. It's better to accept the comparison + if the difference is only in case, rather than to fail. */ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */ if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) break; @@ -280,7 +283,7 @@ compute_curr_prefix (const char *orig_installprefix, /* Full pathname of shared library, or NULL. */ static char *shared_library_fullname; -#if defined _WIN32 || defined __WIN32__ +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ /* Determine the full pathname of the shared library when it is loaded. */ @@ -302,13 +305,31 @@ DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) /* Shouldn't happen. */ return FALSE; - shared_library_fullname = strdup (location); + { +#if defined __CYGWIN__ + /* On Cygwin, we need to convert paths coming from Win32 system calls + to the Unix-like slashified notation. */ + static char location_as_posix_path[2 * MAX_PATH]; + /* There's no error return defined for cygwin_conv_to_posix_path. + See cygwin-api/func-cygwin-conv-to-posix-path.html. + Does it overflow the buffer of expected size MAX_PATH or does it + truncate the path? I don't know. Let's catch both. */ + cygwin_conv_to_posix_path (location, location_as_posix_path); + location_as_posix_path[MAX_PATH - 1] = '\0'; + if (strlen (location_as_posix_path) >= MAX_PATH - 1) + /* A sign of buffer overflow or path truncation. */ + return FALSE; + shared_library_fullname = strdup (location_as_posix_path); +#else + shared_library_fullname = strdup (location); +#endif + } } return TRUE; } -#else /* Unix */ +#else /* Unix except Cygwin */ static void find_shared_library_fullname () @@ -359,15 +380,15 @@ find_shared_library_fullname () #endif } -#endif /* WIN32 / Unix */ +#endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */ /* Return the full pathname of the current shared library. Return NULL if unknown. - Guaranteed to work only on Linux and Woe32. */ + Guaranteed to work only on Linux, Cygwin and Woe32. */ static char * get_shared_library_fullname () { -#if !(defined _WIN32 || defined __WIN32__) +#if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__) static bool tried_find_shared_library_fullname; if (!tried_find_shared_library_fullname) { diff --git a/intl/relocatable.h b/intl/relocatable.h index 48c5b71e2..f6d38321a 100644 --- a/intl/relocatable.h +++ b/intl/relocatable.h @@ -1,5 +1,5 @@ /* Provide relocatable packages. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. Written by Bruno Haible <[email protected]>, 2003. This program is free software; you can redistribute it and/or modify it @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _RELOCATABLE_H @@ -31,7 +31,9 @@ extern "C" { /* When building a DLL, we must export some functions. Note that because this is a private .h file, we don't need to use __declspec(dllimport) in any case. */ -#if defined _MSC_VER && BUILDING_DLL +#if HAVE_VISIBILITY && BUILDING_DLL +# define RELOCATABLE_DLL_EXPORTED __attribute__((__visibility__("default"))) +#elif defined _MSC_VER && BUILDING_DLL # define RELOCATABLE_DLL_EXPORTED __declspec(dllexport) #else # define RELOCATABLE_DLL_EXPORTED diff --git a/intl/textdomain.c b/intl/textdomain.c index 8745a8435..c316460fd 100644 --- a/intl/textdomain.c +++ b/intl/textdomain.c @@ -1,5 +1,5 @@ /* Implementation of the textdomain(3) function. - Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -23,21 +23,21 @@ #include <stdlib.h> #include <string.h> +#include "gettextP.h" #ifdef _LIBC # include <libintl.h> #else # include "libgnuintl.h" #endif -#include "gettextP.h" +/* Handle multi-threaded applications. */ #ifdef _LIBC -/* We have to handle multi-threaded applications. */ # include <bits/libc-lock.h> +# define gl_rwlock_define __libc_rwlock_define +# define gl_rwlock_wrlock __libc_rwlock_wrlock +# define gl_rwlock_unlock __libc_rwlock_unlock #else -/* Provide dummy implementation if this is outside glibc. */ -# define __libc_rwlock_define(CLASS, NAME) -# define __libc_rwlock_wrlock(NAME) -# define __libc_rwlock_unlock(NAME) +# include "lock.h" #endif /* The internal variables in the standalone libintl.a must have different @@ -71,7 +71,7 @@ extern const char *_nl_current_default_domain attribute_hidden; #endif /* Lock variable to protect the global data in the gettext implementation. */ -__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) +gl_rwlock_define (extern, _nl_state_lock attribute_hidden) /* Set the current default message catalog to DOMAINNAME. If DOMAINNAME is null, return the current default. @@ -86,7 +86,7 @@ TEXTDOMAIN (const char *domainname) if (domainname == NULL) return (char *) _nl_current_default_domain; - __libc_rwlock_wrlock (_nl_state_lock); + gl_rwlock_wrlock (_nl_state_lock); old_domain = (char *) _nl_current_default_domain; @@ -130,7 +130,7 @@ TEXTDOMAIN (const char *domainname) free (old_domain); } - __libc_rwlock_unlock (_nl_state_lock); + gl_rwlock_unlock (_nl_state_lock); return new_domain; } diff --git a/intl/vasnprintf.c b/intl/vasnprintf.c index 8a62282d7..cef29a756 100644 --- a/intl/vasnprintf.c +++ b/intl/vasnprintf.c @@ -1,5 +1,5 @@ /* vsprintf with automatic memory allocation. - Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002-2006 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). @@ -41,7 +41,7 @@ #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ #include <string.h> /* memcpy(), strlen() */ #include <errno.h> /* errno */ -#include <limits.h> /* CHAR_BIT */ +#include <limits.h> /* CHAR_BIT, INT_MAX */ #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ #if WIDE_CHAR_VERSION # include "wprintf-parse.h" @@ -52,6 +52,11 @@ /* Checked size_t computations. */ #include "xsize.h" +/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ +#ifndef EOVERFLOW +# define EOVERFLOW E2BIG +#endif + #ifdef HAVE_WCHAR_T # ifdef HAVE_WCSLEN # define local_wcslen wcslen @@ -316,9 +321,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar const CHAR_T *digitp = dp->precision_start + 1; precision = 0; - do + while (digitp != dp->precision_end) precision = xsum (xtimes (precision, 10), *digitp++ - '0'); - while (digitp != dp->precision_end); } } @@ -331,28 +335,28 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Multiply by 2, as an estimate for FLAG_GROUP. */ + tmp_length = xsum (tmp_length, tmp_length); + /* Add 1, to account for a leading sign. */ + tmp_length = xsum (tmp_length, 1); break; case 'o': @@ -362,8 +366,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) @@ -371,15 +374,17 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Add 1, to account for a leading sign. */ + tmp_length = xsum (tmp_length, 1); break; case 'x': case 'X': @@ -389,8 +394,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) @@ -398,15 +402,17 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Add 2, to account for a leading sign or alternate form. */ + tmp_length = xsum (tmp_length, 2); break; case 'f': case 'F': @@ -864,8 +870,19 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar free (buf_malloced); CLEANUP (); *lengthp = length; + if (length > INT_MAX) + goto length_overflow; return result; + length_overflow: + /* We could produce such a big string, but its length doesn't fit into + an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in + this case. */ + if (result != resultbuf) + free (result); + errno = EOVERFLOW; + return NULL; + out_of_memory: if (!(result == resultbuf || result == NULL)) free (result); diff --git a/intl/vasnprintf.h b/intl/vasnprintf.h index 65f1bc13d..e67b88da3 100644 --- a/intl/vasnprintf.h +++ b/intl/vasnprintf.h @@ -1,5 +1,5 @@ /* vsprintf with automatic memory allocation. - Copyright (C) 2002-2003 Free Software Foundation, Inc. + Copyright (C) 2002-2004 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 @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _VASNPRINTF_H @@ -48,7 +48,24 @@ extern "C" { If successful, return the address of the string (this may be = RESULTBUF if no dynamic memory allocation was necessary) and set *LENGTHP to the number of resulting bytes, excluding the trailing NUL. Upon error, set - errno and return NULL. */ + errno and return NULL. + + When dynamic memory allocation occurs, the preallocated buffer is left + alone (with possibly modified contents). This makes it possible to use + a statically allocated or stack-allocated buffer, like this: + + char buf[100]; + size_t len = sizeof (buf); + char *output = vasnprintf (buf, &len, format, args); + if (output == NULL) + ... error handling ...; + else + { + ... use the output string ...; + if (output != buf) + free (output); + } + */ extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) diff --git a/intl/vasnwprintf.h b/intl/vasnwprintf.h index d3cef4cbc..6ff03ce16 100644 --- a/intl/vasnwprintf.h +++ b/intl/vasnwprintf.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _VASNWPRINTF_H diff --git a/intl/wprintf-parse.h b/intl/wprintf-parse.h index 24a2cfc28..600b89adc 100644 --- a/intl/wprintf-parse.h +++ b/intl/wprintf-parse.h @@ -13,7 +13,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _WPRINTF_PARSE_H diff --git a/intl/xsize.h b/intl/xsize.h index 362e24b72..b3023a7d4 100644 --- a/intl/xsize.h +++ b/intl/xsize.h @@ -14,7 +14,7 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _XSIZE_H |