/* floating point to accurate string
- Copyright (C) 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2011 Free Software Foundation, Inc.
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
/* Written by Paul Eggert. */
+/* This code can misbehave on some buggy or older platforms, when
+ operating on arguments on floating types other than 'double', or
+ when given unusual combinations of options. Gnulib's
+ snprintf-posix module works around many of these problems.
+
+ This code relies on sprintf, strtod, etc. operating accurately;
+ otherwise, the resulting strings could be inaccurate or too long. */
+
+#include <config.h>
+
#include "ftoastr.h"
#include "intprops.h"
# define FLOAT_MIN LDBL_MIN
# define FLOAT_PREC_BOUND _GL_LDBL_PREC_BOUND
# define FTOASTR ldtoastr
-# define STRTOF strtold
+# if HAVE_C99_STRTOLD
+# define STRTOF strtold
+# endif
#elif LENGTH == 2
# define FLOAT double
# define FLOAT_DIG DBL_DIG
# define FLOAT_MIN DBL_MIN
# define FLOAT_PREC_BOUND _GL_DBL_PREC_BOUND
# define FTOASTR dtoastr
-# define STRTOF strtod
#else
# define LENGTH 1
# define FLOAT float
# define FLOAT_MIN FLT_MIN
# define FLOAT_PREC_BOUND _GL_FLT_PREC_BOUND
# define FTOASTR ftoastr
-# define STRTOF strtof
+# if HAVE_STRTOF
+# define STRTOF strtof
+# endif
#endif
/* On pre-C99 hosts, approximate strtof and strtold with strtod. This
may generate one or two extra digits, but that's better than not
- working at all. Assume that strtof works if strtold does. */
-#if LENGTH != 2 && ! HAVE_C99_STRTOLD
-# undef STRTOF
+ working at all. */
+#ifndef STRTOF
# define STRTOF strtod
#endif
+/* On hosts where it's not known that snprintf works, use sprintf to
+ implement the subset needed here. Typically BUFSIZE is big enough
+ and there's little or no performance hit. */
+#if ! GNULIB_SNPRINTF
+# undef snprintf
+# define snprintf ftoastr_snprintf
+static int
+ftoastr_snprintf (char *buf, size_t bufsize, char const *format,
+ int width, int prec, FLOAT x)
+{
+ char width_0_buffer[LENGTH == 1 ? FLT_BUFSIZE_BOUND
+ : LENGTH == 2 ? DBL_BUFSIZE_BOUND
+ : LDBL_BUFSIZE_BOUND];
+ int n = width;
+ if (bufsize < sizeof width_0_buffer)
+ {
+ n = sprintf (width_0_buffer, format, 0, prec, x);
+ if (n < 0)
+ return n;
+ if (n < width)
+ n = width;
+ }
+ if (n < bufsize)
+ n = sprintf (buf, format, width, prec, x);
+ return n;
+}
+#endif
+
int
FTOASTR (char *buf, size_t bufsize, int flags, int width, FLOAT x)
{