summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Crane <arc@cpan.org>2015-07-07 17:12:26 +0100
committerAaron Crane <arc@cpan.org>2015-07-15 14:25:05 +0100
commit638ca15aeec3bf86124489c8c913c5b42d4fee16 (patch)
tree2c2c3cb9731b20c9e386f7d0a2bbbe7d7121fe61
parent082ce9c667e6d73783164fa1abab61806b678b4f (diff)
downloadperl-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.pod14
-rw-r--r--sv.c26
-rw-r--r--t/op/sprintf.t5
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
diff --git a/sv.c b/sv.c
index d3debba72c..e0f80d036a 100644
--- a/sv.c
+++ b/sv.c
@@ -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<