From: Nicholas Clark Date: Thu, 13 May 2010 11:04:55 +0000 (+0100) Subject: Return 0 (with a warning) for sprintf("%.0g") and sprintf("%.0f") X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=95ea86d57f54b7436354f58e8ed9989a65c974a8;p=p5sagit%2Fp5-mst-13.2.git Return 0 (with a warning) for sprintf("%.0g") and sprintf("%.0f") There is special case code in the sprintf implementation, for simple %f and %g formats, conditionally compiled in only when NVs are doubles. Under long doubles, these are handled by the general purpose code, which always returns 0 if the argument is missing. Note that sprintf(" %.0g"), ie a leading space, sufficient to bypass the special case code, would return the string " 0". The special case code used to return an empty string, meaning that the behaviour of sprintf("%.0g") and sprintf("%.0f") was inconsistent between a perl built with doubles, and a perl with long doubles, and the behaviour of sprintf("%.0g") and sprintf(" %.0g") was inconsistent. 5b98cd54dff3b163 fixed #62874 - the special case code did not warn, but changed behaviour to return 0. d347ad18ecf3da70 undid the behaviour change, viewing it as a regression. However, the tests added in 5b98cd54dff3b163 expose the inconsistency in behaviour between doubles and long doubles. There should be no inconsistency, hence the only logically consistent conclusion is that the special case implementation was wrong - it cannot give results inconsistent with the general code. Hence this commit changes it to return 0 (with a warning). This is achieved by simply skipping the special case code, if there are insufficient arguments. --- diff --git a/sv.c b/sv.c index 8cbd3a0..db11794 100644 --- a/sv.c +++ b/sv.c @@ -9399,15 +9399,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen, pp = pat + 2; while (*pp >= '0' && *pp <= '9') digits = 10 * digits + (*pp++ - '0'); - if (pp - pat == (int)patlen - 1) { - NV nv; - - if (svix < svmax) - nv = SvNV(*svargs); - else { - S_vcatpvfn_missing_argument(aTHX); - return; - } + if (pp - pat == (int)patlen - 1 && svix < svmax) { + const NV nv = SvNV(*svargs); if (*pp == 'g') { /* Add check for digits != 0 because it seems that some gconverts are buggy in this case, and we don't yet have diff --git a/t/op/sprintf.t b/t/op/sprintf.t index b153839..14f0395 100644 --- a/t/op/sprintf.t +++ b/t/op/sprintf.t @@ -374,7 +374,7 @@ __END__ >%+8.1f< >-1234.875< > -1234.9< >%*.*f< >[5, 2, 12.3456]< >12.35< >%f< >0< >0.000000< ->%.0f< >[]< > MISSING< +>%.0f< >[]< >0 MISSING< > %.0f< >[]< > 0 MISSING< >%.0f< >0< >0< >%.0f< >2**38< >274877906944< >Should have exact int'l rep'n< @@ -390,7 +390,7 @@ __END__ >%g< >12345.6789< >12345.7< >%+g< >12345.6789< >+12345.7< >%#g< >12345.6789< >12345.7< ->%.0g< >[]< > MISSING< +>%.0g< >[]< >0 MISSING< > %.0g< >[]< > 0 MISSING< >%.0g< >-0.0< >-0< >C99 standard mandates minus sign but C89 does not skip: MSWin32 VMS hpux:10.20 openbsd netbsd:1.5 irix darwin< >%.0g< >12345.6789< >1e+04<