From: Bruno Haible Date: Thu, 19 Jun 2003 12:45:06 +0000 (+0000) Subject: Add an implementation of printf(), fprintf() etc. that supports formatting X-Git-Tag: v0.13~432 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f58ba018630aa17c2636572aa557ee744b0e856a;p=thirdparty%2Fgettext.git Add an implementation of printf(), fprintf() etc. that supports formatting with positions, for those systems that lack it (NetBSD, Woe32). --- diff --git a/ChangeLog b/ChangeLog index 5e7f1450f..a2f1566b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-06-19 Bruno Haible + + * PACKAGING: Add intmax.m4, longdouble.m4, longlong.m4, + printf-posix.m4, signed.m4, wchar_t.m4, wint_t.m4. + 2003-06-18 Bruno Haible * config/install-sh: Update from automake-1.7.5. diff --git a/PACKAGING b/PACKAGING index b92d00724..9a53831f2 100644 --- a/PACKAGING +++ b/PACKAGING @@ -111,6 +111,7 @@ following file list. $prefix/share/aclocal/glibc21.m4 $prefix/share/aclocal/iconv.m4 $prefix/share/aclocal/intdiv0.m4 + $prefix/share/aclocal/intmax.m4 $prefix/share/aclocal/inttypes.m4 $prefix/share/aclocal/inttypes_h.m4 $prefix/share/aclocal/inttypes-pri.m4 @@ -119,12 +120,18 @@ following file list. $prefix/share/aclocal/lib-ld.m4 $prefix/share/aclocal/lib-link.m4 $prefix/share/aclocal/lib-prefix.m4 + $prefix/share/aclocal/longdouble.m4 + $prefix/share/aclocal/longlong.m4 $prefix/share/aclocal/nls.m4 $prefix/share/aclocal/po.m4 + $prefix/share/aclocal/printf-posix.m4 $prefix/share/aclocal/progtest.m4 + $prefix/share/aclocal/signed.m4 $prefix/share/aclocal/stdint_h.m4 $prefix/share/aclocal/uintmax_t.m4 $prefix/share/aclocal/ulonglong.m4 + $prefix/share/aclocal/wchar_t.m4 + $prefix/share/aclocal/wint_t.m4 $prefix/share/emacs/site-lisp/po-compat.el $prefix/share/emacs/site-lisp/po-compat.elc $prefix/share/emacs/site-lisp/po-mode.el diff --git a/gettext-runtime/ChangeLog b/gettext-runtime/ChangeLog index 58c8c96e9..2f9a688a4 100644 --- a/gettext-runtime/ChangeLog +++ b/gettext-runtime/ChangeLog @@ -1,3 +1,11 @@ +2003-06-19 Bruno Haible + + * Makefile.am (config.h_vms, config.h.msvc): Update. + (intl/libgnuintl.h_vms, intl/libgnuintl.h.msvc-static): New rule. + (all-local): Depend on them. + (intl/libgnuintl.h.msvc-shared): Also perform some AC_SUBST + substitutions. + 2003-06-19 Bruno Haible * configure.ac: New option --disable-libasprintf. diff --git a/gettext-runtime/Makefile.am b/gettext-runtime/Makefile.am index 347d6394b..99ed8ae96 100644 --- a/gettext-runtime/Makefile.am +++ b/gettext-runtime/Makefile.am @@ -69,12 +69,16 @@ config.h_vms: config.h.in ../version.sh -e 's/#undef HAVE_LC_MESSAGES$$/#define HAVE_LC_MESSAGES 1/' \ -e 's/#undef HAVE_LIMITS_H$$/#define HAVE_LIMITS_H 1/' \ -e 's/#undef HAVE_LOCALE_H$$/#define HAVE_LOCALE_H 1/' \ + -e 's/#undef HAVE_LONG_DOUBLE$$/#define HAVE_LONG_DOUBLE 1/' \ + -e 's/#undef HAVE_LONG_LONG$$/#define HAVE_LONG_LONG 1/' \ -e 's/#undef HAVE_MALLOC_H$$/#define HAVE_MALLOC_H 1/' \ -e 's/#undef HAVE_MEMMOVE$$/#define HAVE_MEMMOVE 1/' \ -e 's/#undef HAVE_MEMORY_H$$/#define HAVE_MEMORY_H 1/' \ -e 's/#undef HAVE_MMAP$$/#define HAVE_MMAP 1/' \ -e 's/#undef HAVE_MUNMAP$$/#define HAVE_MUNMAP 1/' \ -e 's/#undef HAVE_NL_TYPES_H$$/#define HAVE_NL_TYPES_H 1/' \ + -e 's/#undef HAVE_POSIX_PRINTF$$/#define HAVE_POSIX_PRINTF 1/' \ + -e 's/#undef HAVE_PTRDIFF_T$$/#define HAVE_PTRDIFF_T 1/' \ -e 's/#undef HAVE_PUTENV$$/#define HAVE_PUTENV 1/' \ -e 's/#undef HAVE_SETENV$$/#define HAVE_SETENV 1/' \ -e 's/#undef HAVE_SETLOCALE$$/#define HAVE_SETLOCALE 1/' \ @@ -94,6 +98,9 @@ config.h_vms: config.h.in ../version.sh -e 's/#undef HAVE_UNSETENV$$/#define HAVE_UNSETENV 1/' \ -e 's/#undef HAVE_UNSIGNED_LONG_LONG$$/#define HAVE_UNSIGNED_LONG_LONG 1/' \ -e 's/#undef HAVE_VPRINTF$$/#define HAVE_VPRINTF 1/' \ + -e 's/#undef HAVE_WCHAR_T$$/#define HAVE_WCHAR_T 1/' \ + -e 's/#undef HAVE_WINT_T$$/#define HAVE_WINT_T 1/' \ + -e 's/#undef HAVE_WPRINTF$$/#define HAVE_WPRINTF 1/' \ -e 's/#undef ICONV_CONST$$/#define ICONV_CONST/' \ -e 's/#undef STDC_HEADERS$$/#define STDC_HEADERS 1/' \ -e 's/#undef realpath$$/#define realpath rpl_realpath/' \ @@ -104,6 +111,15 @@ config.h_vms: config.h.in ../version.sh # vms_jackets.h is a header that comes with Compaq's "porting library". # KEEP_CRTL_SETLOCALE tells it to not override the native locale support. +intl/libgnuintl.h_vms: intl/libgnuintl.h.in + sed -e 's,@''HAVE_POSIX_PRINTF''@,1,g ' \ + -e 's,@''HAVE_ASPRINTF''@,0,g' \ + -e 's,@''HAVE_SNPRINTF''@,0,g' \ + -e 's,@''HAVE_WPRINTF''@,1,g' \ + < $(srcdir)/intl/libgnuintl.h.in > $@ + +all-local: intl/libgnuintl.h_vms + EXTRA_DIST += Makefile.vms config.h_vms @@ -120,9 +136,12 @@ config.h.msvc: config.h.in ../version.sh -e 's/#undef HAVE_ICONV$$/#define HAVE_ICONV 1/' \ -e 's/#undef HAVE_LIMITS_H$$/#define HAVE_LIMITS_H 1/' \ -e 's/#undef HAVE_LOCALE_H$$/#define HAVE_LOCALE_H 1/' \ + -e 's/#undef HAVE_LONG_DOUBLE$$/#define HAVE_LONG_DOUBLE 1/' \ -e 's/#undef HAVE_MEMMOVE$$/#define HAVE_MEMMOVE 1/' \ + -e 's/#undef HAVE_PTRDIFF_T$$/#define HAVE_PTRDIFF_T 1/' \ -e 's/#undef HAVE_PUTENV$$/#define HAVE_PUTENV 1/' \ -e 's/#undef HAVE_SETLOCALE$$/#define HAVE_SETLOCALE 1/' \ + -e 's/#undef HAVE_SNPRINTF$$/#define HAVE_SNPRINTF 1/' \ -e 's/#undef HAVE_STDDEF_H$$/#define HAVE_STDDEF_H 1/' \ -e 's/#undef HAVE_STDLIB_H$$/#define HAVE_STDLIB_H 1/' \ -e 's/#undef HAVE_STRDUP$$/#define HAVE_STRDUP 1/' \ @@ -132,6 +151,9 @@ config.h.msvc: config.h.in ../version.sh -e 's/#undef HAVE_SYS_STAT_H$$/#define HAVE_SYS_STAT_H 1/' \ -e 's/#undef HAVE_SYS_TYPES_H$$/#define HAVE_SYS_TYPES_H 1/' \ -e 's/#undef HAVE_VPRINTF$$/#define HAVE_VPRINTF 1/' \ + -e 's/#undef HAVE_WCHAR_T$$/#define HAVE_WCHAR_T 1/' \ + -e 's/#undef HAVE_WINT_T$$/#define HAVE_WINT_T 1/' \ + -e 's/#undef HAVE_WPRINTF$$/#define HAVE_WPRINTF 1/' \ -e 's/#undef ICONV_CONST$$/#define ICONV_CONST const/' \ -e 's/#undef STACK_DIRECTION$$/#define STACK_DIRECTION -1/' \ -e 's/#undef STDC_HEADERS$$/#define STDC_HEADERS 1/' \ @@ -142,9 +164,22 @@ config.h.msvc: config.h.in ../version.sh -e '/#undef INSTALLPREFIX$$/d' \ < $(srcdir)/config.h.in > $@ -intl/libgnuintl.h.msvc-shared: intl/libgnuintl.h.in windows/dllexport.h - sed -e 's/extern \([^"]\)/extern LIBINTL_DLL_EXPORTED \1/' -e '/#define _LIBINTL_H/r windows/dllexport.h' < $(srcdir)/intl/libgnuintl.h.in > $@ +intl/libgnuintl.h.msvc-static: intl/libgnuintl.h.in + sed -e 's,@''HAVE_POSIX_PRINTF''@,0,g ' \ + -e 's,@''HAVE_ASPRINTF''@,0,g' \ + -e 's,@''HAVE_SNPRINTF''@,0,g' \ + -e 's,@''HAVE_WPRINTF''@,1,g' \ + < $(srcdir)/intl/libgnuintl.h.in > $@ -all-local: intl/libgnuintl.h.msvc-shared +intl/libgnuintl.h.msvc-shared: intl/libgnuintl.h.in windows/dllexport.h + sed -e 's,@''HAVE_POSIX_PRINTF''@,0,g ' \ + -e 's,@''HAVE_ASPRINTF''@,0,g' \ + -e 's,@''HAVE_SNPRINTF''@,0,g' \ + -e 's,@''HAVE_WPRINTF''@,1,g' \ + -e 's/extern \([^"]\)/extern LIBINTL_DLL_EXPORTED \1/' \ + -e '/#define _LIBINTL_H/r windows/dllexport.h' \ + < $(srcdir)/intl/libgnuintl.h.in > $@ + +all-local: intl/libgnuintl.h.msvc-static intl/libgnuintl.h.msvc-shared EXTRA_DIST += README.woe32 Makefile.msvc config.h.msvc windows/dllexport.h windows/intl.rc diff --git a/gettext-runtime/intl/ChangeLog b/gettext-runtime/intl/ChangeLog index 9aeb58f81..f2645f87c 100644 --- a/gettext-runtime/intl/ChangeLog +++ b/gettext-runtime/intl/ChangeLog @@ -1,3 +1,32 @@ +2003-06-19 Bruno Haible + + * printf-args.h: New file, from ../libasprintf. + * printf-args.c: New file, from ../libasprintf. + * printf-parse.h: New file, from ../libasprintf. + * printf-parse.c: New file, from ../libasprintf. + * vasnprintf.h: New file, from ../libasprintf. + * vasnprintf.c: New file, from ../libasprintf. + * wprintf-parse.h: New file. + * vasnwprintf.h: New file. + * printf.c: New file. + * libgnuintl.h.in (fprintf, vfprintf, printf, vprintf, sprintf, + vsprintf, snprintf, vsnprintf, asprintf, vasprintf, fwprintf, + vfwprintf, wprintf, vwprintf, swprintf, vswprintf): New fallback + macros. + * Makefile.in (HEADERS): Add printf-args.h, printf-args.c, + printf-parse.h, wprintf-parse.h, printf-parse.c, vasnprintf.h, + vasnwprintf.h, vasnprintf.c. + (SOURCES): Add printf.c. + (OBJECTS): Add printf.$lo. + (DISTFILES.gettext): Add libgnuintl.h_vms, libgnuintl.h.msvc-static. + (printf.lo): New rule. + (libgnuintl.h): Also perform some AC_SUBST substitutions. + (printf.$lo): New dependencies. + * Makefile.msvc (OBJECTS): Add printf.obj. + (libgnuintl.h): Use libgnuintl.h.msvc-static. + (printf.obj): New rule. + * Makefile.vms (libgnuintl.h): Use libgnuintl.h_vms. + 2003-06-12 Bruno Haible * libgnuintl.h (_INTL_REDIRECT_ASM): Don't define when using Mingw. diff --git a/gettext-runtime/intl/Makefile.in b/gettext-runtime/intl/Makefile.in index 882396481..a4d299298 100644 --- a/gettext-runtime/intl/Makefile.in +++ b/gettext-runtime/intl/Makefile.in @@ -73,6 +73,9 @@ HEADERS = \ eval-plural.h \ localcharset.h \ relocatable.h \ + printf-args.h printf-args.c \ + printf-parse.h wprintf-parse.h printf-parse.c \ + vasnprintf.h vasnwprintf.h vasnprintf.c \ os2compat.h \ libgnuintl.h.in SOURCES = \ @@ -96,6 +99,7 @@ SOURCES = \ relocatable.c \ localename.c \ log.c \ + printf.c \ osdep.c \ os2compat.c \ intl-compat.c @@ -120,6 +124,7 @@ OBJECTS = \ relocatable.$lo \ localename.$lo \ log.$lo \ + printf.$lo \ osdep.$lo \ intl-compat.$lo DISTFILES.common = Makefile.in \ @@ -127,7 +132,8 @@ config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) DISTFILES.generated = plural.c DISTFILES.normal = VERSION DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc \ -Makefile.vms libgnuintl.h.msvc-shared README.woe32 Makefile.msvc +libgnuintl.h_vms Makefile.vms \ +libgnuintl.h.msvc-static libgnuintl.h.msvc-shared README.woe32 Makefile.msvc DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h @@ -209,6 +215,8 @@ 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 osdep.lo: $(srcdir)/osdep.c $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c intl-compat.lo: $(srcdir)/intl-compat.c @@ -224,7 +232,11 @@ ref-del.sed: $(srcdir)/ref-del.sin INCLUDES = -I. -I$(srcdir) -I.. libgnuintl.h: $(srcdir)/libgnuintl.h.in - cp $(srcdir)/libgnuintl.h.in libgnuintl.h + sed -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 @@ -412,6 +424,7 @@ dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h dcigettext.$lo: $(srcdir)/eval-plural.h localcharset.$lo: $(srcdir)/localcharset.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)/printf-parse.c $(srcdir)/vasnprintf.h $(srcdir)/vasnwprintf.h $(srcdir)/vasnprintf.c tags: TAGS diff --git a/gettext-runtime/intl/Makefile.msvc b/gettext-runtime/intl/Makefile.msvc index 552a3f6c9..7fbb2f75c 100644 --- a/gettext-runtime/intl/Makefile.msvc +++ b/gettext-runtime/intl/Makefile.msvc @@ -99,7 +99,7 @@ INSTALL_DATA = copy SHELL = /bin/sh -OBJECTS = bindtextdom.obj dcgettext.obj dgettext.obj gettext.obj finddomain.obj loadmsgcat.obj localealias.obj textdomain.obj l10nflist.obj explodename.obj dcigettext.obj dcngettext.obj dngettext.obj ngettext.obj plural.obj plural-exp.obj localcharset.obj relocatable.obj localename.obj log.obj osdep.obj intl-compat.obj +OBJECTS = bindtextdom.obj dcgettext.obj dgettext.obj gettext.obj finddomain.obj loadmsgcat.obj localealias.obj textdomain.obj l10nflist.obj explodename.obj dcigettext.obj dcngettext.obj dngettext.obj ngettext.obj plural.obj plural-exp.obj localcharset.obj relocatable.obj localename.obj log.obj printf.obj osdep.obj intl-compat.obj RESOURCES = intl.res @@ -107,7 +107,7 @@ all : intl.lib libintl.h libgnuintl.h : !if !$(DLL) - $(LN) $(srcdir)\libgnuintl.h.in libgnuintl.h + $(LN) $(srcdir)\libgnuintl.h.msvc-static libgnuintl.h !else $(LN) $(srcdir)\libgnuintl.h.msvc-shared libgnuintl.h !endif @@ -172,6 +172,9 @@ localename.obj : $(srcdir)\localename.c libgnuintl.h log.obj : $(srcdir)\log.c libgnuintl.h $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c $(srcdir)\log.c +printf.obj : $(srcdir)\printf.c libgnuintl.h $(srcdir)\printf-args.h $(srcdir)\printf-args.c $(srcdir)\printf-parse.h $(srcdir)\wprintf-parse.h $(srcdir)\printf-parse.c $(srcdir)\vasnprintf.h $(srcdir)\vasnwprintf.h $(srcdir)\vasnprintf.c + $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c $(srcdir)\printf.c + osdep.obj : $(srcdir)\osdep.c libgnuintl.h $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c $(srcdir)\osdep.c diff --git a/gettext-runtime/intl/Makefile.vms b/gettext-runtime/intl/Makefile.vms index 4db38fbe6..97ab01129 100644 --- a/gettext-runtime/intl/Makefile.vms +++ b/gettext-runtime/intl/Makefile.vms @@ -51,8 +51,7 @@ all : intl.olb,libintl.h write sys$output "Nothing else to be done for 'all'." libgnuintl.h : - if f$search("$(srcdir)libgnuintl.h_in") .nes. "" then $(LN) $(srcdir)libgnuintl.h_in libgnuintl.h - if f$search("$(srcdir)libgnuintl.h_in") .eqs. "" then $(LN) $(srcdir)libgnuintl.h.in libgnuintl.h + $(LN) $(srcdir)libgnuintl.h_vms libgnuintl.h bindtextdom.obj : $(srcdir)bindtextdom.c,libgnuintl.h,$(srcdir)gettextP.h,$(srcdir)gmo.h,$(srcdir)loadinfo.h $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) $(srcdir)bindtextdom.c diff --git a/gettext-runtime/intl/libgnuintl.h.in b/gettext-runtime/intl/libgnuintl.h.in index b6c526c83..ce06b18be 100644 --- a/gettext-runtime/intl/libgnuintl.h.in +++ b/gettext-runtime/intl/libgnuintl.h.in @@ -289,6 +289,97 @@ extern char *bind_textdomain_codeset _INTL_PARAMS ((const char *__domainname, #endif +/* Support for format strings with positions in *printf(), following the + POSIX/XSI specification. + Note: These replacements for the *printf() functions are visible only + in source files that #include or #include "gettext.h". + Packages that use *printf() in source files that don't refer to _() + or gettext() but for which the format string could be the return value + of _() or gettext() need to add this #include. Oh well. */ + +#if !@HAVE_POSIX_PRINTF@ + +#include +#include + +/* Get va_list. */ +#if __STDC__ || defined __cplusplus +# include +#else +# include +#endif + +#undef fprintf +#define fprintf libintl_fprintf +extern int fprintf _INTL_PARAMS ((FILE *, const char *, ...)); +#undef vfprintf +#define vfprintf libintl_vfprintf +extern int vfprintf _INTL_PARAMS ((FILE *, const char *, va_list)); + +#undef printf +#define printf libintl_printf +extern int printf _INTL_PARAMS ((const char *, ...)); +#undef vprintf +#define vprintf libintl_vprintf +extern int vprintf _INTL_PARAMS ((const char *, va_list)); + +#undef sprintf +#define sprintf libintl_sprintf +extern int sprintf _INTL_PARAMS ((char *, const char *, ...)); +#undef vsprintf +#define vsprintf libintl_vsprintf +extern int vsprintf _INTL_PARAMS ((char *, const char *, va_list)); + +#if @HAVE_SNPRINTF@ + +#undef snprintf +#define snprintf libintl_snprintf +extern int snprintf _INTL_PARAMS ((char *, size_t, const char *, ...)); +#undef vsnprintf +#define vsnprintf libintl_vsnprintf +extern int vsnprintf _INTL_PARAMS ((char *, size_t, const char *, va_list)); + +#endif + +#if @HAVE_ASPRINTF@ + +#undef asprintf +#define asprintf libintl_asprintf +extern int asprintf _INTL_PARAMS ((char **, const char *, ...)); +#undef vasprintf +#define vasprintf libintl_vasprintf +extern int vasprintf _INTL_PARAMS ((char **, const char *, va_list)); + +#endif + +#if @HAVE_WPRINTF@ + +#undef fwprintf +#define fwprintf libintl_fwprintf +extern int fwprintf _INTL_PARAMS ((FILE *, const wchar_t *, ...)); +#undef vfwprintf +#define vfwprintf libintl_vfwprintf +extern int vfwprintf _INTL_PARAMS ((FILE *, const wchar_t *, va_list)); + +#undef wprintf +#define wprintf libintl_wprintf +extern int wprintf _INTL_PARAMS ((const wchar_t *, ...)); +#undef vwprintf +#define vwprintf libintl_vwprintf +extern int vwprintf _INTL_PARAMS ((const wchar_t *, va_list)); + +#undef swprintf +#define swprintf libintl_swprintf +extern int swprintf _INTL_PARAMS ((wchar_t *, size_t, const wchar_t *, ...)); +#undef vswprintf +#define vswprintf libintl_vswprintf +extern int vswprintf _INTL_PARAMS ((wchar_t *, size_t, const wchar_t *, va_list)); + +#endif + +#endif + + /* Support for relocatable packages. */ /* Sets the original and the current installation prefix of the package. diff --git a/gettext-runtime/intl/printf-args.c b/gettext-runtime/intl/printf-args.c new file mode 100644 index 000000000..f39197402 --- /dev/null +++ b/gettext-runtime/intl/printf-args.c @@ -0,0 +1,119 @@ +/* Decomposed printf argument list. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Specification. */ +#include "printf-args.h" + +#ifdef STATIC +STATIC +#endif +int +printf_fetchargs (va_list args, arguments *a) +{ + unsigned int i; + argument *ap; + + for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++) + switch (ap->type) + { + case TYPE_SCHAR: + ap->a.a_schar = va_arg (args, /*signed char*/ int); + break; + case TYPE_UCHAR: + ap->a.a_uchar = va_arg (args, /*unsigned char*/ int); + break; + case TYPE_SHORT: + ap->a.a_short = va_arg (args, /*short*/ int); + break; + case TYPE_USHORT: + ap->a.a_ushort = va_arg (args, /*unsigned short*/ int); + break; + case TYPE_INT: + ap->a.a_int = va_arg (args, int); + break; + case TYPE_UINT: + ap->a.a_uint = va_arg (args, unsigned int); + break; + case TYPE_LONGINT: + ap->a.a_longint = va_arg (args, long int); + break; + case TYPE_ULONGINT: + ap->a.a_ulongint = va_arg (args, unsigned long int); + break; +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + ap->a.a_longlongint = va_arg (args, long long int); + break; + case TYPE_ULONGLONGINT: + ap->a.a_ulonglongint = va_arg (args, unsigned long long int); + break; +#endif + case TYPE_DOUBLE: + ap->a.a_double = va_arg (args, double); + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + ap->a.a_longdouble = va_arg (args, long double); + break; +#endif + case TYPE_CHAR: + ap->a.a_char = va_arg (args, int); + break; +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: + ap->a.a_wide_char = va_arg (args, wint_t); + break; +#endif + case TYPE_STRING: + ap->a.a_string = va_arg (args, const char *); + break; +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: + ap->a.a_wide_string = va_arg (args, const wchar_t *); + break; +#endif + case TYPE_POINTER: + ap->a.a_pointer = va_arg (args, void *); + break; + case TYPE_COUNT_SCHAR_POINTER: + ap->a.a_count_schar_pointer = va_arg (args, signed char *); + break; + case TYPE_COUNT_SHORT_POINTER: + ap->a.a_count_short_pointer = va_arg (args, short *); + break; + case TYPE_COUNT_INT_POINTER: + ap->a.a_count_int_pointer = va_arg (args, int *); + break; + case TYPE_COUNT_LONGINT_POINTER: + ap->a.a_count_longint_pointer = va_arg (args, long int *); + break; +#ifdef HAVE_LONG_LONG + case TYPE_COUNT_LONGLONGINT_POINTER: + ap->a.a_count_longlongint_pointer = va_arg (args, long long int *); + break; +#endif + default: + /* Unknown type. */ + return -1; + } + return 0; +} diff --git a/gettext-runtime/intl/printf-args.h b/gettext-runtime/intl/printf-args.h new file mode 100644 index 000000000..35114a8fa --- /dev/null +++ b/gettext-runtime/intl/printf-args.h @@ -0,0 +1,134 @@ +/* Decomposed printf argument list. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _PRINTF_ARGS_H +#define _PRINTF_ARGS_H + +/* Get wchar_t. */ +#ifdef HAVE_WCHAR_T +# include +#endif + +/* Get wint_t. */ +#ifdef HAVE_WINT_T +# include +#endif + +/* Get va_list. */ +#include + + +/* Argument types */ +typedef enum +{ + TYPE_NONE, + TYPE_SCHAR, + TYPE_UCHAR, + TYPE_SHORT, + TYPE_USHORT, + TYPE_INT, + TYPE_UINT, + TYPE_LONGINT, + TYPE_ULONGINT, +#ifdef HAVE_LONG_LONG + TYPE_LONGLONGINT, + TYPE_ULONGLONGINT, +#endif + TYPE_DOUBLE, +#ifdef HAVE_LONG_DOUBLE + TYPE_LONGDOUBLE, +#endif + TYPE_CHAR, +#ifdef HAVE_WINT_T + TYPE_WIDE_CHAR, +#endif + TYPE_STRING, +#ifdef HAVE_WCHAR_T + TYPE_WIDE_STRING, +#endif + TYPE_POINTER, + TYPE_COUNT_SCHAR_POINTER, + TYPE_COUNT_SHORT_POINTER, + TYPE_COUNT_INT_POINTER, + TYPE_COUNT_LONGINT_POINTER +#ifdef HAVE_LONG_LONG +, TYPE_COUNT_LONGLONGINT_POINTER +#endif +} arg_type; + +/* Polymorphic argument */ +typedef struct +{ + arg_type type; + union + { + signed char a_schar; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long int a_longint; + unsigned long int a_ulongint; +#ifdef HAVE_LONG_LONG + long long int a_longlongint; + unsigned long long int a_ulonglongint; +#endif + float a_float; + double a_double; +#ifdef HAVE_LONG_DOUBLE + long double a_longdouble; +#endif + int a_char; +#ifdef HAVE_WINT_T + wint_t a_wide_char; +#endif + const char* a_string; +#ifdef HAVE_WCHAR_T + const wchar_t* a_wide_string; +#endif + void* a_pointer; + signed char * a_count_schar_pointer; + short * a_count_short_pointer; + int * a_count_int_pointer; + long int * a_count_longint_pointer; +#ifdef HAVE_LONG_LONG + long long int * a_count_longlongint_pointer; +#endif + } + a; +} +argument; + +typedef struct +{ + unsigned int count; + argument *arg; +} +arguments; + + +/* Fetch the arguments, putting them into a. */ +#ifdef STATIC +STATIC +#else +extern +#endif +int printf_fetchargs (va_list args, arguments *a); + +#endif /* _PRINTF_ARGS_H */ diff --git a/gettext-runtime/intl/printf-parse.c b/gettext-runtime/intl/printf-parse.c new file mode 100644 index 000000000..ff61c174c --- /dev/null +++ b/gettext-runtime/intl/printf-parse.c @@ -0,0 +1,498 @@ +/* Formatted output to strings. + Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Specification. */ +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +#else +# include "printf-parse.h" +#endif + +/* Get size_t, NULL. */ +#include + +/* Get intmax_t. */ +#if HAVE_STDINT_H_WITH_UINTMAX +# include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +# include +#endif + +/* malloc(), realloc(), free(). */ +#include + +#if WIDE_CHAR_VERSION +# define PRINTF_PARSE wprintf_parse +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +#else +# define PRINTF_PARSE printf_parse +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +#endif + +#ifdef STATIC +STATIC +#endif +int +PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) +{ + const CHAR_T *cp = format; /* pointer into format */ + int arg_posn = 0; /* number of regular arguments consumed */ + unsigned int d_allocated; /* allocated elements of d->dir */ + unsigned int a_allocated; /* allocated elements of a->arg */ + unsigned int max_width_length = 0; + unsigned int max_precision_length = 0; + + d->count = 0; + d_allocated = 1; + d->dir = malloc (d_allocated * sizeof (DIRECTIVE)); + if (d->dir == NULL) + /* Out of memory. */ + return -1; + + a->count = 0; + a_allocated = 0; + a->arg = NULL; + +#define REGISTER_ARG(_index_,_type_) \ + { \ + unsigned int n = (_index_); \ + if (n >= a_allocated) \ + { \ + argument *memory; \ + a_allocated = 2 * a_allocated; \ + if (a_allocated <= n) \ + a_allocated = n + 1; \ + memory = (a->arg \ + ? realloc (a->arg, a_allocated * sizeof (argument)) \ + : malloc (a_allocated * sizeof (argument))); \ + if (memory == NULL) \ + /* Out of memory. */ \ + goto error; \ + a->arg = memory; \ + } \ + while (a->count <= n) \ + a->arg[a->count++].type = TYPE_NONE; \ + if (a->arg[n].type == TYPE_NONE) \ + a->arg[n].type = (_type_); \ + else if (a->arg[n].type != (_type_)) \ + /* Ambiguous type for positional argument. */ \ + goto error; \ + } + + while (*cp != '\0') + { + CHAR_T c = *cp++; + if (c == '%') + { + int arg_index = -1; + DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ + + /* Initialize the next directive. */ + dp->dir_start = cp - 1; + dp->flags = 0; + dp->width_start = NULL; + dp->width_end = NULL; + dp->width_arg_index = -1; + dp->precision_start = NULL; + dp->precision_end = NULL; + dp->precision_arg_index = -1; + dp->arg_index = -1; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const CHAR_T *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + arg_index = n - 1; + cp = np + 1; + } + } + + /* Read the flags. */ + for (;;) + { + if (*cp == '\'') + { + dp->flags |= FLAG_GROUP; + cp++; + } + else if (*cp == '-') + { + dp->flags |= FLAG_LEFT; + cp++; + } + else if (*cp == '+') + { + dp->flags |= FLAG_SHOWSIGN; + cp++; + } + else if (*cp == ' ') + { + dp->flags |= FLAG_SPACE; + cp++; + } + else if (*cp == '#') + { + dp->flags |= FLAG_ALT; + cp++; + } + else if (*cp == '0') + { + dp->flags |= FLAG_ZERO; + cp++; + } + else + break; + } + + /* Parse the field width. */ + if (*cp == '*') + { + dp->width_start = cp; + cp++; + dp->width_end = cp; + if (max_width_length < 1) + max_width_length = 1; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const CHAR_T *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + dp->width_arg_index = n - 1; + cp = np + 1; + } + } + if (dp->width_arg_index < 0) + dp->width_arg_index = arg_posn++; + REGISTER_ARG (dp->width_arg_index, TYPE_INT); + } + else if (*cp >= '0' && *cp <= '9') + { + unsigned int width_length; + + dp->width_start = cp; + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + dp->width_end = cp; + width_length = dp->width_end - dp->width_start; + if (max_width_length < width_length) + max_width_length = width_length; + } + + /* Parse the precision. */ + if (*cp == '.') + { + cp++; + if (*cp == '*') + { + dp->precision_start = cp - 1; + cp++; + dp->precision_end = cp; + if (max_precision_length < 2) + max_precision_length = 2; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const CHAR_T *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + dp->precision_arg_index = n - 1; + cp = np + 1; + } + } + if (dp->precision_arg_index < 0) + dp->precision_arg_index = arg_posn++; + REGISTER_ARG (dp->precision_arg_index, TYPE_INT); + } + else + { + unsigned int precision_length; + + dp->precision_start = cp - 1; + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + dp->precision_end = cp; + precision_length = dp->precision_end - dp->precision_start; + if (max_precision_length < precision_length) + max_precision_length = precision_length; + } + } + + { + arg_type type; + + /* Parse argument type/size specifiers. */ + { + int flags = 0; + + for (;;) + { + if (*cp == 'h') + { + flags |= (1 << (flags & 1)); + cp++; + } + else if (*cp == 'L') + { + flags |= 4; + cp++; + } + else if (*cp == 'l') + { + flags += 8; + cp++; + } +#ifdef HAVE_INTMAX_T + else if (*cp == 'j') + { + if (sizeof (intmax_t) > sizeof (long)) + { + /* intmax_t = long long */ + flags += 16; + } + else if (sizeof (intmax_t) > sizeof (int)) + { + /* intmax_t = long */ + flags += 8; + } + cp++; + } +#endif + else if (*cp == 'z' || *cp == 'Z') + { + /* 'z' is standardized in ISO C 99, but glibc uses 'Z' + because the warning facility in gcc-2.95.2 understands + only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ + if (sizeof (size_t) > sizeof (long)) + { + /* size_t = long long */ + flags += 16; + } + else if (sizeof (size_t) > sizeof (int)) + { + /* size_t = long */ + flags += 8; + } + cp++; + } + else if (*cp == 't') + { + if (sizeof (ptrdiff_t) > sizeof (long)) + { + /* ptrdiff_t = long long */ + flags += 16; + } + else if (sizeof (ptrdiff_t) > sizeof (int)) + { + /* ptrdiff_t = long */ + flags += 8; + } + cp++; + } + else + break; + } + + /* Read the conversion character. */ + c = *cp++; + switch (c) + { + case 'd': case 'i': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_LONGLONGINT; + else +#endif + if (flags >= 8) + type = TYPE_LONGINT; + else if (flags & 2) + type = TYPE_SCHAR; + else if (flags & 1) + type = TYPE_SHORT; + else + type = TYPE_INT; + break; + case 'o': case 'u': case 'x': case 'X': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_ULONGLONGINT; + else +#endif + if (flags >= 8) + type = TYPE_ULONGINT; + else if (flags & 2) + type = TYPE_UCHAR; + else if (flags & 1) + type = TYPE_USHORT; + else + type = TYPE_UINT; + break; + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': +#ifdef HAVE_LONG_DOUBLE + if (flags >= 16 || (flags & 4)) + type = TYPE_LONGDOUBLE; + else +#endif + type = TYPE_DOUBLE; + break; + case 'c': + if (flags >= 8) +#ifdef HAVE_WINT_T + type = TYPE_WIDE_CHAR; +#else + goto error; +#endif + else + type = TYPE_CHAR; + break; +#ifdef HAVE_WINT_T + case 'C': + type = TYPE_WIDE_CHAR; + c = 'c'; + break; +#endif + case 's': + if (flags >= 8) +#ifdef HAVE_WCHAR_T + type = TYPE_WIDE_STRING; +#else + goto error; +#endif + else + type = TYPE_STRING; + break; +#ifdef HAVE_WCHAR_T + case 'S': + type = TYPE_WIDE_STRING; + c = 's'; + break; +#endif + case 'p': + type = TYPE_POINTER; + break; + case 'n': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_COUNT_LONGLONGINT_POINTER; + else +#endif + if (flags >= 8) + type = TYPE_COUNT_LONGINT_POINTER; + else if (flags & 2) + type = TYPE_COUNT_SCHAR_POINTER; + else if (flags & 1) + type = TYPE_COUNT_SHORT_POINTER; + else + type = TYPE_COUNT_INT_POINTER; + break; + case '%': + type = TYPE_NONE; + break; + default: + /* Unknown conversion character. */ + goto error; + } + } + + if (type != TYPE_NONE) + { + dp->arg_index = arg_index; + if (dp->arg_index < 0) + dp->arg_index = arg_posn++; + REGISTER_ARG (dp->arg_index, type); + } + dp->conversion = c; + dp->dir_end = cp; + } + + d->count++; + if (d->count >= d_allocated) + { + DIRECTIVE *memory; + + d_allocated = 2 * d_allocated; + memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE)); + if (memory == NULL) + /* Out of memory. */ + goto error; + d->dir = memory; + } + } + } + d->dir[d->count].dir_start = cp; + + d->max_width_length = max_width_length; + d->max_precision_length = max_precision_length; + return 0; + +error: + if (a->arg) + free (a->arg); + if (d->dir) + free (d->dir); + return -1; +} + +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef PRINTF_PARSE diff --git a/gettext-runtime/intl/printf-parse.h b/gettext-runtime/intl/printf-parse.h new file mode 100644 index 000000000..97e432af1 --- /dev/null +++ b/gettext-runtime/intl/printf-parse.h @@ -0,0 +1,72 @@ +/* Parse printf format string. + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _PRINTF_PARSE_H +#define _PRINTF_PARSE_H + +#include "printf-args.h" + + +/* Flags */ +#define FLAG_GROUP 1 /* ' flag */ +#define FLAG_LEFT 2 /* - flag */ +#define FLAG_SHOWSIGN 4 /* + flag */ +#define FLAG_SPACE 8 /* space flag */ +#define FLAG_ALT 16 /* # flag */ +#define FLAG_ZERO 32 + +/* A parsed directive. */ +typedef struct +{ + const char* dir_start; + const char* dir_end; + int flags; + const char* width_start; + const char* width_end; + int width_arg_index; + const char* precision_start; + const char* precision_end; + int precision_arg_index; + char conversion; /* d i o u x X f e E g G c s p n U % but not C S */ + int arg_index; +} +char_directive; + +/* A parsed format string. */ +typedef struct +{ + unsigned int count; + char_directive *dir; + unsigned int max_width_length; + unsigned int max_precision_length; +} +char_directives; + + +/* Parses the format string. Fills in the number N of directives, and fills + in directives[0], ..., directives[N-1], and sets directives[N].dir_start + to the end of the format string. Also fills in the arg_type fields of the + arguments and the needed count of arguments. */ +#ifdef STATIC +STATIC +#else +extern +#endif +int printf_parse (const char *format, char_directives *d, arguments *a); + +#endif /* _PRINTF_PARSE_H */ diff --git a/gettext-runtime/intl/printf.c b/gettext-runtime/intl/printf.c new file mode 100644 index 000000000..c96ad2f1d --- /dev/null +++ b/gettext-runtime/intl/printf.c @@ -0,0 +1,308 @@ +/* Formatted output to strings, using POSIX/XSI format strings with positions. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if !HAVE_POSIX_PRINTF + +#include +#include + +#define STATIC static + +/* Define auxiliary functions declared in "printf-args.h". */ +#include "printf-args.c" + +/* Define auxiliary functions declared in "printf-parse.h". */ +#include "printf-parse.c" + +/* Define functions declared in "vasnprintf.h". */ +#define vasnprintf libintl_vasnprintf +#include "vasnprintf.c" +#if 0 /* not needed */ +#define asnprintf libintl_asnprintf +#include "asnprintf.c" +#endif + +int +libintl_vfprintf (FILE *stream, const char *format, va_list args) +{ + if (strchr (format, '$') == NULL) + return vfprintf (stream, format, args); + else + { + size_t length; + char *result = libintl_vasnprintf (NULL, &length, format, args); + int retval = -1; + if (result != NULL) + { + if (fwrite (result, 1, length, stream) == length) + retval = length; + free (result); + } + return retval; + } +} + +int +libintl_fprintf (FILE *stream, const char *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vfprintf (stream, format, args); + va_end (args); + return retval; +} + +int +libintl_vprintf (const char *format, va_list args) +{ + return libintl_vfprintf (stdout, format, args); +} + +int +libintl_printf (const char *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vprintf (format, args); + va_end (args); + return retval; +} + +int +libintl_vsprintf (char *resultbuf, const char *format, va_list args) +{ + if (strchr (format, '$') == NULL) + return vsprintf (resultbuf, format, args); + else + { + size_t length = (size_t) ~0 / (4 * sizeof (char)); + char *result = libintl_vasnprintf (resultbuf, &length, format, args); + if (result != resultbuf) + { + free (result); + return -1; + } + else + return length; + } +} + +int +libintl_sprintf (char *resultbuf, const char *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vsprintf (resultbuf, format, args); + va_end (args); + return retval; +} + +#if HAVE_SNPRINTF + +int +libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args) +{ + if (strchr (format, '$') == NULL) + return vsnprintf (resultbuf, length, format, args); + else + { + size_t maxlength = length; + char *result = libintl_vasnprintf (resultbuf, &length, format, args); + if (result != resultbuf) + { + if (maxlength > 0) + { + if (length < maxlength) + abort (); + memcpy (resultbuf, result, maxlength - 1); + resultbuf[maxlength - 1] = '\0'; + } + free (result); + return -1; + } + else + return length; + } +} + +int +libintl_snprintf (char *resultbuf, size_t length, const char *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vsnprintf (resultbuf, length, format, args); + va_end (args); + return retval; +} + +#endif + +#if HAVE_ASPRINTF + +int +libintl_vasprintf (char **resultp, const char *format, va_list args) +{ + size_t length; + char *result = libintl_vasnprintf (NULL, &length, format, args); + if (result == NULL) + return -1; + *resultp = result; + return length; +} + +int +libintl_asprintf (char **resultp, const char *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vasprintf (resultp, format, args); + va_end (args); + return retval; +} + +#endif + +#if HAVE_WPRINTF + +#include + +#define WIDE_CHAR_VERSION 1 + +/* Define auxiliary functions declared in "wprintf-parse.h". */ +#include "printf-parse.c" + +/* Define functions declared in "vasnprintf.h". */ +#define vasnwprintf libintl_vasnwprintf +#include "vasnprintf.c" +#if 0 /* not needed */ +#define asnwprintf libintl_asnwprintf +#include "asnprintf.c" +#endif + +int +libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args) +{ + if (wcschr (format, '$') == NULL) + return vfwprintf (stream, format, args); + else + { + size_t length; + wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args); + int retval = -1; + if (result != NULL) + { + size_t i; + for (i = 0; i < length; i++) + if (fputwc (result[i], stream) == WEOF) + break; + if (i == length) + retval = length; + free (result); + } + return retval; + } +} + +int +libintl_fwprintf (FILE *stream, const wchar_t *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vfwprintf (stream, format, args); + va_end (args); + return retval; +} + +int +libintl_vwprintf (const wchar_t *format, va_list args) +{ + return libintl_vfwprintf (stdout, format, args); +} + +int +libintl_wprintf (const wchar_t *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vwprintf (format, args); + va_end (args); + return retval; +} + +int +libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args) +{ + if (wcschr (format, '$') == NULL) + return vswprintf (resultbuf, length, format, args); + else + { + size_t maxlength = length; + wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args); + if (result != resultbuf) + { + if (maxlength > 0) + { + if (length < maxlength) + abort (); + memcpy (resultbuf, result, (maxlength - 1) * sizeof (wchar_t)); + resultbuf[maxlength - 1] = 0; + } + free (result); + return -1; + } + else + return length; + } +} + +int +libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = libintl_vswprintf (resultbuf, length, format, args); + va_end (args); + return retval; +} + +#endif + +#endif diff --git a/gettext-runtime/intl/vasnprintf.c b/gettext-runtime/intl/vasnprintf.c new file mode 100644 index 000000000..b8bd3ce85 --- /dev/null +++ b/gettext-runtime/intl/vasnprintf.c @@ -0,0 +1,807 @@ +/* vsprintf with automatic memory allocation. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Tell glibc's to provide a prototype for snprintf(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif +#include + +/* Specification. */ +#if WIDE_CHAR_VERSION +# include "vasnwprintf.h" +#else +# include "vasnprintf.h" +#endif + +#include /* snprintf(), sprintf() */ +#include /* abort(), malloc(), realloc(), free() */ +#include /* memcpy(), strlen() */ +#include /* errno */ +#include /* CHAR_BIT */ +#include /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +#else +# include "printf-parse.h" +#endif + +/* For those losing systems which don't have 'alloca' we have to add + some additional code emulating it. */ +#ifdef HAVE_ALLOCA +# define freea(p) /* nothing */ +#else +# define alloca(n) malloc (n) +# define freea(p) free (p) +#endif + +#if WIDE_CHAR_VERSION +# define VASNPRINTF vasnwprintf +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +# define PRINTF_PARSE wprintf_parse +# define USE_SNPRINTF 1 +# define SNPRINTF swprintf +#else +# define VASNPRINTF vasnprintf +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +# define PRINTF_PARSE printf_parse +# define USE_SNPRINTF HAVE_SNPRINTF +# define SNPRINTF snprintf +#endif + +CHAR_T * +VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) +{ + DIRECTIVES d; + arguments a; + + if (PRINTF_PARSE (format, &d, &a) < 0) + { + errno = EINVAL; + return NULL; + } + +#define CLEANUP() \ + free (d.dir); \ + if (a.arg) \ + free (a.arg); + + if (printf_fetchargs (args, &a) < 0) + { + CLEANUP (); + errno = EINVAL; + return NULL; + } + + { + CHAR_T *buf = + (CHAR_T *) alloca ((7 + d.max_width_length + d.max_precision_length + 6) + * sizeof (CHAR_T)); + const CHAR_T *cp; + unsigned int i; + DIRECTIVE *dp; + /* Output string accumulator. */ + CHAR_T *result; + size_t allocated; + size_t length; + + if (resultbuf != NULL) + { + result = resultbuf; + allocated = *lengthp; + } + else + { + result = NULL; + allocated = 0; + } + length = 0; + /* Invariants: + result is either == resultbuf or == NULL or malloc-allocated. + If length > 0, then result != NULL. */ + +#define ENSURE_ALLOCATION(needed) \ + if ((needed) > allocated) \ + { \ + CHAR_T *memory; \ + \ + allocated = (allocated > 0 ? 2 * allocated : 12); \ + if ((needed) > allocated) \ + allocated = (needed); \ + if (result == resultbuf || result == NULL) \ + memory = (CHAR_T *) malloc (allocated * sizeof (CHAR_T)); \ + else \ + memory = (CHAR_T *) realloc (result, allocated * sizeof (CHAR_T)); \ + \ + if (memory == NULL) \ + { \ + if (!(result == resultbuf || result == NULL)) \ + free (result); \ + freea (buf); \ + CLEANUP (); \ + errno = ENOMEM; \ + return NULL; \ + } \ + if (result == resultbuf && length > 0) \ + memcpy (memory, result, length * sizeof (CHAR_T)); \ + result = memory; \ + } + + for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) + { + if (cp != dp->dir_start) + { + size_t n = dp->dir_start - cp; + + ENSURE_ALLOCATION (length + n); + memcpy (result + length, cp, n * sizeof (CHAR_T)); + length += n; + } + if (i == d.count) + break; + + /* Execute a single directive. */ + if (dp->conversion == '%') + { + if (!(dp->arg_index < 0)) + abort (); + ENSURE_ALLOCATION (length + 1); + result[length] = '%'; + length += 1; + } + else + { + if (!(dp->arg_index >= 0)) + abort (); + + if (dp->conversion == 'n') + { + switch (a.arg[dp->arg_index].type) + { + case TYPE_COUNT_SCHAR_POINTER: + *a.arg[dp->arg_index].a.a_count_schar_pointer = length; + break; + case TYPE_COUNT_SHORT_POINTER: + *a.arg[dp->arg_index].a.a_count_short_pointer = length; + break; + case TYPE_COUNT_INT_POINTER: + *a.arg[dp->arg_index].a.a_count_int_pointer = length; + break; + case TYPE_COUNT_LONGINT_POINTER: + *a.arg[dp->arg_index].a.a_count_longint_pointer = length; + break; +#ifdef HAVE_LONG_LONG + case TYPE_COUNT_LONGLONGINT_POINTER: + *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; + break; +#endif + default: + abort (); + } + } + else + { + arg_type type = a.arg[dp->arg_index].type; + CHAR_T *p; + unsigned int prefix_count; + int prefixes[2]; +#if !USE_SNPRINTF + unsigned int tmp_length; + CHAR_T tmpbuf[700]; + CHAR_T *tmp; + + /* Allocate a temporary buffer of sufficient size for calling + sprintf. */ + { + unsigned int width; + unsigned int precision; + + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = (arg < 0 ? -arg : arg); + } + else + { + const CHAR_T *digitp = dp->width_start; + + do + width = width * 10 + (*digitp++ - '0'); + while (digitp != dp->width_end); + } + } + + precision = 6; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + precision = (arg < 0 ? 0 : arg); + } + else + { + const CHAR_T *digitp = dp->precision_start + 1; + + precision = 0; + do + precision = precision * 10 + (*digitp++ - '0'); + while (digitp != dp->precision_end); + } + } + + switch (dp->conversion) + { + + case 'd': case 'i': case 'u': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + 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 */ + 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 */ + 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 */ + break; + + case 'o': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long long) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else +# endif + if (type == TYPE_LONGINT || type == TYPE_ULONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + break; + + case 'x': case 'X': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + tmp_length = + (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 */ + else +# endif + if (type == TYPE_LONGINT || type == TYPE_ULONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading sign or alternate form */ + 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 */ + break; + + case 'f': case 'F': +# ifdef HAVE_LONG_DOUBLE + if (type == TYPE_LONGDOUBLE) + tmp_length = + (unsigned int) (LDBL_MAX_EXP + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + precision + + 10; /* sign, decimal point etc. */ + else +# endif + tmp_length = + (unsigned int) (DBL_MAX_EXP + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + precision + + 10; /* sign, decimal point etc. */ + break; + + case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': + tmp_length = + precision + + 12; /* sign, decimal point, exponent etc. */ + break; + + case 'c': +# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION + if (type == TYPE_WIDE_CHAR) + tmp_length = MB_CUR_MAX; + else +# endif + tmp_length = 1; + break; + + case 's': +# ifdef HAVE_WCHAR_T + if (type == TYPE_WIDE_STRING) +# if WIDE_CHAR_VERSION + tmp_length = + wcslen (a.arg[dp->arg_index].a.a_wide_string); +# else + tmp_length = + wcslen (a.arg[dp->arg_index].a.a_wide_string) + * MB_CUR_MAX; +# endif + else +# endif + tmp_length = strlen (a.arg[dp->arg_index].a.a_string); + break; + + case 'p': + tmp_length = + (unsigned int) (sizeof (void *) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading 0x */ + break; + + default: + abort (); + } + + if (tmp_length < width) + tmp_length = width; + + tmp_length++; /* account for trailing NUL */ + } + + if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) + tmp = tmpbuf; + else + { + tmp = (CHAR_T *) malloc (tmp_length * sizeof (CHAR_T)); + if (tmp == NULL) + { + /* Out of memory. */ + if (!(result == resultbuf || result == NULL)) + free (result); + freea (buf); + CLEANUP (); + errno = ENOMEM; + return NULL; + } + } +#endif + + /* Construct the format string for calling snprintf or + sprintf. */ + p = buf; + *p++ = '%'; + if (dp->flags & FLAG_GROUP) + *p++ = '\''; + if (dp->flags & FLAG_LEFT) + *p++ = '-'; + if (dp->flags & FLAG_SHOWSIGN) + *p++ = '+'; + if (dp->flags & FLAG_SPACE) + *p++ = ' '; + if (dp->flags & FLAG_ALT) + *p++ = '#'; + if (dp->flags & FLAG_ZERO) + *p++ = '0'; + if (dp->width_start != dp->width_end) + { + size_t n = dp->width_end - dp->width_start; + memcpy (p, dp->width_start, n * sizeof (CHAR_T)); + p += n; + } + if (dp->precision_start != dp->precision_end) + { + size_t n = dp->precision_end - dp->precision_start; + memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); + p += n; + } + + switch (type) + { +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + case TYPE_ULONGLONGINT: + *p++ = 'l'; + /*FALLTHROUGH*/ +#endif + case TYPE_LONGINT: + case TYPE_ULONGINT: +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: +#endif +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: +#endif + *p++ = 'l'; + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + *p++ = 'L'; + break; +#endif + default: + break; + } + *p = dp->conversion; +#if USE_SNPRINTF + p[1] = '%'; + p[2] = 'n'; + p[3] = '\0'; +#else + p[1] = '\0'; +#endif + + /* Construct the arguments for calling snprintf or sprintf. */ + prefix_count = 0; + if (dp->width_arg_index >= 0) + { + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; + } + if (dp->precision_arg_index >= 0) + { + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; + } + +#if USE_SNPRINTF + /* Prepare checking whether snprintf returns the count + via %n. */ + ENSURE_ALLOCATION (length + 1); + result[length] = '\0'; +#endif + + for (;;) + { + size_t maxlen; + int count; + int retcount; + + maxlen = allocated - length; + count = -1; + retcount = 0; + +#if USE_SNPRINTF +#define SNPRINTF_BUF(arg) \ + switch (prefix_count) \ + { \ + case 0: \ + retcount = SNPRINTF (result + length, maxlen, buf, \ + arg, &count); \ + break; \ + case 1: \ + retcount = SNPRINTF (result + length, maxlen, buf, \ + prefixes[0], arg, &count); \ + break; \ + case 2: \ + retcount = SNPRINTF (result + length, maxlen, buf, \ + prefixes[0], prefixes[1], arg, \ + &count); \ + break; \ + default: \ + abort (); \ + } +#else +#define SNPRINTF_BUF(arg) \ + switch (prefix_count) \ + { \ + case 0: \ + count = sprintf (tmp, buf, arg); \ + break; \ + case 1: \ + count = sprintf (tmp, buf, prefixes[0], arg); \ + break; \ + case 2: \ + count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ + arg); \ + break; \ + default: \ + abort (); \ + } +#endif + + switch (type) + { + case TYPE_SCHAR: + { + int arg = a.arg[dp->arg_index].a.a_schar; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UCHAR: + { + unsigned int arg = a.arg[dp->arg_index].a.a_uchar; + SNPRINTF_BUF (arg); + } + break; + case TYPE_SHORT: + { + int arg = a.arg[dp->arg_index].a.a_short; + SNPRINTF_BUF (arg); + } + break; + case TYPE_USHORT: + { + unsigned int arg = a.arg[dp->arg_index].a.a_ushort; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT: + { + int arg = a.arg[dp->arg_index].a.a_int; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT: + { + unsigned int arg = a.arg[dp->arg_index].a.a_uint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_LONGINT: + { + long int arg = a.arg[dp->arg_index].a.a_longint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_ULONGINT: + { + unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + { + long long int arg = a.arg[dp->arg_index].a.a_longlongint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_ULONGLONGINT: + { + unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_DOUBLE: + { + double arg = a.arg[dp->arg_index].a.a_double; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + { + long double arg = a.arg[dp->arg_index].a.a_longdouble; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_CHAR: + { + int arg = a.arg[dp->arg_index].a.a_char; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: + { + wint_t arg = a.arg[dp->arg_index].a.a_wide_char; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_STRING: + { + const char *arg = a.arg[dp->arg_index].a.a_string; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: + { + const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_POINTER: + { + void *arg = a.arg[dp->arg_index].a.a_pointer; + SNPRINTF_BUF (arg); + } + break; + default: + abort (); + } + +#if USE_SNPRINTF + /* Portability: Not all implementations of snprintf() + are ISO C 99 compliant. Determine the number of + bytes that snprintf() has produced or would have + produced. */ + if (count >= 0) + { + /* Verify that snprintf() has NUL-terminated its + result. */ + if (count < maxlen && result[length + count] != '\0') + abort (); + /* Portability hack. */ + if (retcount > count) + count = retcount; + } + else + { + /* snprintf() doesn't understand the '%n' + directive. */ + if (p[1] != '\0') + { + /* Don't use the '%n' directive; instead, look + at the snprintf() return value. */ + p[1] = '\0'; + continue; + } + count = retcount; + } +#endif + + /* Attempt to handle failure. */ + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + freea (buf); + CLEANUP (); + errno = EINVAL; + return NULL; + } + +#if !USE_SNPRINTF + if (count >= tmp_length) + /* tmp_length was incorrectly calculated - fix the + code above! */ + abort (); +#endif + + /* Make room for the result. */ + if (count >= maxlen) + { + /* Need at least count bytes. But allocate + proportionally, to avoid looping eternally if + snprintf() reports a too small count. */ + size_t n = length + count; + + if (n < 2 * allocated) + n = 2 * allocated; + + ENSURE_ALLOCATION (n); +#if USE_SNPRINTF + continue; +#endif + } + +#if USE_SNPRINTF + /* The snprintf() result did fit. */ +#else + /* Append the sprintf() result. */ + memcpy (result + length, tmp, count * sizeof (CHAR_T)); + if (tmp != tmpbuf) + free (tmp); +#endif + + length += count; + break; + } + } + } + } + + /* Add the final NUL. */ + ENSURE_ALLOCATION (length + 1); + result[length] = '\0'; + + if (result != resultbuf && length + 1 < allocated) + { + /* Shrink the allocated memory if possible. */ + CHAR_T *memory; + + memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); + if (memory != NULL) + result = memory; + } + + freea (buf); + CLEANUP (); + *lengthp = length; + return result; + } +} + +#undef SNPRINTF +#undef USE_SNPRINTF +#undef PRINTF_PARSE +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef VASNPRINTF diff --git a/gettext-runtime/intl/vasnprintf.h b/gettext-runtime/intl/vasnprintf.h new file mode 100644 index 000000000..65f1bc13d --- /dev/null +++ b/gettext-runtime/intl/vasnprintf.h @@ -0,0 +1,61 @@ +/* vsprintf with automatic memory allocation. + Copyright (C) 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _VASNPRINTF_H +#define _VASNPRINTF_H + +/* Get va_list. */ +#include + +/* Get size_t. */ +#include + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Write formatted output to a string dynamically allocated with malloc(). + You can pass a preallocated buffer for the result in RESULTBUF and its + size in *LENGTHP; otherwise you pass RESULTBUF = NULL. + 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. */ +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) + __attribute__ ((__format__ (__printf__, 3, 0))); + +#ifdef __cplusplus +} +#endif + +#endif /* _VASNPRINTF_H */ diff --git a/gettext-runtime/intl/vasnwprintf.h b/gettext-runtime/intl/vasnwprintf.h new file mode 100644 index 000000000..d3cef4cbc --- /dev/null +++ b/gettext-runtime/intl/vasnwprintf.h @@ -0,0 +1,46 @@ +/* vswprintf with automatic memory allocation. + Copyright (C) 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _VASNWPRINTF_H +#define _VASNWPRINTF_H + +/* Get va_list. */ +#include + +/* Get wchar_t, size_t. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Write formatted output to a string dynamically allocated with malloc(). + You can pass a preallocated buffer for the result in RESULTBUF and its + size in *LENGTHP; otherwise you pass RESULTBUF = NULL. + 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. */ +extern wchar_t * asnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, ...); +extern wchar_t * vasnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* _VASNWPRINTF_H */ diff --git a/gettext-runtime/intl/wprintf-parse.h b/gettext-runtime/intl/wprintf-parse.h new file mode 100644 index 000000000..83ebbf062 --- /dev/null +++ b/gettext-runtime/intl/wprintf-parse.h @@ -0,0 +1,72 @@ +/* Parse printf format string. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _WPRINTF_PARSE_H +#define _WPRINTF_PARSE_H + +#include "printf-args.h" + + +/* Flags */ +#define FLAG_GROUP 1 /* ' flag */ +#define FLAG_LEFT 2 /* - flag */ +#define FLAG_SHOWSIGN 4 /* + flag */ +#define FLAG_SPACE 8 /* space flag */ +#define FLAG_ALT 16 /* # flag */ +#define FLAG_ZERO 32 + +/* A parsed directive. */ +typedef struct +{ + const wchar_t* dir_start; + const wchar_t* dir_end; + int flags; + const wchar_t* width_start; + const wchar_t* width_end; + int width_arg_index; + const wchar_t* precision_start; + const wchar_t* precision_end; + int precision_arg_index; + wchar_t conversion; /* d i o u x X f e E g G c s p n U % but not C S */ + int arg_index; +} +wchar_t_directive; + +/* A parsed format string. */ +typedef struct +{ + unsigned int count; + wchar_t_directive *dir; + unsigned int max_width_length; + unsigned int max_precision_length; +} +wchar_t_directives; + + +/* Parses the format string. Fills in the number N of directives, and fills + in directives[0], ..., directives[N-1], and sets directives[N].dir_start + to the end of the format string. Also fills in the arg_type fields of the + arguments and the needed count of arguments. */ +#ifdef STATIC +STATIC +#else +extern +#endif +int wprintf_parse (const wchar_t *format, wchar_t_directives *d, arguments *a); + +#endif /* _WPRINTF_PARSE_H */ diff --git a/gettext-runtime/libasprintf/ChangeLog b/gettext-runtime/libasprintf/ChangeLog index 338776e38..a3f00c80b 100644 --- a/gettext-runtime/libasprintf/ChangeLog +++ b/gettext-runtime/libasprintf/ChangeLog @@ -1,3 +1,12 @@ +2003-06-19 Bruno Haible + + * configure.ac (jm_AC_TYPE_LONG_LONG): Replaces gt_TYPE_LONGLONG. + * printf-args.c: Generalize to it can be compiled for wide strings. + (PRINTF_PARSE, CHAR_T, DIRECTIVE, DIRECTIVES): New macros. + * vasnprintf.c: Generalize to it can be compiled for wide strings. + (VASNPRINTF, CHAR_T, DIRECTIVE, DIRECTIVES, PRINTF_PARSE, USE_SNPRINTF, + SNPRINTF): New macros. + 2003-05-30 Bruno Haible * autosprintf.texi: Tweak @dircategory and @direntry. diff --git a/gettext-runtime/libasprintf/configure.ac b/gettext-runtime/libasprintf/configure.ac index b3f427678..9d1ed6cac 100644 --- a/gettext-runtime/libasprintf/configure.ac +++ b/gettext-runtime/libasprintf/configure.ac @@ -48,7 +48,7 @@ dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST bh_C_SIGNED AC_TYPE_SIZE_T -gt_TYPE_LONGLONG +jm_AC_TYPE_LONG_LONG gt_TYPE_LONGDOUBLE gt_TYPE_WCHAR_T gt_TYPE_WINT_T diff --git a/gettext-runtime/libasprintf/printf-parse.c b/gettext-runtime/libasprintf/printf-parse.c index bdfe88fe8..ff61c174c 100644 --- a/gettext-runtime/libasprintf/printf-parse.c +++ b/gettext-runtime/libasprintf/printf-parse.c @@ -21,7 +21,11 @@ #endif /* Specification. */ -#include "printf-parse.h" +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +#else +# include "printf-parse.h" +#endif /* Get size_t, NULL. */ #include @@ -37,13 +41,25 @@ /* malloc(), realloc(), free(). */ #include +#if WIDE_CHAR_VERSION +# define PRINTF_PARSE wprintf_parse +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +#else +# define PRINTF_PARSE printf_parse +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +#endif + #ifdef STATIC STATIC #endif int -printf_parse (const char *format, char_directives *d, arguments *a) +PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) { - const char *cp = format; /* pointer into format */ + const CHAR_T *cp = format; /* pointer into format */ int arg_posn = 0; /* number of regular arguments consumed */ unsigned int d_allocated; /* allocated elements of d->dir */ unsigned int a_allocated; /* allocated elements of a->arg */ @@ -52,7 +68,7 @@ printf_parse (const char *format, char_directives *d, arguments *a) d->count = 0; d_allocated = 1; - d->dir = malloc (d_allocated * sizeof (char_directive)); + d->dir = malloc (d_allocated * sizeof (DIRECTIVE)); if (d->dir == NULL) /* Out of memory. */ return -1; @@ -89,11 +105,11 @@ printf_parse (const char *format, char_directives *d, arguments *a) while (*cp != '\0') { - char c = *cp++; + CHAR_T c = *cp++; if (c == '%') { int arg_index = -1; - char_directive *dp = &d->dir[d->count];/* pointer to next directive */ + DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ /* Initialize the next directive. */ dp->dir_start = cp - 1; @@ -109,7 +125,7 @@ printf_parse (const char *format, char_directives *d, arguments *a) /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; @@ -176,7 +192,7 @@ printf_parse (const char *format, char_directives *d, arguments *a) /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; @@ -225,7 +241,7 @@ printf_parse (const char *format, char_directives *d, arguments *a) /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; @@ -451,10 +467,10 @@ printf_parse (const char *format, char_directives *d, arguments *a) d->count++; if (d->count >= d_allocated) { - char_directive *memory; + DIRECTIVE *memory; d_allocated = 2 * d_allocated; - memory = realloc (d->dir, d_allocated * sizeof (char_directive)); + memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE)); if (memory == NULL) /* Out of memory. */ goto error; @@ -475,3 +491,8 @@ error: free (d->dir); return -1; } + +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef PRINTF_PARSE diff --git a/gettext-runtime/libasprintf/vasnprintf.c b/gettext-runtime/libasprintf/vasnprintf.c index 7aac42bcd..b8bd3ce85 100644 --- a/gettext-runtime/libasprintf/vasnprintf.c +++ b/gettext-runtime/libasprintf/vasnprintf.c @@ -29,7 +29,11 @@ #include /* Specification. */ -#include "vasnprintf.h" +#if WIDE_CHAR_VERSION +# include "vasnwprintf.h" +#else +# include "vasnprintf.h" +#endif #include /* snprintf(), sprintf() */ #include /* abort(), malloc(), realloc(), free() */ @@ -37,24 +41,46 @@ #include /* errno */ #include /* CHAR_BIT */ #include /* DBL_MAX_EXP, LDBL_MAX_EXP */ -#include "printf-parse.h" +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +#else +# include "printf-parse.h" +#endif /* For those losing systems which don't have 'alloca' we have to add - some additional code emulating it. */ -#ifdef HAVE_ALLOCA + some additional code emulating it. */ +#ifdef HAVE_ALLOCA # define freea(p) /* nothing */ #else -# define alloca(n) malloc (n) -# define freea(p) free (p) +# define alloca(n) malloc (n) +# define freea(p) free (p) #endif -char * -vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) +#if WIDE_CHAR_VERSION +# define VASNPRINTF vasnwprintf +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +# define PRINTF_PARSE wprintf_parse +# define USE_SNPRINTF 1 +# define SNPRINTF swprintf +#else +# define VASNPRINTF vasnprintf +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +# define PRINTF_PARSE printf_parse +# define USE_SNPRINTF HAVE_SNPRINTF +# define SNPRINTF snprintf +#endif + +CHAR_T * +VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) { - char_directives d; + DIRECTIVES d; arguments a; - if (printf_parse (format, &d, &a) < 0) + if (PRINTF_PARSE (format, &d, &a) < 0) { errno = EINVAL; return NULL; @@ -73,13 +99,14 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } { - char *buf = - (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6); - const char *cp; + CHAR_T *buf = + (CHAR_T *) alloca ((7 + d.max_width_length + d.max_precision_length + 6) + * sizeof (CHAR_T)); + const CHAR_T *cp; unsigned int i; - char_directive *dp; + DIRECTIVE *dp; /* Output string accumulator. */ - char *result; + CHAR_T *result; size_t allocated; size_t length; @@ -99,30 +126,30 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) If length > 0, then result != NULL. */ #define ENSURE_ALLOCATION(needed) \ - if ((needed) > allocated) \ - { \ - char *memory; \ - \ - allocated = (allocated > 0 ? 2 * allocated : 12); \ - if ((needed) > allocated) \ - allocated = (needed); \ - if (result == resultbuf || result == NULL) \ - memory = (char *) malloc (allocated); \ - else \ - memory = (char *) realloc (result, allocated); \ - \ - if (memory == NULL) \ - { \ - if (!(result == resultbuf || result == NULL)) \ - free (result); \ - freea (buf); \ - CLEANUP (); \ - errno = ENOMEM; \ - return NULL; \ - } \ - if (result == resultbuf && length > 0) \ - memcpy (memory, result, length); \ - result = memory; \ + if ((needed) > allocated) \ + { \ + CHAR_T *memory; \ + \ + allocated = (allocated > 0 ? 2 * allocated : 12); \ + if ((needed) > allocated) \ + allocated = (needed); \ + if (result == resultbuf || result == NULL) \ + memory = (CHAR_T *) malloc (allocated * sizeof (CHAR_T)); \ + else \ + memory = (CHAR_T *) realloc (result, allocated * sizeof (CHAR_T)); \ + \ + if (memory == NULL) \ + { \ + if (!(result == resultbuf || result == NULL)) \ + free (result); \ + freea (buf); \ + CLEANUP (); \ + errno = ENOMEM; \ + return NULL; \ + } \ + if (result == resultbuf && length > 0) \ + memcpy (memory, result, length * sizeof (CHAR_T)); \ + result = memory; \ } for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) @@ -132,7 +159,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) size_t n = dp->dir_start - cp; ENSURE_ALLOCATION (length + n); - memcpy (result + length, cp, n); + memcpy (result + length, cp, n * sizeof (CHAR_T)); length += n; } if (i == d.count) @@ -180,13 +207,13 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) else { arg_type type = a.arg[dp->arg_index].type; - char *p; + CHAR_T *p; unsigned int prefix_count; int prefixes[2]; -#if !HAVE_SNPRINTF +#if !USE_SNPRINTF unsigned int tmp_length; - char tmpbuf[700]; - char *tmp; + CHAR_T tmpbuf[700]; + CHAR_T *tmp; /* Allocate a temporary buffer of sufficient size for calling sprintf. */ @@ -208,7 +235,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } else { - const char *digitp = dp->width_start; + const CHAR_T *digitp = dp->width_start; do width = width * 10 + (*digitp++ - '0'); @@ -230,7 +257,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } else { - const char *digitp = dp->precision_start + 1; + const CHAR_T *digitp = dp->precision_start + 1; precision = 0; do @@ -357,7 +384,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) break; case 'c': -# ifdef HAVE_WINT_T +# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION if (type == TYPE_WIDE_CHAR) tmp_length = MB_CUR_MAX; else @@ -368,9 +395,14 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) case 's': # ifdef HAVE_WCHAR_T if (type == TYPE_WIDE_STRING) +# if WIDE_CHAR_VERSION + tmp_length = + wcslen (a.arg[dp->arg_index].a.a_wide_string); +# else tmp_length = wcslen (a.arg[dp->arg_index].a.a_wide_string) * MB_CUR_MAX; +# endif else # endif tmp_length = strlen (a.arg[dp->arg_index].a.a_string); @@ -395,11 +427,11 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) tmp_length++; /* account for trailing NUL */ } - if (tmp_length <= sizeof (tmpbuf)) + if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) tmp = tmpbuf; else { - tmp = (char *) malloc (tmp_length); + tmp = (CHAR_T *) malloc (tmp_length * sizeof (CHAR_T)); if (tmp == NULL) { /* Out of memory. */ @@ -432,13 +464,13 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) if (dp->width_start != dp->width_end) { size_t n = dp->width_end - dp->width_start; - memcpy (p, dp->width_start, n); + memcpy (p, dp->width_start, n * sizeof (CHAR_T)); p += n; } if (dp->precision_start != dp->precision_end) { size_t n = dp->precision_end - dp->precision_start; - memcpy (p, dp->precision_start, n); + memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); p += n; } @@ -469,7 +501,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) break; } *p = dp->conversion; -#if HAVE_SNPRINTF +#if USE_SNPRINTF p[1] = '%'; p[2] = 'n'; p[3] = '\0'; @@ -492,7 +524,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* Prepare checking whether snprintf returns the count via %n. */ ENSURE_ALLOCATION (length + 1); @@ -509,20 +541,20 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) count = -1; retcount = 0; -#if HAVE_SNPRINTF +#if USE_SNPRINTF #define SNPRINTF_BUF(arg) \ switch (prefix_count) \ { \ case 0: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ arg, &count); \ break; \ case 1: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ prefixes[0], arg, &count); \ break; \ case 2: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ prefixes[0], prefixes[1], arg, \ &count); \ break; \ @@ -664,7 +696,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) abort (); } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* Portability: Not all implementations of snprintf() are ISO C 99 compliant. Determine the number of bytes that snprintf() has produced or would have @@ -705,7 +737,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) return NULL; } -#if !HAVE_SNPRINTF +#if !USE_SNPRINTF if (count >= tmp_length) /* tmp_length was incorrectly calculated - fix the code above! */ @@ -724,16 +756,16 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) n = 2 * allocated; ENSURE_ALLOCATION (n); -#if HAVE_SNPRINTF +#if USE_SNPRINTF continue; #endif } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* The snprintf() result did fit. */ #else /* Append the sprintf() result. */ - memcpy (result + length, tmp, count); + memcpy (result + length, tmp, count * sizeof (CHAR_T)); if (tmp != tmpbuf) free (tmp); #endif @@ -752,9 +784,9 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) if (result != resultbuf && length + 1 < allocated) { /* Shrink the allocated memory if possible. */ - char *memory; + CHAR_T *memory; - memory = (char *) realloc (result, length + 1); + memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); if (memory != NULL) result = memory; } @@ -765,3 +797,11 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) return result; } } + +#undef SNPRINTF +#undef USE_SNPRINTF +#undef PRINTF_PARSE +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef VASNPRINTF diff --git a/gettext-runtime/m4/ChangeLog b/gettext-runtime/m4/ChangeLog index e553ded18..3ef0b9c5a 100644 --- a/gettext-runtime/m4/ChangeLog +++ b/gettext-runtime/m4/ChangeLog @@ -1,3 +1,15 @@ +2003-06-19 Bruno Haible + + * printf-posix.m4: New file. + * Makefile.am (EXTRA_DIST): Add printf-posix.m4. + * gettext.m4 (AM_INTL_SUBDIR): Require bh_C_SIGNED, + jm_AC_TYPE_LONG_LONG, gt_TYPE_LONGDOUBLE, gt_TYPE_WCHAR_T, + gt_TYPE_WINT_T, jm_AC_HEADER_INTTYPES_H, jm_AC_HEADER_STDINT_H, + gt_TYPE_INTMAX_T, gt_PRINTF_POSIX. Check for ptrdiff_t, asprintf, + snprintf, wprintf. + * longlong.m4: Update from gnulib. + (jm_AC_TYPE_LONG_LONG): Replaces gt_TYPE_LONGLONG. + 2003-01-11 Bruno Haible * ulonglong.m4 (jm_AC_TYPE_UNSIGNED_LONG_LONG): Also test the ULL diff --git a/gettext-runtime/m4/Makefile.am b/gettext-runtime/m4/Makefile.am index 2cb866bae..130539180 100644 --- a/gettext-runtime/m4/Makefile.am +++ b/gettext-runtime/m4/Makefile.am @@ -19,6 +19,7 @@ longdouble.m4 \ longlong.m4 \ nls.m4 \ po.m4 \ +printf-posix.m4 \ progtest.m4 \ signed.m4 \ stdint_h.m4 \ diff --git a/gettext-runtime/m4/gettext.m4 b/gettext-runtime/m4/gettext.m4 index 16070b40a..1bf54ff0d 100644 --- a/gettext-runtime/m4/gettext.m4 +++ b/gettext-runtime/m4/gettext.m4 @@ -1,4 +1,4 @@ -# gettext.m4 serial 20 (gettext-0.12) +# gettext.m4 serial 21 (gettext-0.12.2) dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General @@ -354,9 +354,18 @@ AC_DEFUN([AM_INTL_SUBDIR], AC_REQUIRE([AC_ISC_POSIX])dnl AC_REQUIRE([AC_HEADER_STDC])dnl AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([bh_C_SIGNED])dnl AC_REQUIRE([AC_C_INLINE])dnl AC_REQUIRE([AC_TYPE_OFF_T])dnl AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([jm_AC_TYPE_LONG_LONG])dnl + AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl + AC_REQUIRE([gt_TYPE_WCHAR_T])dnl + AC_REQUIRE([gt_TYPE_WINT_T])dnl + AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([jm_AC_HEADER_STDINT_H]) + AC_REQUIRE([gt_TYPE_INTMAX_T]) + AC_REQUIRE([gt_PRINTF_POSIX]) AC_REQUIRE([AC_FUNC_ALLOCA])dnl AC_REQUIRE([AC_FUNC_MMAP])dnl AC_REQUIRE([jm_GLIBC21])dnl @@ -365,12 +374,37 @@ AC_DEFUN([AM_INTL_SUBDIR], AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl AC_REQUIRE([gt_INTTYPES_PRI])dnl + AC_CHECK_TYPES([ptrdiff_t]) AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ stdlib.h string.h unistd.h sys/param.h]) - AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ -geteuid getgid getuid mempcpy munmap putenv setenv setlocale stpcpy \ -strcasecmp strdup strtoul tsearch __argz_count __argz_stringify __argz_next \ -__fsetlocking]) + AC_CHECK_FUNCS([asprintf feof_unlocked fgets_unlocked getc_unlocked getcwd \ +getegid geteuid getgid getuid mempcpy munmap putenv setenv setlocale snprintf \ +stpcpy strcasecmp strdup strtoul tsearch wprintf __argz_count \ +__argz_stringify __argz_next __fsetlocking]) + + case $gt_cv_func_printf_posix in + *yes) HAVE_POSIX_PRINTF=1 ;; + *) HAVE_POSIX_PRINTF=0 ;; + esac + AC_SUBST([HAVE_POSIX_PRINTF]) + if test "$ac_cv_func_asprintf" = yes; then + HAVE_ASPRINTF=1 + else + HAVE_ASPRINTF=0 + fi + AC_SUBST([HAVE_ASPRINTF]) + if test "$ac_cv_func_snprintf" = yes; then + HAVE_SNPRINTF=1 + else + HAVE_SNPRINTF=0 + fi + AC_SUBST([HAVE_SNPRINTF]) + if test "$ac_cv_func_wprintf" = yes; then + HAVE_WPRINTF=1 + else + HAVE_WPRINTF=0 + fi + AC_SUBST([HAVE_WPRINTF]) AM_ICONV AM_LANGINFO_CODESET diff --git a/gettext-runtime/m4/longlong.m4 b/gettext-runtime/m4/longlong.m4 index b4f472db8..d7d7350b3 100644 --- a/gettext-runtime/m4/longlong.m4 +++ b/gettext-runtime/m4/longlong.m4 @@ -1,27 +1,25 @@ -# longlong.m4 serial 1 (gettext-0.12) -dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. +# longlong.m4 serial 4 +dnl Copyright (C) 1999-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. -dnl From Bruno Haible. -dnl Test whether the compiler supports the 'long long' type. -dnl Prerequisite: AC_PROG_CC +dnl From Paul Eggert. -AC_DEFUN([gt_TYPE_LONGLONG], +# Define HAVE_LONG_LONG if 'long long' works. + +AC_DEFUN([jm_AC_TYPE_LONG_LONG], [ - AC_CACHE_CHECK([for long long], gt_cv_c_long_long, - [if test "$GCC" = yes; then - gt_cv_c_long_long=yes - else - AC_TRY_COMPILE([long long foo = 0LL; - int array [2*(sizeof(long long) >= sizeof(long)) - 1]; - ], , - gt_cv_c_long_long=yes, gt_cv_c_long_long=no) - fi]) - if test $gt_cv_c_long_long = yes; then - AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the 'long long' type.]) + AC_CACHE_CHECK([for long long], ac_cv_type_long_long, + [AC_TRY_LINK([long long ll = 1LL; int i = 63;], + [long long llmax = (long long) -1; + return ll << i | ll >> i | llmax / ll | llmax % ll;], + ac_cv_type_long_long=yes, + ac_cv_type_long_long=no)]) + if test $ac_cv_type_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, + [Define if you have the 'long long' type.]) fi ]) diff --git a/gettext-runtime/m4/printf-posix.m4 b/gettext-runtime/m4/printf-posix.m4 new file mode 100644 index 000000000..d96c32c82 --- /dev/null +++ b/gettext-runtime/m4/printf-posix.m4 @@ -0,0 +1,43 @@ +# printf-posix.m4 serial 1 (gettext-0.12.2) +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. +dnl Test whether the printf() function supports POSIX/XSI format strings with +dnl positions. + +AC_DEFUN([gt_PRINTF_POSIX], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_CACHE_CHECK([whether printf() supports POSIX/XSI format strings], + gt_cv_func_printf_posix, + [ + AC_TRY_RUN([ +#include +#include +static char buf[100]; +int main () +{ + sprintf (buf, "%2$d %1$d", 33, 55); + return (strcmp (buf, "55 33") == 0); +}], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, + [ + AC_EGREP_CPP(notposix, [ +#if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ + notposix +#endif + ], gt_cv_func_printf_posix="guessing no", + gt_cv_func_printf_posix="guessing yes") + ]) + ]) + case $gt_cv_func_printf_posix in + *yes) + AC_DEFINE(HAVE_POSIX_PRINTF, 1, + [Define if your printf() function supports format strings with positions.]) + ;; + esac +]) diff --git a/gettext-tools/doc/ChangeLog b/gettext-tools/doc/ChangeLog index 52519def7..2bba4138e 100644 --- a/gettext-tools/doc/ChangeLog +++ b/gettext-tools/doc/ChangeLog @@ -1,3 +1,11 @@ +2003-06-19 Bruno Haible + + * gettext.texi (Sources): Recommend to use also for printf. + (aclocal): Mention also intmax.m4, longdouble.m4, longlong.m4, + printf-posix.m4, signed.m4, wchar_t.m4, wint_t.m4. + (c-format): Mention the printf(), fprintf() replacements. + (C, clisp C): Remove portability note for formatting with positions. + 2003-06-15 Bruno Haible * gettext.texi (C): Mention that formatting with positions doesn't work diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi index 5d1d197ba..07a1099a9 100644 --- a/gettext-tools/doc/gettext.texi +++ b/gettext-tools/doc/gettext.texi @@ -1709,6 +1709,14 @@ having translated C strings should contain the line: #include @end example +Similarly, each C module containing @code{printf()}/@code{fprintf()}/... +calls with a format string that could be a translated C string (even if +the C string comes from a different C module) should contain the line: + +@example +#include +@end example + The remaining changes to your C sources are discussed in the further sections of this chapter. @@ -6426,10 +6434,12 @@ AC_CONFIG_AUX_DIR([@var{subdir}]) If you do not have an @file{aclocal.m4} file in your distribution, the simplest is to concatenate the files @file{codeset.m4}, @file{gettext.m4}, @file{glibc21.m4}, @file{iconv.m4}, @file{intdiv0.m4}, -@file{inttypes.m4}, @file{inttypes_h.m4}, @file{inttypes-pri.m4}, -@file{isc-posix.m4}, @file{lcmessage.m4}, @file{lib-ld.m4}, -@file{lib-link.m4}, @file{lib-prefix.m4}, @file{progtest.m4}, -@file{stdint_h.m4}, @file{uintmax_t.m4}, @file{ulonglong.m4} +@file{intmax.m4}, @file{inttypes.m4}, @file{inttypes_h.m4}, +@file{inttypes-pri.m4}, @file{isc-posix.m4}, @file{lcmessage.m4}, +@file{lib-ld.m4}, @file{lib-link.m4}, @file{lib-prefix.m4}, +@file{longdouble.m4}, @file{longlong.m4}, @file{printf-posix.m4}, +@file{progtest.m4}, @file{signed.m4}, @file{stdint_h.m4}, @file{uintmax_t.m4}, +@file{ulonglong.m4}, @file{wchar_t.m4}, @file{wint_t.m4} from GNU @code{gettext}'s @file{m4/} directory into a single file. If you have suppressed the @file{intl/} directory, only @file{gettext.m4}, @file{iconv.m4}, @@ -7210,6 +7220,26 @@ See also the fprintf(3) manual page, @uref{http://www.linuxvalley.it/encyclopedia/ldp/manpage/man3/printf.3.php}, @uref{http://informatik.fh-wuerzburg.de/student/i510/man/printf.html}. +Although format strings with positions that reorder arguments, such as + +@example +"Only %2$d bytes free on '%1$s'." +@end example + +@noindent +which is semantically equivalent to + +@example +"'%s' has only %d bytes free." +@end example + +@noindent +are a POSIX/XSI feature and not specified by ISO C 99, translators can rely +on this reordering ability: On the few platforms where @code{printf()}, +@code{fprintf()} etc. don't support this feature natively, @file{libintl.a} +or @file{libintl.so} provides replacement functions, and GNU @code{} +activates these replacement functions automatically. + @node python-format, lisp-format, c-format, Translators for other Languages @subsection Python Format Strings @@ -7450,7 +7480,7 @@ Use @code{xgettext -k_} @item Formatting with positions -@code{fprintf "%2$d %1$d"} (POSIX/XSI but not C 99 - in practice, not NetBSD and not Windows) +@code{fprintf "%2$d %1$d"} @*In C++: @code{autosprintf "%2$d %1$d"} (@pxref{Top, , Introduction, autosprintf, GNU autosprintf}) @@ -7711,7 +7741,7 @@ use @code{clisp-xgettext} @item Formatting with positions -@code{fprintf "%2$d %1$d"} (POSIX/XSI but not C 99) +@code{fprintf "%2$d %1$d"} @item Portability On platforms without gettext, no translation. diff --git a/gettext-tools/m4/ChangeLog b/gettext-tools/m4/ChangeLog index a8f6de07c..4d145a2fe 100644 --- a/gettext-tools/m4/ChangeLog +++ b/gettext-tools/m4/ChangeLog @@ -1,3 +1,8 @@ +2003-06-19 Bruno Haible + + * Makefile.am (aclocal_DATA): Add intmax.m4, longdouble.m4, + longlong.m4, printf-posix.m4, signed.m4, wchar_t.m4, wint_t.m4. + 2003-06-19 Bruno Haible * locale-fr.m4: New file. diff --git a/gettext-tools/m4/Makefile.am b/gettext-tools/m4/Makefile.am index b315fd0b4..bfac6f135 100644 --- a/gettext-tools/m4/Makefile.am +++ b/gettext-tools/m4/Makefile.am @@ -12,17 +12,24 @@ aclocal_DATA = \ ../../gettext-runtime/m4/glibc21.m4 \ ../../gettext-runtime/m4/iconv.m4 \ ../../gettext-runtime/m4/intdiv0.m4 \ + ../../gettext-runtime/m4/intmax.m4 \ ../../gettext-runtime/m4/inttypes.m4 \ ../../gettext-runtime/m4/inttypes_h.m4 \ ../../gettext-runtime/m4/inttypes-pri.m4 \ ../../gettext-runtime/m4/isc-posix.m4 \ ../../gettext-runtime/m4/lcmessage.m4 \ + ../../gettext-runtime/m4/longdouble.m4 \ + ../../gettext-runtime/m4/longlong.m4 \ ../../gettext-runtime/m4/nls.m4 \ ../../gettext-runtime/m4/po.m4 \ + ../../gettext-runtime/m4/printf-posix.m4 \ ../../gettext-runtime/m4/progtest.m4 \ + ../../gettext-runtime/m4/signed.m4 \ ../../gettext-runtime/m4/stdint_h.m4 \ ../../gettext-runtime/m4/uintmax_t.m4 \ - ../../gettext-runtime/m4/ulonglong.m4 + ../../gettext-runtime/m4/ulonglong.m4 \ + ../../gettext-runtime/m4/wchar_t.m4 \ + ../../gettext-runtime/m4/wint_t.m4 # Generate this list with # find . -type f -name '*.m4' -printf '%f\n' | sort | tr '\012' @ | sed 's/@$/%/;s/@/ \\@/g' | tr @% '\012\012' diff --git a/gettext-tools/misc/ChangeLog b/gettext-tools/misc/ChangeLog index 149a9c4a2..180043687 100644 --- a/gettext-tools/misc/ChangeLog +++ b/gettext-tools/misc/ChangeLog @@ -1,3 +1,8 @@ +2003-06-19 Bruno Haible + + * gettextize.in (m4filelist): Add intmax.m4, longdouble.m4, + longlong.m4, printf-posix.m4, signed.m4, wchar_t.m4, wint_t.m4. + 2003-05-22 Bruno Haible * gettext-0.12.1 released. diff --git a/gettext-tools/misc/gettextize.in b/gettext-tools/misc/gettextize.in index 7bb0f453b..52a0f1dd0 100644 --- a/gettext-tools/misc/gettextize.in +++ b/gettext-tools/misc/gettextize.in @@ -638,12 +638,15 @@ if test -f "$srcdir/po/stamp-cat-id"; then fi $do_changelog && func_poChangeLog_finish -m4filelist=' codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 - inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 - lib-prefix.m4 nls.m4 po.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4' -# We cannot omit codeset.m4, glibc21.m4, intdiv0.m4, inttypes.m4, -# inttypes_h.m4, inttypes-pri.m4, isc-posix.m4, lcmessage.m4, nls.m4, po.m4, -# stdint_h.m4, uintmax_t.m4, ulonglong.m4 +m4filelist=' codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 intmax.m4 + inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 + lib-link.m4 lib-prefix.m4 longdouble.m4 longlong.m4 nls.m4 po.m4 + printf-posix.m4 progtest.m4 signed.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 + wchar_t.m4 wint_t.m4' +# We cannot omit codeset.m4, glibc21.m4, intdiv0.m4, intmax.m4, inttypes.m4, +# inttypes_h.m4, inttypes-pri.m4, isc-posix.m4, lcmessage.m4, longdouble.m4, +# longlong.m4, nls.m4, po.m4, printf-posix.m4, signed.m4, stdint_h.m4, +# uintmax_t.m4, ulonglong.m4, wchar_t.m4, wint_t.m4 # if test -z "$intldir", otherwise "aclocal -I m4" might give an error. # (aclocal doesn't know which macros are really needed, it looks which macros # are potentially needed.)