diff options
author | Aaron Crane <arc@cpan.org> | 2015-07-07 17:12:26 +0100 |
---|---|---|
committer | Aaron Crane <arc@cpan.org> | 2015-07-15 14:25:05 +0100 |
commit | 638ca15aeec3bf86124489c8c913c5b42d4fee16 (patch) | |
tree | 2c2c3cb9731b20c9e386f7d0a2bbbe7d7121fe61 | |
parent | 082ce9c667e6d73783164fa1abab61806b678b4f (diff) | |
download | perl-638ca15aeec3bf86124489c8c913c5b42d4fee16.tar.gz |
Support reordered precision arguments in (s)printf
The printf builtins gained support for argument reordering in October 2000,
in eb3fce905f8436bbc374998ec8c7c34ce2b73e4e, as part of the 5.7.x blead
release cycle. However, a simple typo meant that it never worked: the
initial implementation stored the argument index in the variable "ewix"
(explicit width-argument index) instead of "epix" (for "precision").
The bug was noticed in July 2002, two days before the 5.8.0 release, so
fixing it at that stage was deemed riskier than documenting it. The commit in
question is 7b8dd722af72d0ca45650fb784c09763c0732e34, which was originally
posted as http://marc.info/?l=perl5-porters&m=102683138220786&w=2 .
For whatever reason, the obvious fix was never subsequently applied. This
commit remedies that, and extends it to also skip all redundant-argument
warnings when the precision is supplied with via an explicit index.
-rw-r--r-- | pod/perlfunc.pod | 14 | ||||
-rw-r--r-- | sv.c | 26 | ||||
-rw-r--r-- | t/op/sprintf.t | 5 |
3 files changed, 28 insertions, 17 deletions
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod index 17180caf70..485109fc73 100644 --- a/pod/perlfunc.pod +++ b/pod/perlfunc.pod @@ -7289,11 +7289,16 @@ to fit the specified width: printf '<%.5s>', "truncated"; # prints "<trunc>" printf '<%10.5s>', "truncated"; # prints "< trunc>" -You can also get the precision from the next argument using C<.*>: +You can also get the precision from the next argument using C<.*>, or from a +specified argument (e.g., with C<.*2$>): printf '<%.6x>', 1; # prints "<000001>" printf '<%.*x>', 6, 1; # prints "<000001>" + printf '<%.*2$x>', 1, 6; # prints "<000001>" + + printf '<%6.*2$x>', 1, 4; # prints "< 0001>" + If a precision obtained through C<*> is negative, it counts as having no precision at all. @@ -7306,13 +7311,6 @@ as having no precision at all. printf '<%.*d>', 0, 0; # prints "<>" printf '<%.*d>', -1, 0; # prints "<0>" -You cannot currently get the precision from a specified number, -but it is intended that this will be possible in the future, for -example using C<.*2$>: - - printf '<%.*2$x>', 1, 6; # INVALID, but in future will print - # "<000001>" - =item size For numeric conversions, you can specify the size to interpret the @@ -11449,16 +11449,24 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p q++; if (*q == '*') { q++; - if ( ((epix = expect_number(&q))) && (*q++ != '$') ) - goto unknown; - /* XXX: todo, support specified precision parameter */ - if (epix) - goto unknown; + if ( (epix = expect_number(&q)) ) { + if (*q++ == '$') + used_explicit_ix = TRUE; + else + goto unknown; + } if (args) - i = va_arg(*args, int); - else - i = (ewix ? ewix <= svmax : svix < svmax) - ? SvIVx(svargs[ewix ? ewix-1 : svix++]) : 0; + i = va_arg(*args, int); + else { + SV *precsv; + if (epix) + FETCH_VCATPVFN_ARGUMENT( + precsv, epix > 0 && epix <= svmax, svargs[epix-1]); + else + FETCH_VCATPVFN_ARGUMENT( + precsv, svix < svmax, svargs[svix++]); + i = precsv == &PL_sv_no ? 0 : SvIVx(precsv); + } precis = i; has_precis = !(i < 0); } diff --git a/t/op/sprintf.t b/t/op/sprintf.t index e11287c6c4..db934c7100 100644 --- a/t/op/sprintf.t +++ b/t/op/sprintf.t @@ -308,6 +308,10 @@ __END__ >%+.*d< >[-2,0]< >+0< >% .*d< >[-2,0]< > 0< >%0.*d< >[-2,0]< >0< +>%.*2$d< >[5,3]< >005< >reordered precision arg< +>%4.*2$d< >[5,3]< > 005< >width with reordered precision< +>%*3$.*2$d< >[5,3,4]< > 005< >reordered width with reordered precision< +>%3$*2$.*1$d< >[3,4,5]< > 005< >reordered param, width, precision< >%d< >-1< >-1< >%-d< >-1< >-1< >%+d< >-1< >-1< @@ -738,3 +742,4 @@ a>%*v.*X< >[':', 3, '012']< >030:031:032< >perl #83194: vector flag + custom sep e>%*v.*X< >[':', 3, '012']< >0F0:0F1:0F2< >perl #83194: vector flag + custom separator + dynamic precision< a>%vd< >"version"< >118.101.114.115.105.111.110< >perl #102586: vector flag + "version"< e>%vd< >"version"< >165.133.153.162.137.150.149< >perl #102586: vector flag + "version"< +>%3$*4$v*2$.*1$x< >[3, 4, "\x11\x22\x33", "/"]< > 011/ 022/ 033< >four reordered args< |