X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvasnprintf.c;h=06bf03421095f60a65c738c9d16242341f04fb55;hb=9f88c0b0e0cfa8a9c25f1db4f58b837c7b891575;hp=8d0f516768b5dfbc22dbfaa01141af8bac3df65d;hpb=c114350b101f758aadbd236ae9ea4cb596b622fb;p=gnulib.git diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 8d0f51676..06bf03421 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -41,6 +41,9 @@ #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 @@ -51,12 +54,12 @@ #include "xsize.h" #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL +# include "float+.h" # 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. */ @@ -122,6 +125,33 @@ local_wcslen (const wchar_t *s) /* 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 + CHAR_T * VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) { @@ -184,10 +214,6 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { result = resultbuf; allocated = *lengthp; - /* POSIX says that snprintf() fails with EOVERFLOW when the specified - buffer size is larger than INT_MAX. Let's do the same here. */ - if (allocated > INT_MAX) - goto overflow; } else { @@ -358,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) @@ -366,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 */ @@ -399,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; @@ -418,6 +441,9 @@ 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) { @@ -428,10 +454,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { /* Distinguish 0.0L and -0.0L. */ static long double plus_zero = 0.0L; - long double arg_mem; - memset (&arg_mem, 0, sizeof (long double)); - arg_mem = arg; - if (memcmp (&plus_zero, &arg_mem, sizeof (long double)) != 0) + long double arg_mem = arg; + if (memcmp (&plus_zero, &arg_mem, SIZEOF_LDBL) != 0) { sign = -1; arg = -arg; @@ -508,11 +532,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if ((flags & FLAG_ALT) || mantissa > 0.0L || precision > 0) { - const char *point = - localeconv () -> decimal_point; - /* The decimal point is always a single byte: - either '.' or ','. */ - *p++ = (point[0] != '\0' ? point[0] : '.'); + *p++ = decimal_point_char (); /* This loop terminates because we assume that FLT_RADIX is a power of 2. */ while (mantissa > 0.0L) @@ -535,22 +555,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; @@ -578,10 +599,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { /* Distinguish 0.0 and -0.0. */ static double plus_zero = 0.0; - double arg_mem; - memset (&arg_mem, 0, sizeof (double)); - arg_mem = arg; - if (memcmp (&plus_zero, &arg_mem, sizeof (double)) != 0) + double arg_mem = arg; + if (memcmp (&plus_zero, &arg_mem, SIZEOF_DBL) != 0) { sign = -1; arg = -arg; @@ -658,11 +677,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if ((flags & FLAG_ALT) || mantissa > 0.0 || precision > 0) { - const char *point = - localeconv () -> decimal_point; - /* The decimal point is always a single byte: - either '.' or ','. */ - *p++ = (point[0] != '\0' ? point[0] : '.'); + *p++ = decimal_point_char (); /* This loop terminates because we assume that FLT_RADIX is a power of 2. */ while (mantissa > 0.0) @@ -911,7 +926,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 @@ -921,7 +935,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 */ @@ -939,7 +952,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 @@ -947,7 +959,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 */ @@ -1066,11 +1077,9 @@ 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; } @@ -1227,14 +1236,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;