X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fftoastr.c;h=ebeed3e1347b454779a9a3f39ab54c251d23a977;hb=82781cc8ba8aa1831f3fce91ce14b8538f5319f0;hp=ddc525168abb6867900e1b730d33feb60b799e13;hpb=32a4812677fe70153e37bc19925aab9bac6a283d;p=gnulib.git diff --git a/lib/ftoastr.c b/lib/ftoastr.c index ddc525168..ebeed3e13 100644 --- a/lib/ftoastr.c +++ b/lib/ftoastr.c @@ -1,6 +1,6 @@ /* floating point to accurate string - Copyright (C) 2010 Free Software Foundation, Inc. + Copyright (C) 2010-2012 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 @@ -17,9 +17,18 @@ /* 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 + #include "ftoastr.h" -#include "intprops.h" #include #include #include @@ -30,14 +39,15 @@ # 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 @@ -45,17 +55,46 @@ # 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) { @@ -64,7 +103,8 @@ FTOASTR (char *buf, size_t bufsize, int flags, int width, FLOAT x) Florian Loitsch, Printing floating-point numbers quickly and accurately with integers. ACM SIGPLAN notices 46, 6 (June 2010), 233-243 - . */ + ; also see the + 2010-03-21 draft . */ char format[sizeof "%-+ 0*.*Lg"]; FLOAT abs_x = x < 0 ? -x : x;