X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fftoastr.c;h=7780d00860c2df1be2bd946c067fbd49fb8f49c8;hb=7ef6c64e210ac0979d7e8ac69bc5b5208c2405ab;hp=25e0705e42d961276e69b4165f958e1b36611bb9;hpb=0c7219c6481808cbf45495502d55bac81f5c1112;p=gnulib.git diff --git a/lib/ftoastr.c b/lib/ftoastr.c index 25e0705e4..7780d0086 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-2014 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,7 +55,44 @@ # 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. */ +#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 @@ -56,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;