X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvasnprintf.c;h=e11f1e998306151821a900287727e9832fcd55ab;hb=5d0b385594bc914e6233988bfb6bc1b92a2184b5;hp=aff0b172ed817eae73768c5af89ffc7240320e03;hpb=c930ba2964163bc0cf5e1a9447989033aefb21f7;p=gnulib.git diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index aff0b172e..e11f1e998 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -34,12 +34,16 @@ # include "vasnprintf.h" #endif +#include /* localeconv() */ #include /* snprintf(), sprintf() */ #include /* abort(), malloc(), realloc(), free() */ #include /* memcpy(), strlen() */ #include /* errno */ #include /* CHAR_BIT */ #include /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#if HAVE_NL_LANGINFO +# include +#endif #if WIDE_CHAR_VERSION # include "wprintf-parse.h" #else @@ -50,12 +54,17 @@ #include "xsize.h" #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL +# include # include "isnan.h" -# include "isnanl.h" -# if HAVE_LONG_DOUBLE -# include "printf-frexp.h" -# include "printf-frexpl.h" -# endif +# include "printf-frexp.h" +# include "isnanl-nolibm.h" +# include "printf-frexpl.h" +# include "fpucw.h" +#endif + +/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ +#ifndef EOVERFLOW +# define EOVERFLOW E2BIG #endif #if HAVE_WCHAR_T @@ -109,6 +118,37 @@ local_wcslen (const wchar_t *s) # else /* Unix. */ # define SNPRINTF snprintf + /* Here we need to call the native snprintf, not rpl_snprintf. */ +# undef snprintf +# endif +#endif +/* Here we need to call the native sprintf, not rpl_sprintf. */ +#undef sprintf + +#if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL +/* Determine the decimal-point character according to the current locale. */ +# ifndef decimal_point_char_defined +# define decimal_point_char_defined 1 +static char +decimal_point_char () +{ + const char *point; + /* Determine it in a multithread-safe way. We know nl_langinfo is + multithread-safe on glibc systems, but is not required to be multithread- + safe by POSIX. sprintf(), however, is multithread-safe. localeconv() + is rarely multithread-safe. */ +# if HAVE_NL_LANGINFO && __GLIBC__ + point = nl_langinfo (RADIXCHAR); +# elif 1 + char pointbuf[5]; + sprintf (pointbuf, "%#.0f", 1.0); + point = &pointbuf[1]; +# else + point = localeconv () -> decimal_point; +# endif + /* The decimal point is always a single byte: either '.' or ','. */ + return (point[0] != '\0' ? point[0] : '.'); +} # endif #endif @@ -344,7 +384,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } /* Allocate a temporary buffer of sufficient size. */ -# if HAVE_LONG_DOUBLE if (type == TYPE_LONGDOUBLE) tmp_length = (unsigned int) ((LDBL_DIG + 1) @@ -352,7 +391,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar ) + 1; /* turn floor into ceil */ else -# endif tmp_length = (unsigned int) ((DBL_DIG + 1) * 0.831 /* decimal -> hexadecimal */ @@ -385,7 +423,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar pad_ptr = NULL; p = tmp; -# if HAVE_LONG_DOUBLE if (type == TYPE_LONGDOUBLE) { long double arg = a.arg[dp->arg_index].a.a_longdouble; @@ -404,23 +441,15 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar else { int sign = 0; + DECL_LONG_DOUBLE_ROUNDING + + BEGIN_LONG_DOUBLE_ROUNDING (); - if (arg < 0.0L) + if (signbit (arg)) /* arg < 0.0L or negative zero */ { sign = -1; arg = -arg; } - else if (arg == 0.0L) - { - /* Distinguish 0.0L and -0.0L. */ - static long double plus_zero = 0.0L; - long double arg_mem = arg; - if (memcmp (&plus_zero, &arg_mem, sizeof (long double)) != 0) - { - sign = -1; - arg = -arg; - } - } if (sign < 0) *p++ = '-'; @@ -492,7 +521,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if ((flags & FLAG_ALT) || mantissa > 0.0L || precision > 0) { - *p++ = '.'; + *p++ = decimal_point_char (); /* This loop terminates because we assume that FLT_RADIX is a power of 2. */ while (mantissa > 0.0L) @@ -515,22 +544,23 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } *p++ = dp->conversion - 'A' + 'P'; -# if WIDE_CHAR_VERSION +# if WIDE_CHAR_VERSION { static const wchar_t decimal_format[] = { '%', '+', 'd', '\0' }; SNPRINTF (p, 6 + 1, decimal_format, exponent); } -# else +# else sprintf (p, "%+d", exponent); -# endif +# endif while (*p != '\0') p++; } + + END_LONG_DOUBLE_ROUNDING (); } } else -# endif { double arg = a.arg[dp->arg_index].a.a_double; @@ -549,22 +579,11 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { int sign = 0; - if (arg < 0.0) + if (signbit (arg)) /* arg < 0.0 or negative zero */ { sign = -1; arg = -arg; } - else if (arg == 0.0) - { - /* Distinguish 0.0 and -0.0. */ - static double plus_zero = 0.0; - double arg_mem = arg; - if (memcmp (&plus_zero, &arg_mem, sizeof (double)) != 0) - { - sign = -1; - arg = -arg; - } - } if (sign < 0) *p++ = '-'; @@ -636,7 +655,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if ((flags & FLAG_ALT) || mantissa > 0.0 || precision > 0) { - *p++ = '.'; + *p++ = decimal_point_char (); /* This loop terminates because we assume that FLT_RADIX is a power of 2. */ while (mantissa > 0.0) @@ -885,7 +904,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar break; case 'f': case 'F': -# if HAVE_LONG_DOUBLE if (type == TYPE_LONGDOUBLE) tmp_length = (unsigned int) (LDBL_MAX_EXP @@ -895,7 +913,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar + 1 /* turn floor into ceil */ + 10; /* sign, decimal point etc. */ else -# endif tmp_length = (unsigned int) (DBL_MAX_EXP * 0.30103 /* binary -> decimal */ @@ -913,7 +930,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar break; case 'a': case 'A': -# if HAVE_LONG_DOUBLE if (type == TYPE_LONGDOUBLE) tmp_length = (unsigned int) (LDBL_DIG @@ -921,7 +937,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar ) + 1; /* turn floor into ceil */ else -# endif tmp_length = (unsigned int) (DBL_DIG * 0.831 /* decimal -> hexadecimal */ @@ -1040,15 +1055,18 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar #endif *p++ = 'l'; break; -#if HAVE_LONG_DOUBLE case TYPE_LONGDOUBLE: *p++ = 'L'; break; -#endif default: break; } - *p = dp->conversion; +#if NEED_PRINTF_DIRECTIVE_F + if (dp->conversion == 'F') + *p = 'f'; + else +#endif + *p = dp->conversion; #if USE_SNPRINTF p[1] = '%'; p[2] = 'n'; @@ -1090,6 +1108,9 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar retcount = 0; #if USE_SNPRINTF + /* SNPRINTF can fail if maxlen > INT_MAX. */ + if (maxlen > INT_MAX) + goto overflow; # define SNPRINTF_BUF(arg) \ switch (prefix_count) \ { \ @@ -1198,14 +1219,12 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar SNPRINTF_BUF (arg); } break; -#if 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; @@ -1334,6 +1353,18 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar free (tmp); #endif +#if NEED_PRINTF_DIRECTIVE_F + if (dp->conversion == 'F') + { + /* Convert the %f result to upper case for %F. */ + CHAR_T *rp = result + length; + size_t rc; + for (rc = count; rc > 0; rc--, rp++) + if (*rp >= 'a' && *rp <= 'z') + *rp = *rp - 'a' + 'A'; + } +#endif + length += count; break; } @@ -1365,6 +1396,15 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar not have this limitation. */ return result; + overflow: + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EOVERFLOW; + return NULL; + out_of_memory: if (!(result == resultbuf || result == NULL)) free (result);