[Bug #6] sprintf() of %f on Windows(MSVCRT)

e$B%A%1%C%He(B #6 e$B$,99?7$5$l$^$7$?!#e(B (by _ wanabe)

e$B%U%!%$%ke(B sprintf.patch e$BDI2Ce(B

missing/vsnprintf.c e$B$rMxMQ$9$k$h$&$J%Q%C%A$r=q$-$^$7$?!#e(B
vsnprintf.c e$BCf$Ne(B vsnprintf
e$B$r30$K=P$9$d$jJ}$,$“$^$j$&$^$/$J$$$h$&$K;W$&$N$Ge(B
e$B2?$+$&$^$$J}K!$r$4B8CN$NJ}$O65$($F$$$?$@$1$k$H$”$j$,$?$$$G$9!#e(B

http://redmine.ruby-lang.org/issues/show/6

e$B$J$+$@$G$9!#e(B

At Sun, 26 Oct 2008 10:35:17 +0900,
_ wanabe wrote in [ruby-dev:36932]:

vsnprintf.c e$BCf$Ne(B vsnprintf e$B$r30$K=P$9$d$jJ}$,$"$^$j$&$^$/$J$$$h$&$K;W$&$N$Ge(B
e$B2?$+$&$^$$J}K!$r$4B8CN$NJ}$O65$($F$$$?$@$1$k$H$"$j$,$?$$$G$9!#e(B

win32/Makefile.sube$B$Ne(BHAVE_VSNPRINTFe$B$r>C$;$Pe(Bmissinge$B$N$[$&$r;H$&$he(B
e$B$&$K$J$k$O$:$G$9!#e(B

e$B$A$J$_$K!"e(Bmissing/vsnprintf.ce$B$X$N=$@5$O$I$&$$$&$b$N$G$7$g$&$+!#e(B

e$B$J$+$@$G$9!#e(B

At Sun, 26 Oct 2008 20:42:54 +0900,
wanabe wrote in [ruby-dev:36935]:

win32/Makefile.sube$B$Ne(BHAVE_VSNPRINTFe$B$r>C$;$Pe(Bmissinge$B$N$[$&$r;H$&$he(B
e$B$&$K$J$k$O$:$G$9!#e(B

mingw e$B$G$Oe(B configure e$B$G@8@.$5$l$?e(Bconfig.h e$B$r;H$&$h$&$G$9$7e(B
bcc e$B$G$Oe(B msvcrt e$B$r;H$o$J$$$h$&$J$N$G!"$=$l$O:G8e$N<jCJ$K$7$?$$$H;W$$$^$9!#e(B

mingwe$B$G$Oe(Bconfiugre.ine$B$Ne(B ac_cv_func_vsnprintf=yes
e$B$H$$$&9T$r>C$;e(B
e$B$P$G$-$k$O$:$G$9!#e(Bbcce$B$Oe(Bbcc32/Makefile.sube$B$K$"$kDj5A$r;H$&$N$G!"e(B
win32/Makefile.sube$B$rJQ99$7$F$b1F6A$O<u$1$^$;$s!#e(B

e$B$G$9$,%"%I%P%$%9$N$*$+$2$G$&$^$/$$$+$J$$860x$,$o$+$j$^$7$?!#$"$j$,$H$&$4$6$$$^$9!#e(B
vsnprinte$B#fe(B e$B$re(B rb_win32_vsnprintf e$B$G>e=q$-$7$J$1$l$P$$$$$@$1$@$C$?$h$&$G$9!#e(B

rb_w32_vsnprintf()e$B$Oe(Bmsvcrte$B$Ne(Bvsnprintf()e$B$N%P%0$r2sHr$9$k$?$a$N$be(B
e$B$N$J$N$G!“e(Bmissinge$B$N$b$N$r;H$&$N$G$”$l$Pe(Bsnprintf()e$B$bITMW$K$J$j$^e(B
e$B$9!#%P%$%J%j8_49$K$D$$$F$Oe(Bwin32/mkexports.rbe$B$Ge(Baliase$B$7$F$*$1$P=<e(B
e$BJ,$G$7$g$&!#e(B

e$B$A$J$_$K!"e(Bmissing/vsnprintf.ce$B$X$N=$@5$O$I$&$$$&$b$N$G$7$g$&$+!#e(B

e$B@bL@ITB-$G$7$?!#$9$_$^$;$s!#e(B
test_sprintf_comb.rb e$B$,DL$k$h$&$K=$@5$7$^$7$?!#6qBNE*$K$O0J2<$NDL$j$G$9!#e(B

e$B$J$k$[$I!#e(B

  • sprintf(buf, “%#.15g”, value); /* ensure to print decimal point */
  • snprintf(buf, 32, “%#.15g”, value); /* ensure to print decimal point */

sizeof(buf)e$B$N$[$&$,$$$$$H;W$$$^$9!#e(B

e$B%o%J%Y$G$9!#e(B

2008/10/26 15:45 Nobuyoshi N. [email protected]:

At Sun, 26 Oct 2008 10:35:17 +0900,
_ wanabe wrote in [ruby-dev:36932]:

vsnprintf.c e$BCf$Ne(B vsnprintf e$B$r30$K=P$9$d$jJ}$,$“$^$j$&$^$/$J$$$h$&$K;W$&$N$Ge(B
e$B2?$+$&$^$$J}K!$r$4B8CN$NJ}$O65$($F$$$?$@$1$k$H$”$j$,$?$$$G$9!#e(B

win32/Makefile.sube$B$Ne(BHAVE_VSNPRINTFe$B$r>C$;$Pe(Bmissinge$B$N$[$&$r;H$&$he(B
e$B$&$K$J$k$O$:$G$9!#e(B

mingw e$B$G$Oe(B configure e$B$G@8@.$5$l$?e(Bconfig.h
e$B$r;H$&$h$&$G$9$7e(B
bcc e$B$G$Oe(B msvcrt
e$B$r;H$o$J$$$h$&$J$N$G!“$=$l$O:G8e$N<jCJ$K$7$?$$$H;W$$$^$9!#e(B
e$B$G$9$,%”%I%P%$%9$N$*$+$2$G$&$^$/$$$+$J$$860x$,$o$+$j$^$7$?!#$"$j$,$H$&$4$6$$$^$9!#e(B
vsnprinte$B#fe(B e$B$re(B rb_win32_vsnprintf
e$B$G>e=q$-$7$J$1$l$P$$$$$@$1$@$C$?$h$&$G$9!#e(B

e$B$A$J$_$K!"e(Bmissing/vsnprintf.ce$B$X$N=$@5$O$I$&$$$&$b$N$G$7$g$&$+!#e(B

e$B@bL@ITB-$G$7$?!#$9$_$^$;$s!#e(B
test_sprintf_comb.rb
e$B$,DL$k$h$&$K=$@5$7$^$7$?!#6qBNE*$K$O0J2<$NDL$j$G$9!#e(B

(1) sprintf(“%e”, -1.0000000000000000159e+100)
e$B!!e(B->e$B=$@5A0!'e(B"-1e+100"e$B!!=$@58e!'e(B"-1.000000e+100"
(2) sprintf(“%.0f”, 0.010000000000000000208)
e$B!!e(B->e$B=$@5A0!'e(B"0.“e$B!!=$@58e!'e(B"0”
(3) sprintf(“% #±0.f”, -0)
e$B!!e(B->e$B=$@5A0!'e(B"-0"e$B!!=$@58e!'e(B"-0."
(4) sprintf(“%.0G”, 1)
e$B!!e(B->e$B=$@5A0!'e(B"1E+00"e$B!!=$@58e!'e(B"1"

e$B$G$9$,:#8+D>$7$F$_$k$H!"e(B(1)e$B$N=$@5K!$,>iD9$+$D0UL#ITL@$G$7$?$N$Ge(B
e$B@h$Ne(B rb_win32_vsnprintf e$B$N7o$HJ;$;$F%Q%C%A$r=q$-D>$7$^$7$?!#e(B

Index: include/ruby/win32.h

— include/ruby/win32.h (revision 19941)
+++ include/ruby/win32.h (working copy)
@@ -243,7 +243,11 @@
extern void rb_w32_free_environ(char **);
extern int rb_w32_map_errno(DWORD);

+#if (defined(_MSC_VER) && defined(_DLL)) || defined(MSVCRT)
+#undef HAVE_VSNPRINTF
+#else
#define vsnprintf(s,n,f,l) rb_w32_vsnprintf(s,n,f,l)
+#endif
#define snprintf rb_w32_snprintf
extern int rb_w32_vsnprintf(char *, size_t, const char *, va_list);
extern int rb_w32_snprintf(char *, size_t, const char *, …);
Index: sprintf.c

— sprintf.c (revision 19941)
+++ sprintf.c (working copy)
@@ -1018,7 +1018,7 @@
need += 20;

 CHECK(need);
  • sprintf(&buf[blen], fbuf, fval);
  • snprintf(&buf[blen], need, fbuf, fval);
    blen += strlen(&buf[blen]);
    }
    break;
    Index: numeric.c
    ===================================================================
    — numeric.c (revision 19941)
    +++ numeric.c (working copy)
    @@ -530,12 +530,12 @@
    else if(isnan(value))
    return rb_usascii_str_new2(“NaN”);
  • sprintf(buf, “%#.15g”, value); /* ensure to print decimal point */
  • snprintf(buf, 32, “%#.15g”, value); /* ensure to print decimal
    point /
    if (!(e = strchr(buf, ‘e’))) {
    e = buf + strlen(buf);
    }
    if (!ISDIGIT(e[-1])) { /
    reformat if ended with decimal point
    (ex 111111111111111.) */
  • sprintf(buf, “%#.14e”, value);
  • snprintf(buf, 32, “%#.14e”, value);
    if (!(e = strchr(buf, ‘e’))) {
    e = buf + strlen(buf);
    }
    @@ -1548,7 +1548,7 @@
    char buf[24];
    char *s;
  •  sprintf(buf, "%-.10g", RFLOAT_VALUE(val));
    
  •  snprintf(buf, 24, "%-.10g", RFLOAT_VALUE(val));
     if ((s = strchr(buf, ' ')) != 0) *s = '\0';
     rb_raise(rb_eRangeError, "float %s out of range of integer", 
    

buf);
}
@@ -1694,7 +1694,7 @@
char buf[24];
char *s;

  •  sprintf(buf, "%-.10g", RFLOAT_VALUE(val));
    
  •  snprintf(buf, 24, "%-.10g", RFLOAT_VALUE(val));
     if ((s = strchr(buf, ' ')) != 0) *s = '\0';
     rb_raise(rb_eRangeError, "float %s out of range of long long", 
    

buf);
}
Index: missing/vsnprintf.c

— missing/vsnprintf.c (revision 19941)
+++ missing/vsnprintf.c (working copy)
@@ -753,6 +753,8 @@
#ifdef FLOATING_POINT
case ‘e’: /* anomalous precision */
case ‘E’:

  •  if (prec != 0)
    
  •    flags |= ALT;
     prec = (prec == -1) ?
       DEFPREC + 1 : prec + 1;
     /* FALLTHROUGH */
    

@@ -782,7 +784,7 @@
cp = cvt(_double, prec, flags, &softsign,
&expt, ch, &ndig);
if (ch == ‘g’ || ch == ‘G’) {

  •    if (expt <= -4 || expt > prec)
    
  •    if (expt <= -4 || (expt > prec && expt > 1))
         ch = (ch == 'g') ? 'e' : 'E';
       else
         ch = 'g';
    

@@ -798,6 +800,8 @@
size = expt;
if (prec || flags & ALT)
size += prec + 1;

  •    } else if (!prec) { /* "0" */
    
  •      size = 1;
       } else  /* "0.X" */
         size = prec + 2;
     } else if (expt >= ndig) {  /* fixed g fmt */
    

@@ -1008,13 +1012,15 @@
if (ch >= ‘f’) { /* ‘f’ or ‘g’ /
if (_double == 0) {
/
kludge for __dtoa irregularity */

  •      if (prec == 0 ||
    
  •      if (ndig <= 1 &&
             (flags & ALT) == 0) {
           PRINT("0", 1);
         } else {
           PRINT("0.", 2);
           PAD(ndig - 1, zeroes);
         }
    
  •    } else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
    
  •      PRINT("0", 1);
       } else if (expt <= 0) {
         PRINT("0.", 2);
         PAD(-expt, zeroes);