Commit 8de2581a authored by Paul Eggert's avatar Paul Eggert
Browse files

Limit format fields to more POSIX-like spec

* doc/lispref/strings.texi (Formatting Strings):
Don’t allow mixing numbered with unnumbered format specs.
* src/editfns.c (styled_format): Don’t bother checking for field 0,
since it doesn’t crash and the behavior is not specified.
* test/src/editfns-tests.el (format-with-field): Adjust tests to
match current doc.  Add more tests for out-of-range fields.
parent 178d0cb5
...@@ -965,16 +965,13 @@ extra values to be formatted are ignored. ...@@ -965,16 +965,13 @@ extra values to be formatted are ignored.
decimal number immediately after the initial @samp{%}, followed by a decimal number immediately after the initial @samp{%}, followed by a
literal dollar sign @samp{$}. It causes the format specification to literal dollar sign @samp{$}. It causes the format specification to
convert the argument with the given number instead of the next convert the argument with the given number instead of the next
argument. Argument 1 is the argument just after the format. argument. Field numbers start at 1. A format can contain either
numbered or unnumbered format specifications but not both, except that
You can mix specifications with and without field numbers. A @samp{%%} can be mixed with numbered specifications.
specification without a field number that follows a specification with
a field number will convert the argument after the one specified by
the field number:
@example @example
(format "Argument %2$s, then %s, then %1$s" "x" "y" "z") (format "%2$s, %3$s, %%, %1$s" "x" "y" "z")
@result{} "Argument y, then z, then x" @result{} "y, z, %, x"
@end example @end example
@cindex flags in format specifications @cindex flags in format specifications
......
...@@ -3900,8 +3900,10 @@ where field is [0-9]+ followed by a literal dollar "$", flags is ...@@ -3900,8 +3900,10 @@ where field is [0-9]+ followed by a literal dollar "$", flags is
[+ #-0]+, width is [0-9]+, and precision is a literal period "." [+ #-0]+, width is [0-9]+, and precision is a literal period "."
followed by [0-9]+. followed by [0-9]+.
If field is given, it must be a one-based argument number; the given If a %-sequence is numbered with a field with positive value N, the
argument is substituted instead of the next one. Nth argument is substituted instead of the next one. A format can
contain either numbered or unnumbered %-sequences but not both, except
that %% can be mixed with numbered %-sequences.
The + flag character inserts a + before any positive number, while a The + flag character inserts a + before any positive number, while a
space inserts a space before any positive number; these flags only space inserts a space before any positive number; these flags only
...@@ -4081,8 +4083,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) ...@@ -4081,8 +4083,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
num = str2num (format, &num_end); num = str2num (format, &num_end);
if (*num_end == '$') if (*num_end == '$')
{ {
if (num == 0)
error ("Invalid format field number 0");
n = num - 1; n = num - 1;
format = num_end + 1; format = num_end + 1;
} }
......
...@@ -178,17 +178,33 @@ ...@@ -178,17 +178,33 @@
(concat (make-string 2048 ?X) "0"))))) (concat (make-string 2048 ?X) "0")))))
(ert-deftest format-with-field () (ert-deftest format-with-field ()
(should (equal (format "First argument %2$s, then %s, then %1$s" 1 2 3) (should (equal (format "First argument %2$s, then %3$s, then %1$s" 1 2 3)
"First argument 2, then 3, then 1")) "First argument 2, then 3, then 1"))
(should (equal (format "a %2$s %d %1$d %2$S %d %d b" 11 "22" 33 44) (should (equal (format "a %2$s %3$d %1$d %2$S %3$d %4$d b" 11 "22" 33 44)
"a 22 33 11 \"22\" 33 44 b")) "a 22 33 11 \"22\" 33 44 b"))
(should (equal (format "a %08$s %s b" 1 2 3 4 5 6 7 8 9) "a 8 9 b")) (should (equal (format "a %08$s %0000000000000000009$s b" 1 2 3 4 5 6 7 8 9)
"a 8 9 b"))
(should (equal (should-error (format "a %999999$s b" 11)) (should (equal (should-error (format "a %999999$s b" 11))
'(error "Not enough arguments for format string"))) '(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %2147483647$s b"))
'(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %9223372036854775807$s b"))
'(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %9223372036854775808$s b"))
'(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %18446744073709551615$s b"))
'(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %18446744073709551616$s b"))
'(error "Not enough arguments for format string")))
(should (equal (should-error
(format (format "a %%%d$d b" most-positive-fixnum)))
'(error "Not enough arguments for format string")))
(should (equal (should-error
(format (format "a %%%d$d b" (+ 1.0 most-positive-fixnum))))
'(error "Not enough arguments for format string")))
(should (equal (should-error (format "a %$s b" 11)) (should (equal (should-error (format "a %$s b" 11))
'(error "Invalid format operation %$"))) '(error "Invalid format operation %$")))
(should (equal (should-error (format "a %0$s b" 11)) (should (equal (should-error (format "a %-1$s b" 11))
'(error "Invalid format field number 0"))) '(error "Invalid format operation %$"))))
(should (equal (format "a %1$% %s b" 11) "a % 11 b")))
;;; editfns-tests.el ends here ;;; editfns-tests.el ends here
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment