|
32 | 32 |
|
33 | 33 | #include"c.h"
|
34 | 34 |
|
| 35 | +#include<ctype.h> |
35 | 36 | #include<limits.h>
|
| 37 | +#include<math.h> |
36 | 38 | #ifndefWIN32
|
37 | 39 | #include<sys/ioctl.h>
|
38 | 40 | #endif
|
@@ -932,27 +934,80 @@ fmtfloat(double value, char type, int forcesign, int leftjust,
|
932 | 934 | PrintfTarget*target)
|
933 | 935 | {
|
934 | 936 | intsignvalue=0;
|
| 937 | +intprec; |
935 | 938 | intvallen;
|
936 | 939 | charfmt[32];
|
937 |
| -charconvert[512]; |
938 |
| -intpadlen=0;/* amount to pad */ |
| 940 | +charconvert[1024]; |
| 941 | +intzeropadlen=0;/* amount to pad with zeroes */ |
| 942 | +intpadlen=0;/* amount to pad with spaces */ |
| 943 | + |
| 944 | +/* |
| 945 | + * We rely on the regular C library's sprintf to do the basic conversion, |
| 946 | + * then handle padding considerations here. |
| 947 | + * |
| 948 | + * The dynamic range of "double" is about 1E+-308 for IEEE math, and not |
| 949 | + * too wildly more than that with other hardware. In "f" format, sprintf |
| 950 | + * could therefore generate at most 308 characters to the left of the |
| 951 | + * decimal point; while we need to allow the precision to get as high as |
| 952 | + * 308+17 to ensure that we don't truncate significant digits from very |
| 953 | + * small values. To handle both these extremes, we use a buffer of 1024 |
| 954 | + * bytes and limit requested precision to 350 digits; this should prevent |
| 955 | + * buffer overrun even with non-IEEE math. If the original precision |
| 956 | + * request was more than 350, separately pad with zeroes. |
| 957 | + */ |
| 958 | +if (precision<0)/* cover possible overflow of "accum" */ |
| 959 | +precision=0; |
| 960 | +prec=Min(precision,350); |
939 | 961 |
|
940 |
| -/* we rely on regular C library's sprintf to do the basic conversion */ |
941 | 962 | if (pointflag)
|
942 |
| -sprintf(fmt,"%%.%d%c",precision,type); |
| 963 | +{ |
| 964 | +sprintf(fmt,"%%.%d%c",prec,type); |
| 965 | +zeropadlen=precision-prec; |
| 966 | +} |
943 | 967 | else
|
944 | 968 | sprintf(fmt,"%%%c",type);
|
945 | 969 |
|
946 |
| -if (adjust_sign((value<0),forcesign,&signvalue)) |
| 970 | +if (!isnan(value)&&adjust_sign((value<0),forcesign,&signvalue)) |
947 | 971 | value=-value;
|
948 | 972 |
|
949 | 973 | vallen=sprintf(convert,fmt,value);
|
950 | 974 |
|
951 |
| -adjust_padlen(minlen,vallen,leftjust,&padlen); |
| 975 | +/* If it's infinity or NaN, forget about doing any zero-padding */ |
| 976 | +if (zeropadlen>0&& !isdigit((unsignedchar)convert[vallen-1])) |
| 977 | +zeropadlen=0; |
| 978 | + |
| 979 | +adjust_padlen(minlen,vallen+zeropadlen,leftjust,&padlen); |
952 | 980 |
|
953 | 981 | leading_pad(zpad,&signvalue,&padlen,target);
|
954 | 982 |
|
955 |
| -dostr(convert,vallen,target); |
| 983 | +if (zeropadlen>0) |
| 984 | +{ |
| 985 | +/* If 'e' or 'E' format, inject zeroes before the exponent */ |
| 986 | +char*epos=strrchr(convert,'e'); |
| 987 | + |
| 988 | +if (!epos) |
| 989 | +epos=strrchr(convert,'E'); |
| 990 | +if (epos) |
| 991 | +{ |
| 992 | +/* pad after exponent */ |
| 993 | +dostr(convert,epos-convert,target); |
| 994 | +while (zeropadlen-->0) |
| 995 | +dopr_outch('0',target); |
| 996 | +dostr(epos,vallen- (epos-convert),target); |
| 997 | +} |
| 998 | +else |
| 999 | +{ |
| 1000 | +/* no exponent, pad after the digits */ |
| 1001 | +dostr(convert,vallen,target); |
| 1002 | +while (zeropadlen-->0) |
| 1003 | +dopr_outch('0',target); |
| 1004 | +} |
| 1005 | +} |
| 1006 | +else |
| 1007 | +{ |
| 1008 | +/* no zero padding, just emit the number as-is */ |
| 1009 | +dostr(convert,vallen,target); |
| 1010 | +} |
956 | 1011 |
|
957 | 1012 | trailing_pad(&padlen,target);
|
958 | 1013 | }
|
|