|
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
|
@@ -906,27 +908,80 @@ fmtfloat(double value, char type, int forcesign, int leftjust,
|
906 | 908 | PrintfTarget*target)
|
907 | 909 | {
|
908 | 910 | intsignvalue=0;
|
| 911 | +intprec; |
909 | 912 | intvallen;
|
910 | 913 | charfmt[32];
|
911 |
| -charconvert[512]; |
912 |
| -intpadlen=0;/* amount to pad */ |
| 914 | +charconvert[1024]; |
| 915 | +intzeropadlen=0;/* amount to pad with zeroes */ |
| 916 | +intpadlen=0;/* amount to pad with spaces */ |
| 917 | + |
| 918 | +/* |
| 919 | + * We rely on the regular C library's sprintf to do the basic conversion, |
| 920 | + * then handle padding considerations here. |
| 921 | + * |
| 922 | + * The dynamic range of "double" is about 1E+-308 for IEEE math, and not |
| 923 | + * too wildly more than that with other hardware. In "f" format, sprintf |
| 924 | + * could therefore generate at most 308 characters to the left of the |
| 925 | + * decimal point; while we need to allow the precision to get as high as |
| 926 | + * 308+17 to ensure that we don't truncate significant digits from very |
| 927 | + * small values. To handle both these extremes, we use a buffer of 1024 |
| 928 | + * bytes and limit requested precision to 350 digits; this should prevent |
| 929 | + * buffer overrun even with non-IEEE math. If the original precision |
| 930 | + * request was more than 350, separately pad with zeroes. |
| 931 | + */ |
| 932 | +if (precision<0)/* cover possible overflow of "accum" */ |
| 933 | +precision=0; |
| 934 | +prec=Min(precision,350); |
913 | 935 |
|
914 |
| -/* we rely on regular C library's sprintf to do the basic conversion */ |
915 | 936 | if (pointflag)
|
916 |
| -sprintf(fmt,"%%.%d%c",precision,type); |
| 937 | +{ |
| 938 | +sprintf(fmt,"%%.%d%c",prec,type); |
| 939 | +zeropadlen=precision-prec; |
| 940 | +} |
917 | 941 | else
|
918 | 942 | sprintf(fmt,"%%%c",type);
|
919 | 943 |
|
920 |
| -if (adjust_sign((value<0),forcesign,&signvalue)) |
| 944 | +if (!isnan(value)&&adjust_sign((value<0),forcesign,&signvalue)) |
921 | 945 | value=-value;
|
922 | 946 |
|
923 | 947 | vallen=sprintf(convert,fmt,value);
|
924 | 948 |
|
925 |
| -adjust_padlen(minlen,vallen,leftjust,&padlen); |
| 949 | +/* If it's infinity or NaN, forget about doing any zero-padding */ |
| 950 | +if (zeropadlen>0&& !isdigit((unsignedchar)convert[vallen-1])) |
| 951 | +zeropadlen=0; |
| 952 | + |
| 953 | +adjust_padlen(minlen,vallen+zeropadlen,leftjust,&padlen); |
926 | 954 |
|
927 | 955 | leading_pad(zpad,&signvalue,&padlen,target);
|
928 | 956 |
|
929 |
| -dostr(convert,vallen,target); |
| 957 | +if (zeropadlen>0) |
| 958 | +{ |
| 959 | +/* If 'e' or 'E' format, inject zeroes before the exponent */ |
| 960 | +char*epos=strrchr(convert,'e'); |
| 961 | + |
| 962 | +if (!epos) |
| 963 | +epos=strrchr(convert,'E'); |
| 964 | +if (epos) |
| 965 | +{ |
| 966 | +/* pad after exponent */ |
| 967 | +dostr(convert,epos-convert,target); |
| 968 | +while (zeropadlen-->0) |
| 969 | +dopr_outch('0',target); |
| 970 | +dostr(epos,vallen- (epos-convert),target); |
| 971 | +} |
| 972 | +else |
| 973 | +{ |
| 974 | +/* no exponent, pad after the digits */ |
| 975 | +dostr(convert,vallen,target); |
| 976 | +while (zeropadlen-->0) |
| 977 | +dopr_outch('0',target); |
| 978 | +} |
| 979 | +} |
| 980 | +else |
| 981 | +{ |
| 982 | +/* no zero padding, just emit the number as-is */ |
| 983 | +dostr(convert,vallen,target); |
| 984 | +} |
930 | 985 |
|
931 | 986 | trailing_pad(&padlen,target);
|
932 | 987 | }
|
|