From 820079f092edf503c03f4c5f5671a7dfa863d64f Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Tue, 13 Mar 2012 16:23:38 +0000 Subject: [PATCH] Roll back changes for autodetecting C99 vsnprintf (#1688) git-svn-id: http://svn.osgeo.org/postgis/trunk@9485 b70326c6-7e19-0410-871a-916f4a2858ee --- configure.ac | 41 +- liblwgeom/Makefile.in | 3 - liblwgeom/cunit/cu_out_kml.c | 12 +- liblwgeom/liblwgeom.h.in | 15 +- liblwgeom/liblwgeom_internal.h | 19 - liblwgeom/lwgeom_geos.c | 2 +- liblwgeom/snprintf.c | 2110 -------------------------------- liblwgeom/stringbuffer.c | 11 +- liblwgeom/vsprintf.c | 197 ++- libpgcommon/lwgeom_pg.c | 2 +- macros/snprintf.m4 | 230 ---- postgis_config.h.in | 30 +- raster/rt_pg/rt_pg.c | 2 +- 13 files changed, 182 insertions(+), 2492 deletions(-) delete mode 100644 macros/snprintf.m4 diff --git a/configure.ac b/configure.ac index 4f499ca34..52a4eb95f 100644 --- a/configure.ac +++ b/configure.ac @@ -14,6 +14,7 @@ AC_INIT() AC_CONFIG_HEADERS([postgis_config.h]) AC_CONFIG_MACRO_DIR([macros]) + dnl Invoke libtool: we do this as it is the easiest way to find the PIC dnl flags required to build liblwgeom AC_PROG_LIBTOOL @@ -27,35 +28,6 @@ AC_PROG_CXX AC_PATH_PROG([ANT], [ant], []) AC_SUBST([ANT]) -dnl -dnl Types -dnl -AC_TYPE_LONG_LONG_INT -AC_TYPE_LONG_DOUBLE -AC_TYPE_UNSIGNED_LONG_LONG_INT -AC_TYPE_INTMAX_T -AC_TYPE_UINTMAX_T -AC_TYPE_UINTPTR_T - -dnl -dnl Functions -dnl -HW_FUNC_VA_COPY -HW_FUNC___VA_COPY -HW_FUNC_VSNPRINTF -HW_FUNC_SNPRINTF -HW_FUNC_VASPRINTF -HW_FUNC_ASPRINTF -AC_FUNC_FSEEKO - -dnl -dnl Check for platform-specific functions -dnl -dnl AC_CHECK_FUNC(vasprintf, [HAVE_VASPRINTF=1], [HAVE_VASPRINTF=0]) -dnl AC_DEFINE([HAVE_VASPRINTF]) -dnl AC_CHECK_FUNC(asprintf, [HAVE_ASPRINTF=1], [HAVE_ASPRINTF=0]) -dnl AC_DEFINE([HAVE_ASPRINTF]) - dnl dnl Define PIC flags in PICFLAGS (note: this variable is set as part of libtool initialisation above) dnl @@ -101,6 +73,7 @@ AC_SUBST([POSTGIS_MICRO_VERSION]) dnl dnl Search for flex/bison to build the parser dnl + AC_PROG_LEX AC_PROG_YACC AC_SUBST([LEX]) @@ -114,6 +87,16 @@ AC_DEFINE_UNQUOTED([HAVE_IEEEFP_H], [$HAVE_IEEEFP_H], [ieeefp.h header]) AC_CHECK_HEADER([termios.h], [HAVE_TERMIOS_H=1], [HAVE_TERMIOS_H=0]) AC_DEFINE_UNQUOTED([HAVE_TERMIOS_H], [$HAVE_TERMIOS_H], [termios.h header]) + +dnl +dnl Check for platform-specific functions +dnl +AC_CHECK_FUNC(vasprintf, [HAVE_VASPRINTF=1], [HAVE_VASPRINTF=0]) +AC_DEFINE([HAVE_VASPRINTF]) +AC_CHECK_FUNC(asprintf, [HAVE_ASPRINTF=1], [HAVE_ASPRINTF=0]) +AC_DEFINE([HAVE_ASPRINTF]) +AC_FUNC_FSEEKO() + dnl dnl MingW requires use of pwd -W to give proper Windows (not MingW) paths dnl for in-place regression tests diff --git a/liblwgeom/Makefile.in b/liblwgeom/Makefile.in index 37c8cb40f..872003c4c 100644 --- a/liblwgeom/Makefile.in +++ b/liblwgeom/Makefile.in @@ -68,7 +68,6 @@ SA_OBJS = \ lwsegmentize.o \ lwlinearreferencing.o \ lwprint.o \ - snprintf.o \ vsprintf.o \ g_box.o \ g_serialized.o \ @@ -88,8 +87,6 @@ SA_OBJS = \ lwgeom_geos_split.o \ lwgeom_transform.o - - NM_OBJS = \ lwspheroid.o diff --git a/liblwgeom/cunit/cu_out_kml.c b/liblwgeom/cunit/cu_out_kml.c index 34eaf1e21..5fee60e38 100644 --- a/liblwgeom/cunit/cu_out_kml.c +++ b/liblwgeom/cunit/cu_out_kml.c @@ -77,12 +77,6 @@ static void do_kml_test_prefix(char * in, char * out, int precision, const char static void out_kml_test_precision(void) { - /* huge data */ - do_kml_test( - "POINT(1E300 -1E300)", - "1e+300,-1e+300", - 0); - /* 0 precision, i.e a round */ do_kml_test( "POINT(1.1111111111111 1.1111111111111)", @@ -100,6 +94,12 @@ static void out_kml_test_precision(void) "POINT(1.2345678901234 1.2345678901234)", "1.23456789,1.23456789", 8); + + /* huge data */ + do_kml_test( + "POINT(1E300 -1E300)", + "1e+300,-1e+300", + 0); } diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index af02ec182..76326a9ba 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -227,19 +227,7 @@ void default_freeor(void *ptr); void default_errorreporter(const char *fmt, va_list ap); void default_noticereporter(const char *fmt, va_list ap); -extern int lw_vasprintf(char **result, const char *format, va_list ap); -extern int lw_vsnprintf(char *s, size_t n, const char *format, va_list ap); - -extern int lw_snprintf -#if __STDC__ -(char *s, size_t n, const char *format, ...); -#else -(result, n, va_alist); -char *result; -size_t n; -va_dcl -#endif - +extern int lw_vasprintf (char **result, const char *format, va_list args); extern int lw_asprintf #if __STDC__ (char **result, const char *format, ...); @@ -250,7 +238,6 @@ va_dcl #endif - /******************************************************************/ typedef struct { diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index b58ce2575..a7a5579f3 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -31,25 +31,6 @@ #include "liblwgeom.h" -/** -* SNPRINTF Compatibility Functions -*/ -#if HAVE_STDARG_H -#include -#if !HAVE_VSNPRINTF -int rpl_vsnprintf(char *, size_t, const char *, va_list); -#endif -#if !HAVE_SNPRINTF -int rpl_snprintf(char *, size_t, const char *, ...); -#endif -#if !HAVE_VASPRINTF -int rpl_vasprintf(char **, const char *, va_list); -#endif -#if !HAVE_ASPRINTF -int rpl_asprintf(char **, const char *, ...); -#endif -#endif /* HAVE_STDARG_H */ - /** * PI */ diff --git a/liblwgeom/lwgeom_geos.c b/liblwgeom/lwgeom_geos.c index ea093200f..deb5593f3 100644 --- a/liblwgeom/lwgeom_geos.c +++ b/liblwgeom/lwgeom_geos.c @@ -28,7 +28,7 @@ lwgeom_geos_error(const char *fmt, ...) va_start(ap, fmt); /* Call the supplied function */ - if ( LWGEOM_GEOS_ERRMSG_MAXSIZE-1 < lw_vsnprintf(lwgeom_geos_errmsg, LWGEOM_GEOS_ERRMSG_MAXSIZE-1, fmt, ap) ) + if ( LWGEOM_GEOS_ERRMSG_MAXSIZE-1 < vsnprintf(lwgeom_geos_errmsg, LWGEOM_GEOS_ERRMSG_MAXSIZE-1, fmt, ap) ) { lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE-1] = '\0'; } diff --git a/liblwgeom/snprintf.c b/liblwgeom/snprintf.c index 05909b429..e69de29bb 100644 --- a/liblwgeom/snprintf.c +++ b/liblwgeom/snprintf.c @@ -1,2110 +0,0 @@ -/* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */ - -/* - * Copyright (c) 1995 Patrick Powell. - * - * This code is based on code written by Patrick Powell . - * It may be used for any purpose as long as this notice remains intact on all - * source code distributions. - */ - -/* - * Copyright (c) 2008 Holger Weiss. - * - * This version of the code is maintained by Holger Weiss . - * My changes to the code may freely be used, modified and/or redistributed for - * any purpose. It would be nice if additions and fixes to this file (including - * trivial code cleanups) would be sent back in order to let me include them in - * the version available at . - * However, this is not a requirement for using or redistributing (possibly - * modified) versions of this file, nor is leaving this notice intact mandatory. - */ - -/* - * History - * - * 2008-01-20 Holger Weiss for C99-snprintf 1.1: - * - * Fixed the detection of infinite floating point values on IRIX (and - * possibly other systems) and applied another few minor cleanups. - * - * 2008-01-06 Holger Weiss for C99-snprintf 1.0: - * - * Added a lot of new features, fixed many bugs, and incorporated various - * improvements done by Andrew Tridgell , Russ Allbery - * , Hrvoje Niksic , Damien Miller - * , and others for the Samba, INN, Wget, and OpenSSH - * projects. The additions include: support the "e", "E", "g", "G", and - * "F" conversion specifiers (and use conversion style "f" or "F" for the - * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", - * "t", and "z" length modifiers; support the "#" flag and the (non-C99) - * "'" flag; use localeconv(3) (if available) to get both the current - * locale's decimal point character and the separator between groups of - * digits; fix the handling of various corner cases of field width and - * precision specifications; fix various floating point conversion bugs; - * handle infinite and NaN floating point values; don't attempt to write to - * the output buffer (which may be NULL) if a size of zero was specified; - * check for integer overflow of the field width, precision, and return - * values and during the floating point conversion; use the OUTCHAR() macro - * instead of a function for better performance; provide asprintf(3) and - * vasprintf(3) functions; add new test cases. The replacement functions - * have been renamed to use an "rpl_" prefix, the function calls in the - * main project (and in this file) must be redefined accordingly for each - * replacement function which is needed (by using Autoconf or other means). - * Various other minor improvements have been applied and the coding style - * was cleaned up for consistency. - * - * 2007-07-23 Holger Weiss for Mutt 1.5.13: - * - * C99 compliant snprintf(3) and vsnprintf(3) functions return the number - * of characters that would have been written to a sufficiently sized - * buffer (excluding the '\0'). The original code simply returned the - * length of the resulting output string, so that's been fixed. - * - * 1998-03-05 Michael Elkins for Mutt 0.90.8: - * - * The original code assumed that both snprintf(3) and vsnprintf(3) were - * missing. Some systems only have snprintf(3) but not vsnprintf(3), so - * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. - * - * 1998-01-27 Thomas Roessler for Mutt 0.89i: - * - * The PGP code was using unsigned hexadecimal formats. Unfortunately, - * unsigned formats simply didn't work. - * - * 1997-10-22 Brandon Long for Mutt 0.87.1: - * - * Ok, added some minimal floating point support, which means this probably - * requires libm on most operating systems. Don't yet support the exponent - * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just - * wasn't being exercised in ways which showed it, so that's been fixed. - * Also, formatted the code to Mutt conventions, and removed dead code left - * over from the original. Also, there is now a builtin-test, run with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf - * - * 2996-09-15 Brandon Long for Mutt 0.43: - * - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything from the - * normal C string format, at least as far as I can tell from the Solaris - * 2.5 printf(3S) man page. - */ - -/* - * ToDo - * - * - Add wide character support. - * - Add support for "%a" and "%A" conversions. - * - Create test routines which predefine the expected results. Our test cases - * usually expose bugs in system implementations rather than in ours :-) - */ - -/* - * Usage - * - * 1) The following preprocessor macros should be defined to 1 if the feature or - * file in question is available on the target system (by using Autoconf or - * other means), though basic functionality should be available as long as - * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: - * - * HAVE_VSNPRINTF - * HAVE_SNPRINTF - * HAVE_VASPRINTF - * HAVE_ASPRINTF - * HAVE_STDARG_H - * HAVE_STDDEF_H - * HAVE_STDINT_H - * HAVE_STDLIB_H - * HAVE_INTTYPES_H - * HAVE_LOCALE_H - * HAVE_LOCALECONV - * HAVE_LCONV_DECIMAL_POINT - * HAVE_LCONV_THOUSANDS_SEP - * HAVE_LONG_DOUBLE - * HAVE_LONG_LONG_INT - * HAVE_UNSIGNED_LONG_LONG_INT - * HAVE_INTMAX_T - * HAVE_UINTMAX_T - * HAVE_UINTPTR_T - * HAVE_PTRDIFF_T - * HAVE_VA_COPY - * HAVE___VA_COPY - * - * 2) The calls to the functions which should be replaced must be redefined - * throughout the project files (by using Autoconf or other means): - * - * #define vsnprintf rpl_vsnprintf - * #define snprintf rpl_snprintf - * #define vasprintf rpl_vasprintf - * #define asprintf rpl_asprintf - * - * 3) The required replacement functions should be declared in some header file - * included throughout the project files: - * - * #if HAVE_CONFIG_H - * #include - * #endif - * #if HAVE_STDARG_H - * #include - * #if !HAVE_VSNPRINTF - * int rpl_vsnprintf(char *, size_t, const char *, va_list); - * #endif - * #if !HAVE_SNPRINTF - * int rpl_snprintf(char *, size_t, const char *, ...); - * #endif - * #if !HAVE_VASPRINTF - * int rpl_vasprintf(char **, const char *, va_list); - * #endif - * #if !HAVE_ASPRINTF - * int rpl_asprintf(char **, const char *, ...); - * #endif - * #endif - * - * Autoconf macros for handling step 1 and step 2 are available at - * . - */ - -#include "liblwgeom_internal.h" - -#if HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#if TEST_SNPRINTF -#include /* For pow(3), NAN, and INFINITY. */ -#include /* For strcmp(3). */ -#if defined(__NetBSD__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NeXT__) || \ - defined(__bsd__) -#define OS_BSD 1 -#elif defined(sgi) || defined(__sgi) -#ifndef __c99 -#define __c99 /* Force C99 mode to get included on IRIX 6.5.30. */ -#endif /* !defined(__c99) */ -#define OS_IRIX 1 -#define OS_SYSV 1 -#elif defined(__svr4__) -#define OS_SYSV 1 -#elif defined(__linux__) -#define OS_LINUX 1 -#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ -#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ -#ifdef HAVE_SNPRINTF -#undef HAVE_SNPRINTF -#endif /* defined(HAVE_SNPRINTF) */ -#ifdef HAVE_VSNPRINTF -#undef HAVE_VSNPRINTF -#endif /* defined(HAVE_VSNPRINTF) */ -#ifdef HAVE_ASPRINTF -#undef HAVE_ASPRINTF -#endif /* defined(HAVE_ASPRINTF) */ -#ifdef HAVE_VASPRINTF -#undef HAVE_VASPRINTF -#endif /* defined(HAVE_VASPRINTF) */ -#ifdef snprintf -#undef snprintf -#endif /* defined(snprintf) */ -#ifdef vsnprintf -#undef vsnprintf -#endif /* defined(vsnprintf) */ -#ifdef asprintf -#undef asprintf -#endif /* defined(asprintf) */ -#ifdef vasprintf -#undef vasprintf -#endif /* defined(vasprintf) */ -#else /* By default, we assume a modern system for testing. */ -#ifndef HAVE_STDARG_H -#define HAVE_STDARG_H 1 -#endif /* HAVE_STDARG_H */ -#ifndef HAVE_STDDEF_H -#define HAVE_STDDEF_H 1 -#endif /* HAVE_STDDEF_H */ -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H 1 -#endif /* HAVE_STDINT_H */ -#ifndef HAVE_STDLIB_H -#define HAVE_STDLIB_H 1 -#endif /* HAVE_STDLIB_H */ -#ifndef HAVE_INTTYPES_H -#define HAVE_INTTYPES_H 1 -#endif /* HAVE_INTTYPES_H */ -#ifndef HAVE_LOCALE_H -#define HAVE_LOCALE_H 1 -#endif /* HAVE_LOCALE_H */ -#ifndef HAVE_LOCALECONV -#define HAVE_LOCALECONV 1 -#endif /* !defined(HAVE_LOCALECONV) */ -#ifndef HAVE_LCONV_DECIMAL_POINT -#define HAVE_LCONV_DECIMAL_POINT 1 -#endif /* HAVE_LCONV_DECIMAL_POINT */ -#ifndef HAVE_LCONV_THOUSANDS_SEP -#define HAVE_LCONV_THOUSANDS_SEP 1 -#endif /* HAVE_LCONV_THOUSANDS_SEP */ -#ifndef HAVE_LONG_DOUBLE -#define HAVE_LONG_DOUBLE 1 -#endif /* !defined(HAVE_LONG_DOUBLE) */ -#ifndef HAVE_LONG_LONG_INT -#define HAVE_LONG_LONG_INT 1 -#endif /* !defined(HAVE_LONG_LONG_INT) */ -#ifndef HAVE_UNSIGNED_LONG_LONG_INT -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ -#ifndef HAVE_INTMAX_T -#define HAVE_INTMAX_T 1 -#endif /* !defined(HAVE_INTMAX_T) */ -#ifndef HAVE_UINTMAX_T -#define HAVE_UINTMAX_T 1 -#endif /* !defined(HAVE_UINTMAX_T) */ -#ifndef HAVE_UINTPTR_T -#define HAVE_UINTPTR_T 1 -#endif /* !defined(HAVE_UINTPTR_T) */ -#ifndef HAVE_PTRDIFF_T -#define HAVE_PTRDIFF_T 1 -#endif /* !defined(HAVE_PTRDIFF_T) */ -#ifndef HAVE_VA_COPY -#define HAVE_VA_COPY 1 -#endif /* !defined(HAVE_VA_COPY) */ -#ifndef HAVE___VA_COPY -#define HAVE___VA_COPY 1 -#endif /* !defined(HAVE___VA_COPY) */ -#endif /* HAVE_CONFIG_H */ -#define snprintf rpl_snprintf -#define vsnprintf rpl_vsnprintf -#define asprintf rpl_asprintf -#define vasprintf rpl_vasprintf -#endif /* TEST_SNPRINTF */ - -#if !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || !HAVE_VASPRINTF -#include /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ -#ifdef VA_START -#undef VA_START -#endif /* defined(VA_START) */ -#ifdef VA_SHIFT -#undef VA_SHIFT -#endif /* defined(VA_SHIFT) */ -#if HAVE_STDARG_H -#include -#define VA_START(ap, last) va_start(ap, last) -#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ -#else /* Assume is available. */ -#include -#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ -#define VA_SHIFT(ap, value, type) value = va_arg(ap, type) -#endif /* HAVE_STDARG_H */ - -#if !HAVE_VASPRINTF -#if HAVE_STDLIB_H -#include /* For malloc(3). */ -#endif /* HAVE_STDLIB_H */ -#ifdef VA_COPY -#undef VA_COPY -#endif /* defined(VA_COPY) */ -#ifdef VA_END_COPY -#undef VA_END_COPY -#endif /* defined(VA_END_COPY) */ -#if HAVE_VA_COPY -#define VA_COPY(dest, src) va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#elif HAVE___VA_COPY -#define VA_COPY(dest, src) __va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#else -#define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list)) -#define VA_END_COPY(ap) /* No-op. */ -#define NEED_MYMEMCPY 1 -static void *mymemcpy(void *, void *, size_t); -#endif /* HAVE_VA_COPY */ -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_VSNPRINTF -#include /* For ERANGE and errno. */ -#include /* For *_MAX. */ -#if HAVE_INTTYPES_H -#include /* For intmax_t (if not defined in ). */ -#endif /* HAVE_INTTYPES_H */ -#if HAVE_LOCALE_H -#include /* For localeconv(3). */ -#endif /* HAVE_LOCALE_H */ -#if HAVE_STDDEF_H -#include /* For ptrdiff_t. */ -#endif /* HAVE_STDDEF_H */ -#if HAVE_STDINT_H -#include /* For intmax_t. */ -#endif /* HAVE_STDINT_H */ - -/* Support for unsigned long long int. We may also need ULLONG_MAX. */ -#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ -#ifdef UINT_MAX -#define ULONG_MAX UINT_MAX -#else -#define ULONG_MAX INT_MAX -#endif /* defined(UINT_MAX) */ -#endif /* !defined(ULONG_MAX) */ -#ifdef ULLONG -#undef ULLONG -#endif /* defined(ULLONG) */ -#if HAVE_UNSIGNED_LONG_LONG_INT -#define ULLONG unsigned long long int -#ifndef ULLONG_MAX -#define ULLONG_MAX ULONG_MAX -#endif /* !defined(ULLONG_MAX) */ -#else -#define ULLONG unsigned long int -#ifdef ULLONG_MAX -#undef ULLONG_MAX -#endif /* defined(ULLONG_MAX) */ -#define ULLONG_MAX ULONG_MAX -#endif /* HAVE_LONG_LONG_INT */ - -/* Support for uintmax_t. We also need UINTMAX_MAX. */ -#ifdef UINTMAX_T -#undef UINTMAX_T -#endif /* defined(UINTMAX_T) */ -#if HAVE_UINTMAX_T || defined(uintmax_t) -#define UINTMAX_T uintmax_t -#ifndef UINTMAX_MAX -#define UINTMAX_MAX ULLONG_MAX -#endif /* !defined(UINTMAX_MAX) */ -#else -#define UINTMAX_T ULLONG -#ifdef UINTMAX_MAX -#undef UINTMAX_MAX -#endif /* defined(UINTMAX_MAX) */ -#define UINTMAX_MAX ULLONG_MAX -#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ - -/* Support for long double. */ -#ifndef LDOUBLE -#if HAVE_LONG_DOUBLE -#define LDOUBLE long double -#else -#define LDOUBLE double -#endif /* HAVE_LONG_DOUBLE */ -#endif /* !defined(LDOUBLE) */ - -/* Support for long long int. */ -#ifndef LLONG -#if HAVE_LONG_LONG_INT -#define LLONG long long int -#else -#define LLONG long int -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !defined(LLONG) */ - -/* Support for intmax_t. */ -#ifndef INTMAX_T -#if HAVE_INTMAX_T || defined(intmax_t) -#define INTMAX_T intmax_t -#else -#define INTMAX_T LLONG -#endif /* HAVE_INTMAX_T || defined(intmax_t) */ -#endif /* !defined(INTMAX_T) */ - -/* Support for uintptr_t. */ -#ifndef UINTPTR_T -#if HAVE_UINTPTR_T || defined(uintptr_t) -#define UINTPTR_T uintptr_t -#else -#define UINTPTR_T unsigned long int -#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ -#endif /* !defined(UINTPTR_T) */ - -/* Support for ptrdiff_t. */ -#ifndef PTRDIFF_T -#if HAVE_PTRDIFF_T || defined(ptrdiff_t) -#define PTRDIFF_T ptrdiff_t -#else -#define PTRDIFF_T long int -#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ -#endif /* !defined(PTRDIFF_T) */ - -/* - * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: - * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an - * unsigned type if necessary. This should work just fine in practice. - */ -#ifndef UPTRDIFF_T -#define UPTRDIFF_T PTRDIFF_T -#endif /* !defined(UPTRDIFF_T) */ - -/* - * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). - * However, we'll simply use size_t and convert it to a signed type if - * necessary. This should work just fine in practice. - */ -#ifndef SSIZE_T -#define SSIZE_T size_t -#endif /* !defined(SSIZE_T) */ - -/* Either ERANGE or E2BIG should be available everywhere. */ -#ifndef ERANGE -#define ERANGE E2BIG -#endif /* !defined(ERANGE) */ -#ifndef EOVERFLOW -#define EOVERFLOW ERANGE -#endif /* !defined(EOVERFLOW) */ - -/* - * Buffer size to hold the octal string representation of UINT128_MAX without - * nul-termination ("3777777777777777777777777777777777777777777"). - */ -#ifdef MAX_CONVERT_LENGTH -#undef MAX_CONVERT_LENGTH -#endif /* defined(MAX_CONVERT_LENGTH) */ -#define MAX_CONVERT_LENGTH 43 - -/* Format read states. */ -#define PRINT_S_DEFAULT 0 -#define PRINT_S_FLAGS 1 -#define PRINT_S_WIDTH 2 -#define PRINT_S_DOT 3 -#define PRINT_S_PRECISION 4 -#define PRINT_S_MOD 5 -#define PRINT_S_CONV 6 - -/* Format flags. */ -#define PRINT_F_MINUS (1 << 0) -#define PRINT_F_PLUS (1 << 1) -#define PRINT_F_SPACE (1 << 2) -#define PRINT_F_NUM (1 << 3) -#define PRINT_F_ZERO (1 << 4) -#define PRINT_F_QUOTE (1 << 5) -#define PRINT_F_UP (1 << 6) -#define PRINT_F_UNSIGNED (1 << 7) -#define PRINT_F_TYPE_G (1 << 8) -#define PRINT_F_TYPE_E (1 << 9) - -/* Conversion flags. */ -#define PRINT_C_CHAR 1 -#define PRINT_C_SHORT 2 -#define PRINT_C_LONG 3 -#define PRINT_C_LLONG 4 -#define PRINT_C_LDOUBLE 5 -#define PRINT_C_SIZE 6 -#define PRINT_C_PTRDIFF 7 -#define PRINT_C_INTMAX 8 - -#ifndef MAX -#define MAX(x, y) ((x >= y) ? x : y) -#endif /* !defined(MAX) */ -#ifndef CHARTOINT -#define CHARTOINT(ch) (ch - '0') -#endif /* !defined(CHARTOINT) */ -#ifndef ISDIGIT -#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') -#endif /* !defined(ISDIGIT) */ -#ifndef ISNAN -#define ISNAN(x) (x != x) -#endif /* !defined(ISNAN) */ -#ifndef ISINF -#define ISINF(x) (x != 0.0 && x + x == x) -#endif /* !defined(ISINF) */ - -#ifdef OUTCHAR -#undef OUTCHAR -#endif /* defined(OUTCHAR) */ -#define OUTCHAR(str, len, size, ch) \ -do { \ - if (len + 1 < size) \ - str[len] = ch; \ - (len)++; \ -} while (/* CONSTCOND */ 0) - -static void fmtstr(char *, size_t *, size_t, const char *, int, int, int); -static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int); -static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *); -static void printsep(char *, size_t *, size_t); -static int getnumsep(int); -static int getexponent(LDOUBLE); -static int convert(UINTMAX_T, char *, size_t, int, int); -static UINTMAX_T cast(LDOUBLE); -static UINTMAX_T myround(LDOUBLE); -static LDOUBLE mypow10(int); - -extern int errno; - -int -rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - LDOUBLE fvalue; - INTMAX_T value; - unsigned char cvalue; - const char *strvalue; - INTMAX_T *intmaxptr; - PTRDIFF_T *ptrdiffptr; - SSIZE_T *sizeptr; - LLONG *llongptr; - long int *longptr; - int *intptr; - short int *shortptr; - signed char *charptr; - size_t len = 0; - int overflow = 0; - int base = 0; - int cflags = 0; - int flags = 0; - int width = 0; - int precision = -1; - int state = PRINT_S_DEFAULT; - char ch = *format++; - - /* - * C99 says: "If `n' is zero, nothing is written, and `s' may be a null - * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer - * even if a size larger than zero was specified. At least NetBSD's - * snprintf(3) does the same, as well as other versions of this file. - * (Though some of these versions will write to a non-NULL buffer even - * if a size of zero was specified, which violates the standard.) - */ - if (str == NULL && size != 0) - size = 0; - - while (ch != '\0') - switch (state) { - case PRINT_S_DEFAULT: - if (ch == '%') - state = PRINT_S_FLAGS; - else - OUTCHAR(str, len, size, ch); - ch = *format++; - break; - case PRINT_S_FLAGS: - switch (ch) { - case '-': - flags |= PRINT_F_MINUS; - ch = *format++; - break; - case '+': - flags |= PRINT_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= PRINT_F_SPACE; - ch = *format++; - break; - case '#': - flags |= PRINT_F_NUM; - ch = *format++; - break; - case '0': - flags |= PRINT_F_ZERO; - ch = *format++; - break; - case '\'': /* SUSv2 flag (not in C99). */ - flags |= PRINT_F_QUOTE; - ch = *format++; - break; - default: - state = PRINT_S_WIDTH; - break; - } - break; - case PRINT_S_WIDTH: - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (width > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - width = 10 * width + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative field width argument is - * taken as a `-' flag followed by a positive - * field width." (7.19.6.1, 5) - */ - if ((width = va_arg(args, int)) < 0) { - flags |= PRINT_F_MINUS; - width = -width; - } - ch = *format++; - state = PRINT_S_DOT; - } else - state = PRINT_S_DOT; - break; - case PRINT_S_DOT: - if (ch == '.') { - state = PRINT_S_PRECISION; - ch = *format++; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_PRECISION: - if (precision == -1) - precision = 0; - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (precision > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - precision = 10 * precision + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative precision argument is - * taken as if the precision were omitted." - * (7.19.6.1, 5) - */ - if ((precision = va_arg(args, int)) < 0) - precision = -1; - ch = *format++; - state = PRINT_S_MOD; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_MOD: - switch (ch) { - case 'h': - ch = *format++; - if (ch == 'h') { /* It's a char. */ - ch = *format++; - cflags = PRINT_C_CHAR; - } else - cflags = PRINT_C_SHORT; - break; - case 'l': - ch = *format++; - if (ch == 'l') { /* It's a long long. */ - ch = *format++; - cflags = PRINT_C_LLONG; - } else - cflags = PRINT_C_LONG; - break; - case 'L': - cflags = PRINT_C_LDOUBLE; - ch = *format++; - break; - case 'j': - cflags = PRINT_C_INTMAX; - ch = *format++; - break; - case 't': - cflags = PRINT_C_PTRDIFF; - ch = *format++; - break; - case 'z': - cflags = PRINT_C_SIZE; - ch = *format++; - break; - } - state = PRINT_S_CONV; - break; - case PRINT_S_CONV: - switch (ch) { - case 'd': - /* FALLTHROUGH */ - case 'i': - switch (cflags) { - case PRINT_C_CHAR: - value = (signed char)va_arg(args, int); - break; - case PRINT_C_SHORT: - value = (short int)va_arg(args, int); - break; - case PRINT_C_LONG: - value = va_arg(args, long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, LLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, SSIZE_T); - break; - case PRINT_C_INTMAX: - value = va_arg(args, INTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, PTRDIFF_T); - break; - default: - value = va_arg(args, int); - break; - } - fmtint(str, &len, size, value, 10, width, - precision, flags); - break; - case 'X': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'x': - base = 16; - /* FALLTHROUGH */ - case 'o': - if (base == 0) - base = 8; - /* FALLTHROUGH */ - case 'u': - if (base == 0) - base = 10; - flags |= PRINT_F_UNSIGNED; - switch (cflags) { - case PRINT_C_CHAR: - value = (unsigned char)va_arg(args, - unsigned int); - break; - case PRINT_C_SHORT: - value = (unsigned short int)va_arg(args, - unsigned int); - break; - case PRINT_C_LONG: - value = va_arg(args, unsigned long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, ULLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, size_t); - break; - case PRINT_C_INTMAX: - value = va_arg(args, UINTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, UPTRDIFF_T); - break; - default: - value = va_arg(args, unsigned int); - break; - } - fmtint(str, &len, size, value, base, width, - precision, flags); - break; - case 'A': - /* Not yet supported, we'll use "%F". */ - /* FALLTHROUGH */ - case 'F': - flags |= PRINT_F_UP; - case 'a': - /* Not yet supported, we'll use "%f". */ - /* FALLTHROUGH */ - case 'f': - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'E': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'e': - flags |= PRINT_F_TYPE_E; - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'G': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'g': - flags |= PRINT_F_TYPE_G; - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - /* - * If the precision is zero, it is treated as - * one (cf. C99: 7.19.6.1, 8). - */ - if (precision == 0) - precision = 1; - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'c': - cvalue = va_arg(args, int); - OUTCHAR(str, len, size, cvalue); - break; - case 's': - strvalue = va_arg(args, char *); - fmtstr(str, &len, size, strvalue, width, - precision, flags); - break; - case 'p': - /* - * C99 says: "The value of the pointer is - * converted to a sequence of printing - * characters, in an implementation-defined - * manner." (C99: 7.19.6.1, 8) - */ - if ((strvalue = va_arg(args, void *)) == NULL) - /* - * We use the glibc format. BSD prints - * "0x0", SysV "0". - */ - fmtstr(str, &len, size, "(nil)", width, - -1, flags); - else { - /* - * We use the BSD/glibc format. SysV - * omits the "0x" prefix (which we emit - * using the PRINT_F_NUM flag). - */ - flags |= PRINT_F_NUM; - flags |= PRINT_F_UNSIGNED; - fmtint(str, &len, size, - (UINTPTR_T)strvalue, 16, width, - precision, flags); - } - break; - case 'n': - switch (cflags) { - case PRINT_C_CHAR: - charptr = va_arg(args, signed char *); - *charptr = len; - break; - case PRINT_C_SHORT: - shortptr = va_arg(args, short int *); - *shortptr = len; - break; - case PRINT_C_LONG: - longptr = va_arg(args, long int *); - *longptr = len; - break; - case PRINT_C_LLONG: - llongptr = va_arg(args, LLONG *); - *llongptr = len; - break; - case PRINT_C_SIZE: - /* - * C99 says that with the "z" length - * modifier, "a following `n' conversion - * specifier applies to a pointer to a - * signed integer type corresponding to - * size_t argument." (7.19.6.1, 7) - */ - sizeptr = va_arg(args, SSIZE_T *); - *sizeptr = len; - break; - case PRINT_C_INTMAX: - intmaxptr = va_arg(args, INTMAX_T *); - *intmaxptr = len; - break; - case PRINT_C_PTRDIFF: - ptrdiffptr = va_arg(args, PTRDIFF_T *); - *ptrdiffptr = len; - break; - default: - intptr = va_arg(args, int *); - *intptr = len; - break; - } - break; - case '%': /* Print a "%" character verbatim. */ - OUTCHAR(str, len, size, ch); - break; - default: /* Skip other characters. */ - break; - } - ch = *format++; - state = PRINT_S_DEFAULT; - base = cflags = flags = width = 0; - precision = -1; - break; - } -out: - if (len < size) - str[len] = '\0'; - else if (size > 0) - str[size - 1] = '\0'; - - if (overflow || len >= INT_MAX) { - errno = overflow ? EOVERFLOW : ERANGE; - return -1; - } - return (int)len; -} - -static void -fmtstr(char *str, size_t *len, size_t size, const char *value, int width, - int precision, int flags) -{ - int padlen, strln; /* Amount to pad. */ - int noprecision = (precision == -1); - - if (value == NULL) /* We're forgiving. */ - value = "(null)"; - - /* If a precision was specified, don't read the string past it. */ - for (strln = 0; value[strln] != '\0' && - (noprecision || strln < precision); strln++) - continue; - - if ((padlen = width - strln) < 0) - padlen = 0; - if (flags & PRINT_F_MINUS) /* Left justify. */ - padlen = -padlen; - - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - while (*value != '\0' && (noprecision || precision-- > 0)) { - OUTCHAR(str, *len, size, *value); - value++; - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width, - int precision, int flags) -{ - UINTMAX_T uvalue; - char iconvert[MAX_CONVERT_LENGTH]; - char sign = 0; - char hexprefix = 0; - int spadlen = 0; /* Amount to space pad. */ - int zpadlen = 0; /* Amount to zero pad. */ - int pos; - int separators = (flags & PRINT_F_QUOTE); - int noprecision = (precision == -1); - - if (flags & PRINT_F_UNSIGNED) - uvalue = value; - else { - uvalue = (value >= 0) ? value : -value; - if (value < 0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - } - - pos = convert(uvalue, iconvert, sizeof(iconvert), base, - flags & PRINT_F_UP); - - if (flags & PRINT_F_NUM && uvalue != 0) { - /* - * C99 says: "The result is converted to an `alternative form'. - * For `o' conversion, it increases the precision, if and only - * if necessary, to force the first digit of the result to be a - * zero (if the value and precision are both 0, a single 0 is - * printed). For `x' (or `X') conversion, a nonzero result has - * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) - */ - switch (base) { - case 8: - if (precision <= pos) - precision = pos + 1; - break; - case 16: - hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; - break; - } - } - - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(pos); - - zpadlen = precision - pos - separators; - spadlen = width /* Minimum field width. */ - - separators /* Number of separators. */ - - MAX(precision, pos) /* Number of integer digits. */ - - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ - - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ - - if (zpadlen < 0) - zpadlen = 0; - if (spadlen < 0) - spadlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a - * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justify. */ - spadlen = -spadlen; - else if (flags & PRINT_F_ZERO && noprecision) { - zpadlen += spadlen; - spadlen = 0; - } - while (spadlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ - OUTCHAR(str, *len, size, '0'); - OUTCHAR(str, *len, size, hexprefix); - } - while (zpadlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - zpadlen--; - } - while (pos > 0) { /* The actual digits. */ - pos--; - OUTCHAR(str, *len, size, iconvert[pos]); - if (separators > 0 && pos > 0 && pos % 3 == 0) - printsep(str, len, size); - } - while (spadlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen++; - } -} - -static void -fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width, - int precision, int flags, int *overflow) -{ - LDOUBLE ufvalue; - UINTMAX_T intpart; - UINTMAX_T fracpart; - UINTMAX_T mask; - const char *infnan = NULL; - char iconvert[MAX_CONVERT_LENGTH]; - char fconvert[MAX_CONVERT_LENGTH]; - char econvert[5]; /* "e-12" (without nul-termination). */ - char esign = 0; - char sign = 0; - int leadfraczeros = 0; - int exponent = 0; - int emitpoint = 0; - int omitzeros = 0; - int omitcount = 0; - int padlen = 0; - int epos = 0; - int fpos = 0; - int ipos = 0; - int separators = (flags & PRINT_F_QUOTE); - int estyle = (flags & PRINT_F_TYPE_E); -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - struct lconv *lc = localeconv(); -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - - /* - * AIX' man page says the default is 0, but C99 and at least Solaris' - * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX - * defaults to 6. - */ - if (precision == -1) - precision = 6; - - if (fvalue < 0.0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - - if (ISNAN(fvalue)) - infnan = (flags & PRINT_F_UP) ? "NAN" : "nan"; - else if (ISINF(fvalue)) - infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; - - if (infnan != NULL) { - if (sign != 0) - iconvert[ipos++] = sign; - while (*infnan != '\0') - iconvert[ipos++] = *infnan++; - fmtstr(str, len, size, iconvert, width, ipos, flags); - return; - } - - /* "%e" (or "%E") or "%g" (or "%G") conversion. */ - if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { - if (flags & PRINT_F_TYPE_G) { - /* - * For "%g" (and "%G") conversions, the precision - * specifies the number of significant digits, which - * includes the digits in the integer part. The - * conversion will or will not be using "e-style" (like - * "%e" or "%E" conversions) depending on the precision - * and on the exponent. However, the exponent can be - * affected by rounding the converted value, so we'll - * leave this decision for later. Until then, we'll - * assume that we're going to do an "e-style" conversion - * (in order to get the exponent calculated). For - * "e-style", the precision must be decremented by one. - */ - precision--; - /* - * For "%g" (and "%G") conversions, trailing zeros are - * removed from the fractional portion of the result - * unless the "#" flag was specified. - */ - if (!(flags & PRINT_F_NUM)) - omitzeros = 1; - } - exponent = getexponent(fvalue); - estyle = 1; - } - -again: - /* - * Sorry, we only support 9, 19, or 38 digits (that is, the number of - * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value - * minus one) past the decimal point due to our conversion method. - */ - switch (sizeof(UINTMAX_T)) { - case 16: - if (precision > 38) - precision = 38; - break; - case 8: - if (precision > 19) - precision = 19; - break; - default: - if (precision > 9) - precision = 9; - break; - } - - ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; - if (estyle) /* We want exactly one integer digit. */ - ufvalue /= mypow10(exponent); - - if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { - *overflow = 1; - return; - } - - /* - * Factor of ten with the number of digits needed for the fractional - * part. For example, if the precision is 3, the mask will be 1000. - */ - mask = mypow10(precision); - /* - * We "cheat" by converting the fractional part to integer by - * multiplying by a factor of ten. - */ - if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { - /* - * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 - * (because precision = 3). Now, myround(1000 * 0.99962) will - * return 1000. So, the integer part must be incremented by one - * and the fractional part must be set to zero. - */ - intpart++; - fracpart = 0; - if (estyle && intpart == 10) { - /* - * The value was rounded up to ten, but we only want one - * integer digit if using "e-style". So, the integer - * part must be set to one and the exponent must be - * incremented by one. - */ - intpart = 1; - exponent++; - } - } - - /* - * Now that we know the real exponent, we can check whether or not to - * use "e-style" for "%g" (and "%G") conversions. If we don't need - * "e-style", the precision must be adjusted and the integer and - * fractional parts must be recalculated from the original value. - * - * C99 says: "Let P equal the precision if nonzero, 6 if the precision - * is omitted, or 1 if the precision is zero. Then, if a conversion - * with style `E' would have an exponent of X: - * - * - if P > X >= -4, the conversion is with style `f' (or `F') and - * precision P - (X + 1). - * - * - otherwise, the conversion is with style `e' (or `E') and precision - * P - 1." (7.19.6.1, 8) - * - * Note that we had decremented the precision by one. - */ - if (flags & PRINT_F_TYPE_G && estyle && - precision + 1 > exponent && exponent >= -4) { - precision -= exponent; - estyle = 0; - goto again; - } - - if (estyle) { - if (exponent < 0) { - exponent = -exponent; - esign = '-'; - } else - esign = '+'; - - /* - * Convert the exponent. The sizeof(econvert) is 5. So, the - * econvert buffer can hold e.g. "e+999" and "e-999". We don't - */ - epos = convert(exponent, econvert, 3, 10, 0); - /* - * C99 says: "The exponent always contains at least two digits, - * and only as many more digits as necessary to represent the - * exponent." (7.19.6.1, 8) - */ - if (epos == 1) - econvert[epos++] = '0'; - econvert[epos++] = esign; - econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; - } - - /* Convert the integer part and the fractional part. */ - ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); - if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ - fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); - - leadfraczeros = precision - fpos; - - if (omitzeros) { - if (fpos > 0) /* Omit trailing fractional part zeros. */ - while (omitcount < fpos && fconvert[omitcount] == '0') - omitcount++; - else { /* The fractional part is zero, omit it completely. */ - omitcount = precision; - leadfraczeros = 0; - } - precision -= omitcount; - } - - /* - * Print a decimal point if either the fractional part is non-zero - * and/or the "#" flag was specified. - */ - if (precision > 0 || flags & PRINT_F_NUM) - emitpoint = 1; - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(ipos); - - padlen = width /* Minimum field width. */ - - ipos /* Number of integer digits. */ - - epos /* Number of exponent characters. */ - - precision /* Number of fractional digits. */ - - separators /* Number of group separators. */ - - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ - - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ - - if (padlen < 0) - padlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justifty. */ - padlen = -padlen; - else if (flags & PRINT_F_ZERO && padlen > 0) { - if (sign != 0) { /* Sign. */ - OUTCHAR(str, *len, size, sign); - sign = 0; - } - while (padlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - padlen--; - } - } - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - while (ipos > 0) { /* Integer part. */ - ipos--; - OUTCHAR(str, *len, size, iconvert[ipos]); - if (separators > 0 && ipos > 0 && ipos % 3 == 0) - printsep(str, len, size); - } - if (emitpoint) { /* Decimal point. */ -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - if (lc->decimal_point != NULL && *lc->decimal_point != '\0') - OUTCHAR(str, *len, size, *lc->decimal_point); - else /* We'll always print some decimal point character. */ -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - OUTCHAR(str, *len, size, '.'); - } - while (leadfraczeros > 0) { /* Leading fractional part zeros. */ - OUTCHAR(str, *len, size, '0'); - leadfraczeros--; - } - while (fpos > omitcount) { /* The remaining fractional part. */ - fpos--; - OUTCHAR(str, *len, size, fconvert[fpos]); - } - while (epos > 0) { /* Exponent. */ - epos--; - OUTCHAR(str, *len, size, econvert[epos]); - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -printsep(char *str, size_t *len, size_t size) -{ -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - struct lconv *lc = localeconv(); - int i; - - if (lc->thousands_sep != NULL) - for (i = 0; lc->thousands_sep[i] != '\0'; i++) - OUTCHAR(str, *len, size, lc->thousands_sep[i]); - else -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - OUTCHAR(str, *len, size, ','); -} - -static int -getnumsep(int digits) -{ - int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - int strln; - struct lconv *lc = localeconv(); - - /* We support an arbitrary separator length (including zero). */ - if (lc->thousands_sep != NULL) { - for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) - continue; - separators *= strln; - } -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - return separators; -} - -static int -getexponent(LDOUBLE value) -{ - LDOUBLE tmp = (value >= 0.0) ? value : -value; - int exponent = 0; - - /* - * We check for 99 > exponent > -99 in order to work around possible - * endless loops which could happen (at least) in the second loop (at - * least) if we're called with an infinite value. However, we checked - * for infinity before calling this function using our ISINF() macro, so - * this might be somewhat paranoid. - */ - while (tmp < 1.0 && tmp > 0.0 && --exponent > -310) - tmp *= 10; - while (tmp >= 10.0 && ++exponent < 310) - tmp /= 10; - - return exponent; -} - -static int -convert(UINTMAX_T value, char *buf, size_t size, int base, int caps) -{ - const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef"; - size_t pos = 0; - - /* We return an unterminated buffer with the digits in reverse order. */ - do { - buf[pos++] = digits[value % base]; - value /= base; - } while (value != 0 && pos < size); - - return (int)pos; -} - -static UINTMAX_T -cast(LDOUBLE value) -{ - UINTMAX_T result; - - /* - * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be - * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), - * it may be increased to the nearest higher representable value for the - * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE - * value although converting the latter to UINTMAX_T would overflow. - */ - if (value >= UINTMAX_MAX) - return UINTMAX_MAX; - - result = value; - /* - * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to - * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates - * the standard). Sigh. - */ - return (result <= value) ? result : result - 1; -} - -static UINTMAX_T -myround(LDOUBLE value) -{ - UINTMAX_T intpart = cast(value); - - return ((value -= intpart) < 0.5) ? intpart : intpart + 1; -} - -static LDOUBLE -mypow10(int exponent) -{ - LDOUBLE result = 1; - - while (exponent > 0) { - result *= 10; - exponent--; - } - while (exponent < 0) { - result /= 10; - exponent++; - } - return result; -} -#endif /* !HAVE_VSNPRINTF */ - -#if !HAVE_VASPRINTF -#if NEED_MYMEMCPY -void * -mymemcpy(void *dst, void *src, size_t len) -{ - const char *from = src; - char *to = dst; - - /* No need for optimization, we use this only to replace va_copy(3). */ - while (len-- > 0) - *to++ = *from++; - return dst; -} -#endif /* NEED_MYMEMCPY */ - -int -rpl_vasprintf(char **ret, const char *format, va_list ap) -{ - size_t size; - int len; - va_list aq; - - VA_COPY(aq, ap); - len = rpl_vsnprintf(NULL, 0, format, aq); - VA_END_COPY(aq); - if (len < 0 || (*ret = malloc(size = len + 1)) == NULL) - return -1; - return rpl_vsnprintf(*ret, size, format, ap); -} -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_SNPRINTF -#if HAVE_STDARG_H -int -rpl_snprintf(char *str, size_t size, const char *format, ...) -#else -int -rpl_snprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char *str; - size_t size; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, str, char *); - VA_SHIFT(ap, size, size_t); - VA_SHIFT(ap, format, const char *); - len = rpl_vsnprintf(str, size, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_SNPRINTF */ - -#if !HAVE_ASPRINTF -#if HAVE_STDARG_H -int -rpl_asprintf(char **ret, const char *format, ...) -#else -int -rpl_asprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char **ret; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, ret, char **); - VA_SHIFT(ap, format, const char *); - len = rpl_vasprintf(ret, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_ASPRINTF */ -#else /* Dummy declaration to avoid empty translation unit warnings. */ -int main(void); -#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */ - -#if TEST_SNPRINTF -int -main(void) -{ - const char *float_fmt[] = { - /* "%E" and "%e" formats. */ -#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX - "%.16e", - "%22.16e", - "%022.16e", - "%-22.16e", - "%#+'022.16e", -#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9E|bar", - "%-123.9e", - "%123.9e", - "%+23.9e", - "%+05.8e", - "%-05.8e", - "%05.8e", - "%+5.8e", - "%-5.8e", - "% 5.8e", - "%5.8e", - "%+4.9e", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0e", - "%#10.1e", - "%10.5e", - "% 10.5e", - "%5.0e", - "%5.e", - "%#5.0e", - "%#5.e", - "%3.2e", - "%3.1e", - "%-1.5e", - "%1.5e", - "%01.3e", - "%1.e", - "%.1e", - "%#.0e", - "%+.0e", - "% .0e", - "%.0e", - "%#.e", - "%+.e", - "% .e", - "%.e", - "%4e", - "%e", - "%E", -#endif /* !OS_LINUX */ - /* "%F" and "%f" formats. */ -#if !OS_BSD && !OS_IRIX - "% '022f", - "%+'022f", - "%-'22f", - "%'22f", -#if HAVE_LONG_LONG_INT - "%.16f", - "%22.16f", - "%022.16f", - "%-22.16f", - "%#+'022.16f", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9F|bar", - "%-123.9f", - "%123.9f", - "%+23.9f", - "%+#010.0f", - "%#10.1f", - "%10.5f", - "% 10.5f", - "%+05.8f", - "%-05.8f", - "%05.8f", - "%+5.8f", - "%-5.8f", - "% 5.8f", - "%5.8f", - "%5.0f", - "%5.f", - "%#5.0f", - "%#5.f", - "%+4.9f", - "%3.2f", - "%3.1f", - "%-1.5f", - "%1.5f", - "%01.3f", - "%1.f", - "%.1f", - "%#.0f", - "%+.0f", - "% .0f", - "%.0f", - "%#.f", - "%+.f", - "% .f", - "%.f", - "%4f", - "%f", - "%F", - /* "%G" and "%g" formats. */ -#if !OS_BSD && !OS_IRIX && !OS_LINUX - "% '022g", - "%+'022g", - "%-'22g", - "%'22g", -#if HAVE_LONG_LONG_INT - "%.16g", - "%22.16g", - "%022.16g", - "%-22.16g", - "%#+'022.16g", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ - "foo|%#+0123.9G|bar", - "%-123.9g", - "%123.9g", - "%+23.9g", - "%+05.8g", - "%-05.8g", - "%05.8g", - "%+5.8g", - "%-5.8g", - "% 5.8g", - "%5.8g", - "%+4.9g", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0g", - "%#10.1g", - "%10.5g", - "% 10.5g", - "%5.0g", - "%5.g", - "%#5.0g", - "%#5.g", - "%3.2g", - "%3.1g", - "%-1.5g", - "%1.5g", - "%01.3g", - "%1.g", - "%.1g", - "%#.0g", - "%+.0g", - "% .0g", - "%.0g", - "%#.g", - "%+.g", - "% .g", - "%.g", - "%4g", - "%g", - "%G", -#endif /* !OS_LINUX */ - NULL - }; - double float_val[] = { - -4.136, - -134.52, - -5.04030201, - -3410.01234, - -999999.999999, - -913450.29876, - -913450.2, - -91345.2, - -9134.2, - -913.2, - -91.2, - -9.2, - -9.9, - 4.136, - 134.52, - 5.04030201, - 3410.01234, - 999999.999999, - 913450.29876, - 913450.2, - 91345.2, - 9134.2, - 913.2, - 91.2, - 9.2, - 9.9, - 9.96, - 9.996, - 9.9996, - 9.99996, - 9.999996, - 9.9999996, - 9.99999996, - 0.99999996, - 0.99999999, - 0.09999999, - 0.00999999, - 0.00099999, - 0.00009999, - 0.00000999, - 0.00000099, - 0.00000009, - 0.00000001, - 0.0000001, - 0.000001, - 0.00001, - 0.0001, - 0.001, - 0.01, - 0.1, - 1.0, - 1.5, - -1.5, - -1.0, - -0.1, -#if !OS_BSD /* BSD sometimes gets these wrong. */ -#ifdef INFINITY - INFINITY, - -INFINITY, -#endif /* defined(INFINITY) */ -#ifdef NAN - NAN, -#endif /* defined(NAN) */ -#endif /* !OS_BSD */ - 0 - }; - const char *long_fmt[] = { - "foo|%0123ld|bar", -#if !OS_IRIX - "% '0123ld", - "%+'0123ld", - "%-'123ld", - "%'123ld", -#endif /* !OS_IRiX */ - "%123.9ld", - "% 123.9ld", - "%+123.9ld", - "%-123.9ld", - "%0123ld", - "% 0123ld", - "%+0123ld", - "%-0123ld", - "%10.5ld", - "% 10.5ld", - "%+10.5ld", - "%-10.5ld", - "%010ld", - "% 010ld", - "%+010ld", - "%-010ld", - "%4.2ld", - "% 4.2ld", - "%+4.2ld", - "%-4.2ld", - "%04ld", - "% 04ld", - "%+04ld", - "%-04ld", - "%5.5ld", - "%+22.33ld", - "%01.3ld", - "%1.5ld", - "%-1.5ld", - "%44ld", - "%4ld", - "%4.0ld", - "%4.ld", - "%.44ld", - "%.4ld", - "%.0ld", - "%.ld", - "%ld", - NULL - }; - long int long_val[] = { -#ifdef LONG_MAX - LONG_MAX, -#endif /* LONG_MAX */ -#ifdef LONG_MIN - LONG_MIN, -#endif /* LONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *ulong_fmt[] = { - /* "%u" formats. */ - "foo|%0123lu|bar", -#if !OS_IRIX - "% '0123lu", - "%+'0123lu", - "%-'123lu", - "%'123lu", -#endif /* !OS_IRiX */ - "%123.9lu", - "% 123.9lu", - "%+123.9lu", - "%-123.9lu", - "%0123lu", - "% 0123lu", - "%+0123lu", - "%-0123lu", - "%5.5lu", - "%+22.33lu", - "%01.3lu", - "%1.5lu", - "%-1.5lu", - "%44lu", - "%lu", - /* "%o" formats. */ - "foo|%#0123lo|bar", - "%#123.9lo", - "%# 123.9lo", - "%#+123.9lo", - "%#-123.9lo", - "%#0123lo", - "%# 0123lo", - "%#+0123lo", - "%#-0123lo", - "%#5.5lo", - "%#+22.33lo", - "%#01.3lo", - "%#1.5lo", - "%#-1.5lo", - "%#44lo", - "%#lo", - "%123.9lo", - "% 123.9lo", - "%+123.9lo", - "%-123.9lo", - "%0123lo", - "% 0123lo", - "%+0123lo", - "%-0123lo", - "%5.5lo", - "%+22.33lo", - "%01.3lo", - "%1.5lo", - "%-1.5lo", - "%44lo", - "%lo", - /* "%X" and "%x" formats. */ - "foo|%#0123lX|bar", - "%#123.9lx", - "%# 123.9lx", - "%#+123.9lx", - "%#-123.9lx", - "%#0123lx", - "%# 0123lx", - "%#+0123lx", - "%#-0123lx", - "%#5.5lx", - "%#+22.33lx", - "%#01.3lx", - "%#1.5lx", - "%#-1.5lx", - "%#44lx", - "%#lx", - "%#lX", - "%123.9lx", - "% 123.9lx", - "%+123.9lx", - "%-123.9lx", - "%0123lx", - "% 0123lx", - "%+0123lx", - "%-0123lx", - "%5.5lx", - "%+22.33lx", - "%01.3lx", - "%1.5lx", - "%-1.5lx", - "%44lx", - "%lx", - "%lX", - NULL - }; - unsigned long int ulong_val[] = { -#ifdef ULONG_MAX - ULONG_MAX, -#endif /* ULONG_MAX */ - 91340, - 341, - 134, - 0203, - 1, - 0 - }; - const char *llong_fmt[] = { - "foo|%0123lld|bar", - "%123.9lld", - "% 123.9lld", - "%+123.9lld", - "%-123.9lld", - "%0123lld", - "% 0123lld", - "%+0123lld", - "%-0123lld", - "%5.5lld", - "%+22.33lld", - "%01.3lld", - "%1.5lld", - "%-1.5lld", - "%44lld", - "%lld", - NULL - }; - LLONG llong_val[] = { -#ifdef LLONG_MAX - LLONG_MAX, -#endif /* LLONG_MAX */ -#ifdef LLONG_MIN - LLONG_MIN, -#endif /* LLONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *string_fmt[] = { - "foo|%10.10s|bar", - "%-10.10s", - "%10.10s", - "%10.5s", - "%5.10s", - "%10.1s", - "%1.10s", - "%10.0s", - "%0.10s", - "%-42.5s", - "%2.s", - "%.10s", - "%.1s", - "%.0s", - "%.s", - "%4s", - "%s", - NULL - }; - const char *string_val[] = { - "Hello", - "Hello, world!", - "Sound check: One, two, three.", - "This string is a little longer than the other strings.", - "1", - "", - NULL - }; -#if !OS_SYSV /* SysV uses a different format than we do. */ - const char *pointer_fmt[] = { - "foo|%p|bar", - "%42p", - "%p", - NULL - }; - const char *pointer_val[] = { - *pointer_fmt, - *string_fmt, - *string_val, - NULL - }; -#endif /* !OS_SYSV */ - char buf1[1024], buf2[1024]; - double value, digits = 9.123456789012345678901234567890123456789; - int i, j, r1, r2, failed = 0, num = 0; - -/* - * Use -DTEST_NILS in order to also test the conversion of nil values. Might - * segfault on systems which don't support converting a NULL pointer with "%s" - * and lets some test cases fail against BSD and glibc due to bugs in their - * implementations. - */ -#ifndef TEST_NILS -#define TEST_NILS 0 -#elif TEST_NILS -#undef TEST_NILS -#define TEST_NILS 1 -#endif /* !defined(TEST_NILS) */ -#ifdef TEST -#undef TEST -#endif /* defined(TEST) */ -#define TEST(fmt, val) \ -do { \ - for (i = 0; fmt[i] != NULL; i++) \ - for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ - r1 = sprintf(buf1, fmt[i], val[j]); \ - r2 = rpl_snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ - if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ - (void)printf("Results don't match, " \ - "format string: %s\n" \ - "\t sprintf(3): [%s] (%d)\n" \ - "\tsnprintf(3): [%s] (%d)\n", \ - fmt[i], buf1, r1, buf2, r2); \ - failed++; \ - } \ - num++; \ - } \ -} while (/* CONSTCOND */ 0) - -#if HAVE_LOCALE_H - (void)setlocale(LC_ALL, ""); -#endif /* HAVE_LOCALE_H */ - - (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); - TEST(float_fmt, float_val); - TEST(long_fmt, long_val); - TEST(ulong_fmt, ulong_val); - TEST(llong_fmt, llong_val); - TEST(string_fmt, string_val); -#if !OS_SYSV /* SysV uses a different format than we do. */ - TEST(pointer_fmt, pointer_val); -#endif /* !OS_SYSV */ - (void)printf("Result: %d out of %d tests failed.\n", failed, num); - - (void)fputs("Checking how many digits we support: ", stdout); - for (i = 0; i < 100; i++) { - value = pow(10, i) * digits; - (void)sprintf(buf1, "%.1f", value); - (void)snprintf(buf2, sizeof(buf2), "%.1f", value); - if (strcmp(buf1, buf2) != 0) { - (void)printf("apparently %d.\n", i); - break; - } - } - return (failed == 0) ? 0 : 1; -} -#endif /* TEST_SNPRINTF */ - -/* -int main(void) -{ -double d = 1e+300; -static int bsz=128; -char buf[bsz]; -int v = rpl_snprintf(buf, bsz, "%g", d); -printf("%d\n",v); -printf("%s\n",buf); -return 1; -} -*/ - -/* vim: set joinspaces textwidth=80: */ diff --git a/liblwgeom/stringbuffer.c b/liblwgeom/stringbuffer.c index 75018a965..d74dd0d72 100644 --- a/liblwgeom/stringbuffer.c +++ b/liblwgeom/stringbuffer.c @@ -201,11 +201,16 @@ stringbuffer_avprintf(stringbuffer_t *s, const char *fmt, va_list ap) int len = 0; /* Length of the output */ va_list ap2; - /* Print to our buffer, using a copy of the variadic arguments, in case we need to print twice*/ + /* Make a copy of the variadic arguments, in case we need to print twice */ + /* Print to our buffer */ va_copy(ap2, ap); - len = lw_vsnprintf(s->str_end, maxlen, fmt, ap2); + len = vsnprintf(s->str_end, maxlen, fmt, ap2); va_end(ap2); + /* Propogate errors up */ + if ( len < 0 ) + return len; + /* We didn't have enough space! */ /* Either Unix vsnprint returned write length larger than our buffer */ /* or Windows vsnprintf returned an error code. */ @@ -215,7 +220,7 @@ stringbuffer_avprintf(stringbuffer_t *s, const char *fmt, va_list ap) maxlen = (s->capacity - (s->str_end - s->str_start)); /* Try to print a second time */ - len = lw_vsnprintf(s->str_end, maxlen, fmt, ap); + len = vsnprintf(s->str_end, maxlen, fmt, ap); /* Printing error? Error! */ if ( len < 0 ) return len; diff --git a/liblwgeom/vsprintf.c b/liblwgeom/vsprintf.c index 46c998266..3153ebcd5 100644 --- a/liblwgeom/vsprintf.c +++ b/liblwgeom/vsprintf.c @@ -1,72 +1,169 @@ -/********************************************************************** - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * - * Copyright (C) 2012 Paul Ramsey - * - * This is free software; you can redistribute and/or modify it under - * the terms of the GNU General Public Licence. See the COPYING file. - * - **********************************************************************/ - -#include "liblwgeom_internal.h" +/* Like vsprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. -int -lw_vasprintf (char **result, const char *format, va_list args) -{ -#if HAVE_VASPRINTF - return vasprintf(result, format, args); -#else - return rpl_vasprintf(result, format, args); +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include #endif -} -int -lw_vsnprintf(char *s, size_t n, const char *format, va_list ap) -{ -#if HAVE_VSNPRINTF - return vsnprintf(s, n, format, ap); +#include +#include +#include + +#if __STDC__ +# include #else - return rpl_vsnprintf(s, n, format, ap); +# include #endif -} +#ifdef TEST +int global_total_width; +#endif -int -lw_snprintf +/* Make sure we have a va_copy that will work on all platforms */ +#ifndef va_copy +# ifdef __va_copy +# define va_copy(d, s) __va_copy((d), (s)) +# else +# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) +# endif +#endif + +int lw_vasprintf (char **result, const char *format, va_list args); +int lw_asprintf #if __STDC__ -(char *s, size_t n, const char *format, ...) +(char **result, const char *format, ...); #else -(s, n, va_alist) -char *s; -size_t n; +(result, va_alist); +char **result; va_dcl #endif + + +static int +int_vasprintf (result, format, args) +char **result; +const char *format; +va_list *args; { - va_list args; - int done; + const char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap; -#if __STDC__ - va_start (args, format); -#else - char *format; - va_start (args); - format = va_arg (args, char *); + memcpy (&ap, args, sizeof (va_list)); + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + } + while (strchr ("hlLjtz", *p)) + ++p; + /* Should be big enough for any format specifier except %s + and floats. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + (void) va_arg (ap, int); + break; + case 'f': + { + double arg = va_arg (ap, double); + if (arg >= 1.0 || arg <= -1.0) + /* Since an ieee double can have an exponent of 307, we'll + make the buffer wide enough to cover the gross case. */ + total_width += 307; + } + break; + case 'e': + case 'E': + case 'g': + case 'G': + (void) va_arg (ap, double); + break; + case 's': + total_width += strlen (va_arg (ap, char *)); + break; + case 'p': + case 'n': + (void) va_arg (ap, char *); + break; + } + p++; + } + } +#ifdef TEST + global_total_width = total_width; #endif - done = lw_vsnprintf (s, n, format, args); - va_end (args); + *result = malloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, *args); + else + return 0; +} - return done; +int +lw_vasprintf (result, format, args) +char **result; +const char *format; +va_list args; +{ + va_list temp; + + va_copy(temp, args); + + return int_vasprintf (result, format, &temp); } int lw_asprintf #if __STDC__ -(char **s, const char *format, ...) +(char **result, const char *format, ...) #else -(s, va_alist) -char **s; +(result, va_alist) +char **result; va_dcl #endif { @@ -80,8 +177,8 @@ va_dcl va_start (args); format = va_arg (args, char *); #endif - done = lw_vasprintf (s, format, args); + done = lw_vasprintf (result, format, args); va_end (args); return done; -} \ No newline at end of file +} diff --git a/libpgcommon/lwgeom_pg.c b/libpgcommon/lwgeom_pg.c index 6366555d4..308f1d136 100644 --- a/libpgcommon/lwgeom_pg.c +++ b/libpgcommon/lwgeom_pg.c @@ -157,7 +157,7 @@ pg_error(const char *fmt, va_list ap) char errmsg[ERRMSG_MAXLEN+1]; - lw_vsnprintf (errmsg, ERRMSG_MAXLEN, fmt, ap); + vsnprintf (errmsg, ERRMSG_MAXLEN, fmt, ap); errmsg[ERRMSG_MAXLEN]='\0'; ereport(ERROR, (errmsg_internal("%s", errmsg))); diff --git a/macros/snprintf.m4 b/macros/snprintf.m4 deleted file mode 100644 index 1a844ba61..000000000 --- a/macros/snprintf.m4 +++ /dev/null @@ -1,230 +0,0 @@ -# $Id: snprintf.m4,v 1.1.1.1 2008/01/06 03:24:00 holger Exp $ - -# Copyright (c) 2008 Holger Weiss . -# -# This code may freely be used, modified and/or redistributed for any purpose. -# It would be nice if additions and fixes to this file (including trivial code -# cleanups) would be sent back in order to let me include them in the version -# available at . However, this is -# not a requirement for using or redistributing (possibly modified) versions of -# this file, nor is leaving this notice intact mandatory. - -# HW_HEADER_STDARG_H -# ------------------ -# Define HAVE_STDARG_H to 1 if is available. -AC_DEFUN([HW_HEADER_STDARG_H], -[ - AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used. - AC_CHECK_HEADERS_ONCE([stdarg.h]) -])# HW_HEADER_STDARG_H - -# HW_HEADER_VARARGS_H -# ------------------- -# Define HAVE_VARARGS_H to 1 if is available. -AC_DEFUN([HW_HEADER_VARARGS_H], -[ - AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used. - AC_CHECK_HEADERS_ONCE([varargs.h]) -])# HW_HEADER_VARARGS_H - -# HW_FUNC_VA_COPY -# --------------- -# Set $hw_cv_func_va_copy to "yes" or "no". Define HAVE_VA_COPY to 1 if -# $hw_cv_func_va_copy is set to "yes". Note that it's "unspecified whether -# va_copy and va_end are macros or identifiers declared with external linkage." -# (C99: 7.15.1, 1) Therefore, the presence of va_copy(3) cannot simply "be -# tested with #ifdef", as suggested by the Autoconf manual (5.5.1). -AC_DEFUN([HW_FUNC_VA_COPY], -[ - AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. - AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H. - AC_CACHE_CHECK([for va_copy], - [hw_cv_func_va_copy], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#if HAVE_STDARG_H - #include - #elif HAVE_VARARGS_H - #include - #endif]], - [[va_list ap, aq; va_copy(aq, ap);]])], - [hw_cv_func_va_copy=yes], - [hw_cv_func_va_copy=no], - [hw_cv_func_va_copy=no])]) - AS_IF([test "$hw_cv_func_va_copy" = yes], - [AC_DEFINE([HAVE_VA_COPY], [1], - [Define to 1 if you have the `va_copy' function or macro.])]) -])# HW_FUNC_VA_COPY - -# HW_FUNC___VA_COPY -# ----------------- -# Set $hw_cv_func___va_copy to "yes" or "no". Define HAVE___VA_COPY to 1 if -# $hw_cv_func___va_copy is set to "yes". -AC_DEFUN([HW_FUNC___VA_COPY], -[ - AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. - AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H. - AC_CACHE_CHECK([for __va_copy], - [hw_cv_func___va_copy], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#if HAVE_STDARG_H - #include - #elif HAVE_VARARGS_H - #include - #endif]], - [[va_list ap, aq; __va_copy(aq, ap);]])], - [hw_cv_func___va_copy=yes], - [hw_cv_func___va_copy=no], - [hw_cv_func___va_copy=no])]) - AS_IF([test "$hw_cv_func___va_copy" = yes], - [AC_DEFINE([HAVE___VA_COPY], [1], - [Define to 1 if you have the `__va_copy' function or macro.])]) -])# HW_FUNC___VA_COPY - -# HW_FUNC_VSNPRINTF -# ----------------- -# Set $hw_cv_func_vsnprintf and $hw_cv_func_vsnprintf_c99 to "yes" or "no", -# respectively. Define HAVE_VSNPRINTF to 1 only if $hw_cv_func_vsnprintf_c99 -# is set to "yes". Otherwise, define vsnprintf to rpl_vsnprintf and make sure -# the replacement function will be built. -AC_DEFUN([HW_FUNC_VSNPRINTF], -[ - AC_PREREQ([2.60])dnl 2.59 should work if some AC_TYPE_* macros are replaced. - AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. - AC_CHECK_FUNC([vsnprintf], - [hw_cv_func_vsnprintf=yes], - [hw_cv_func_vsnprintf=no]) - AS_IF([test "$hw_cv_func_vsnprintf" = yes], - [AC_CACHE_CHECK([whether vsnprintf is C99 compliant], - [hw_cv_func_vsnprintf_c99], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#if HAVE_STDARG_H - #include - #endif - #include - static int testprintf(char *buf, size_t size, const char *format, ...) - { - int result; - va_list ap; - va_start(ap, format); - result = vsnprintf(buf, size, format, ap); - va_end(ap); - return result; - }]], - [[char buf[43]; - if (testprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 || - testprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 || - buf[0] != 'T' || buf[3] != '\0') - return 1;]])], - [hw_cv_func_vsnprintf_c99=yes], - [hw_cv_func_vsnprintf_c99=no], - [hw_cv_func_vsnprintf_c99=no])])], - [hw_cv_func_snprintf_c99=no]) - AS_IF([test "$hw_cv_func_vsnprintf_c99" = yes], - [AC_DEFINE([HAVE_VSNPRINTF], [1], - [Define to 1 if you have a C99 compliant `vsnprintf' function.])], - [AC_DEFINE([vsnprintf], [rpl_vsnprintf], - [Define to rpl_vsnprintf if the replacement function should be used.]) - AC_CHECK_HEADERS([inttypes.h locale.h stddef.h stdint.h]) - AC_CHECK_MEMBERS([struct lconv.decimal_point, struct lconv.thousands_sep], - [], [], [#include ]) - AC_TYPE_LONG_DOUBLE - AC_TYPE_LONG_LONG_INT - AC_TYPE_UNSIGNED_LONG_LONG_INT - AC_TYPE_SIZE_T - AC_TYPE_INTMAX_T - AC_TYPE_UINTMAX_T - AC_TYPE_UINTPTR_T - AC_CHECK_TYPES([ptrdiff_t]) - AC_CHECK_FUNCS([localeconv]) - _HW_FUNC_XPRINTF_REPLACE]) -])# HW_FUNC_VSNPRINTF - -# HW_FUNC_SNPRINTF -# ---------------- -# Set $hw_cv_func_snprintf and $hw_cv_func_snprintf_c99 to "yes" or "no", -# respectively. Define HAVE_SNPRINTF to 1 only if $hw_cv_func_snprintf_c99 -# is set to "yes". Otherwise, define snprintf to rpl_snprintf and make sure -# the replacement function will be built. -AC_DEFUN([HW_FUNC_SNPRINTF], -[ - AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our snprintf(3) calls vsnprintf(3). - AC_CHECK_FUNC([snprintf], - [hw_cv_func_snprintf=yes], - [hw_cv_func_snprintf=no]) - AS_IF([test "$hw_cv_func_snprintf" = yes], - [AC_CACHE_CHECK([whether snprintf is C99 compliant], - [hw_cv_func_snprintf_c99], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[#include ]], - [[char buf[43]; - if (snprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 || - snprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 || - buf[0] != 'T' || buf[3] != '\0') - return 1;]])], - [hw_cv_func_snprintf_c99=yes], - [hw_cv_func_snprintf_c99=no], - [hw_cv_func_snprintf_c99=no])])], - [hw_cv_func_snprintf_c99=no]) - AS_IF([test "$hw_cv_func_snprintf_c99" = yes], - [AC_DEFINE([HAVE_SNPRINTF], [1], - [Define to 1 if you have a C99 compliant `snprintf' function.])], - [AC_DEFINE([snprintf], [rpl_snprintf], - [Define to rpl_snprintf if the replacement function should be used.]) - _HW_FUNC_XPRINTF_REPLACE]) -])# HW_FUNC_SNPRINTF - -# HW_FUNC_VASPRINTF -# ----------------- -# Set $hw_cv_func_vasprintf to "yes" or "no". Define HAVE_VASPRINTF to 1 if -# $hw_cv_func_vasprintf is set to "yes". Otherwise, define vasprintf to -# rpl_vasprintf and make sure the replacement function will be built. -AC_DEFUN([HW_FUNC_VASPRINTF], -[ - AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our vasprintf(3) calls vsnprintf(3). - AC_CHECK_FUNCS([vasprintf], - [hw_cv_func_vasprintf=yes], - [hw_cv_func_vasprintf=no]) - AS_IF([test "$hw_cv_func_vasprintf" = no], - [AC_DEFINE([vasprintf], [rpl_vasprintf], - [Define to rpl_vasprintf if the replacement function should be used.]) - AC_CHECK_HEADERS([stdlib.h]) - HW_FUNC_VA_COPY - AS_IF([test "$hw_cv_func_va_copy" = no], - [HW_FUNC___VA_COPY]) - _HW_FUNC_XPRINTF_REPLACE]) -])# HW_FUNC_VASPRINTF - -# HW_FUNC_ASPRINTF -# ---------------- -# Set $hw_cv_func_asprintf to "yes" or "no". Define HAVE_ASPRINTF to 1 if -# $hw_cv_func_asprintf is set to "yes". Otherwise, define asprintf to -# rpl_asprintf and make sure the replacement function will be built. -AC_DEFUN([HW_FUNC_ASPRINTF], -[ - AC_REQUIRE([HW_FUNC_VASPRINTF])dnl Our asprintf(3) calls vasprintf(3). - AC_CHECK_FUNCS([asprintf], - [hw_cv_func_asprintf=yes], - [hw_cv_func_asprintf=no]) - AS_IF([test "$hw_cv_func_asprintf" = no], - [AC_DEFINE([asprintf], [rpl_asprintf], - [Define to rpl_asprintf if the replacement function should be used.]) - _HW_FUNC_XPRINTF_REPLACE]) -])# HW_FUNC_ASPRINTF - -# _HW_FUNC_XPRINTF_REPLACE -# ------------------------ -# Arrange for building snprintf.c. Must be called if one or more of the -# functions provided by snprintf.c are needed. -AC_DEFUN([_HW_FUNC_XPRINTF_REPLACE], -[ - AS_IF([test "x$_hw_cv_func_xprintf_replace_done" != xyes], - [AC_C_CONST - HW_HEADER_STDARG_H - AC_LIBOBJ([snprintf]) - _hw_cv_func_xprintf_replace_done=yes]) -])# _HW_FUNC_XPRINTF_REPLACE - -dnl vim: set joinspaces textwidth=80: diff --git a/postgis_config.h.in b/postgis_config.h.in index eb20078a1..edf1d08d1 100644 --- a/postgis_config.h.in +++ b/postgis_config.h.in @@ -17,34 +17,14 @@ the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#undef HAVE_DCGETTEXT + /* Define for some functions we are interested in */ -#undef HAVE_FSEEKO -#undef HAVE_VSNPRINTF -#undef HAVE_SNPRINTF #undef HAVE_VASPRINTF #undef HAVE_ASPRINTF -#undef HAVE_STDARG_H -#undef HAVE_STDDEF_H -#undef HAVE_STDINT_H -#undef HAVE_STDLIB_H -#undef HAVE_INTTYPES_H -#undef HAVE_LOCALE_H -#undef HAVE_LOCALECONV -#undef HAVE_LCONV_DECIMAL_POINT -#undef HAVE_LCONV_THOUSANDS_SEP -#undef HAVE_LONG_DOUBLE -#undef HAVE_LONG_LONG_INT -#undef HAVE_UNSIGNED_LONG_LONG_INT -#undef HAVE_INTMAX_T -#undef HAVE_UINTMAX_T -#undef HAVE_UINTPTR_T -#undef HAVE_PTRDIFF_T -#undef HAVE_VA_COPY -#undef HAVE___VA_COPY - -/* Define if the GNU dcgettext() function is already present or - preinstalled. */ -#undef HAVE_DCGETTEXT +#undef HAVE_FSEEKO /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 2f88eb723..f72964764 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -10194,7 +10194,7 @@ rt_pg_error(const char *fmt, va_list ap) char errmsg[ERRMSG_MAXLEN+1]; - lw_vsnprintf (errmsg, ERRMSG_MAXLEN, fmt, ap); + vsnprintf (errmsg, ERRMSG_MAXLEN, fmt, ap); errmsg[ERRMSG_MAXLEN]='\0'; ereport(ERROR, (errmsg_internal("%s", errmsg))); -- 2.40.0