>From 4c9bbc524171fa1022e0cbf4516827be98ae08a5 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 1 Jun 2017 16:03:12 -0700 Subject: [PATCH 2/2] Limit format fields to more POSIX-like spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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. --- doc/lispref/strings.texi | 13 +++++-------- src/editfns.c | 8 ++++---- test/src/editfns-tests.el | 28 ++++++++++++++++++++++------ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 4d33e55..e80e778 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -965,16 +965,13 @@ Formatting Strings decimal number immediately after the initial @samp{%}, followed by a literal dollar sign @samp{$}. It causes the format specification to convert the argument with the given number instead of the next -argument. Argument 1 is the argument just after the format. - - You can mix specifications with and without field numbers. A -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: +argument. Field numbers start at 1. A format can contain either +numbered or unnumbered format specifications but not both, except that address@hidden can be mixed with numbered specifications. @example -(format "Argument %2$s, then %s, then %1$s" "x" "y" "z") - @result{} "Argument y, then z, then x" +(format "%2$s, %3$s, %%, %1$s" "x" "y" "z") + @result{} "y, z, %, x" @end example @cindex flags in format specifications diff --git a/src/editfns.c b/src/editfns.c index 1dbae8f..29af25a 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -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 "." followed by [0-9]+. -If field is given, it must be a one-based argument number; the given -argument is substituted instead of the next one. +If a %-sequence is numbered with a field with positive value N, the +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 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) num = str2num (format, &num_end); if (*num_end == '$') { - if (num == 0) - error ("Invalid format field number 0"); n = num - 1; format = num_end + 1; } diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index c5923aa..54fb743 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el @@ -178,17 +178,33 @@ transpose-test-get-byte-positions (concat (make-string 2048 ?X) "0"))))) (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")) - (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")) - (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)) '(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)) '(error "Invalid format operation %$"))) - (should (equal (should-error (format "a %0$s b" 11)) - '(error "Invalid format field number 0"))) - (should (equal (format "a %1$% %s b" 11) "a % 11 b"))) + (should (equal (should-error (format "a %-1$s b" 11)) + '(error "Invalid format operation %$")))) ;;; editfns-tests.el ends here -- 2.9.4