emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 5324710 2/2: Minor improvements to format field num


From: Philipp Stephani
Subject: [Emacs-diffs] master 5324710 2/2: Minor improvements to format field numbers
Date: Thu, 1 Jun 2017 18:30:01 -0400 (EDT)

branch: master
commit 53247108411a1e9d1aa5352c231fa049f3f918aa
Author: Paul Eggert <address@hidden>
Commit: Philipp Stephani <address@hidden>

    Minor improvements to format field numbers
    
    * src/editfns.c (styled_format): Allow field numbers in a %% spec.
    No need for a special diagnostic for field numbers greater than
    PTRDIFF_MAX.  Reword diagnostic for field 0.
    * test/src/editfns-tests.el (format-with-field): Adjust to match.
---
 doc/lispref/strings.texi  | 119 +++++++++++++++++++++-------------------------
 etc/NEWS                  |   2 +-
 src/editfns.c             |  56 ++++++++--------------
 test/src/editfns-tests.el |  10 ++--
 4 files changed, 79 insertions(+), 108 deletions(-)

diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 526b1fb..4d33e55 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -864,15 +864,6 @@ below, as the first argument, and the string as the 
second, like this:
   (format "%s" @var{arbitrary-string})
 @end example
 
-  If @var{string} contains more than one format specification and none
-of the format specifications contain an explicit field number, the
-format specifications correspond to successive values from
address@hidden  Thus, the first format specification in @var{string}
-uses the first such value, the second format specification uses the
-second such value, and so on.  Any extra format specifications (those
-for which there are no corresponding values) cause an error.  Any
-extra values to be formatted are ignored.
-
   Certain format specifications require values of particular types.  If
 you supply a value that doesn't fit the requirements, an error is
 signaled.
@@ -962,68 +953,33 @@ operation} error.
 @end group
 @end example
 
+  By default, format specifications correspond to successive values from
address@hidden  Thus, the first format specification in @var{string}
+uses the first such value, the second format specification uses the
+second such value, and so on.  Any extra format specifications (those
+for which there are no corresponding values) cause an error.  Any
+extra values to be formatted are ignored.
+
 @cindex field numbers in format spec
-  A specification can have a @dfn{field number}, which is a decimal
-number after the initial @samp{%}, followed by a literal dollar sign
address@hidden  If you provide a field number, then the argument to be
-printed corresponds to the given field number instead of the next
-argument.  Field numbers start at 1.
+  A format specification can have a @dfn{field number}, which is a
+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
+  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:
 
 @example
-(format "First argument %2$s, then %s, then %1$s" 1 2 3)
-     @result{} "First argument 2, then 3, then 1"
address@hidden example
-
-You can't use field numbers in a @samp{%%} specification.
-
address@hidden field width
address@hidden padding
-  A specification can have a @dfn{width}, which is a decimal number
-between the @samp{%} and the specification character.  If the printed
-representation of the object contains fewer characters than this
-width, @code{format} extends it with padding.  The width specifier is
-ignored for the @samp{%%} specification.  Any padding introduced by
-the width specifier normally consists of spaces inserted on the left:
-
address@hidden
-(format "%5d is padded on the left with spaces" 123)
-     @result{} "  123 is padded on the left with spaces"
address@hidden example
-
address@hidden
-If the width is too small, @code{format} does not truncate the
-object's printed representation.  Thus, you can use a width to specify
-a minimum spacing between columns with no risk of losing information.
-In the following two examples, @samp{%7s} specifies a minimum width
-of 7.  In the first case, the string inserted in place of @samp{%7s}
-has only 3 letters, and needs 4 blank spaces as padding.  In the
-second case, the string @code{"specification"} is 13 letters wide but
-is not truncated.
-
address@hidden
address@hidden
-(format "The word '%7s' has %d letters in it."
-        "foo" (length "foo"))
-     @result{} "The word '    foo' has 3 letters in it."
-(format "The word '%7s' has %d letters in it."
-        "specification" (length "specification"))
-     @result{} "The word 'specification' has 13 letters in it."
address@hidden group
+(format "Argument %2$s, then %s, then %1$s" "x" "y" "z")
+     @result{} "Argument y, then z, then x"
 @end example
 
-If you want to use both a field number and a width, place the field
-number before the width.  For example, in @samp{%2$7s}, @samp{2} is
-the field number and @samp{7} is the width.
-
 @cindex flags in format specifications
-  After the @samp{%} and before the optional width specifier, you can
-also put certain @dfn{flag characters}.  The flag characters need to
-come directly after a potential field number.
+  After the @samp{%} and any field number, you can put certain
address@hidden characters}.
 
   The flag @samp{+} inserts a plus sign before a positive number, so
 that it always has a sign.  A space character as flag inserts a space
@@ -1048,8 +1004,8 @@ specification characters like @samp{%s}, @samp{%S} and 
@samp{%c}.
 These specification characters accept the @samp{0} flag, but still pad
 with @emph{spaces}.
 
-  The flag @samp{-} causes the padding inserted by the width
-specifier, if any, to be inserted on the right rather than the left.
+  The flag @samp{-} causes any padding inserted by the width,
+if specified, to be inserted on the right rather than the left.
 If both @samp{-} and @samp{0} are present, the @samp{0} flag is
 ignored.
 
@@ -1067,9 +1023,44 @@ ignored.
 @end group
 @end example
 
address@hidden field width
address@hidden padding
+  A specification can have a @dfn{width}, which is a decimal number
+that appears after any field number and flags.  If the printed
+representation of the object contains fewer characters than this
+width, @code{format} extends it with padding.  The width is
+ignored for the @samp{%%} specification.  Any padding introduced by
+the width normally consists of spaces inserted on the left:
+
address@hidden
+(format "%5d is padded on the left with spaces" 123)
+     @result{} "  123 is padded on the left with spaces"
address@hidden example
+
address@hidden
+If the width is too small, @code{format} does not truncate the
+object's printed representation.  Thus, you can use a width to specify
+a minimum spacing between columns with no risk of losing information.
+In the following two examples, @samp{%7s} specifies a minimum width
+of 7.  In the first case, the string inserted in place of @samp{%7s}
+has only 3 letters, and needs 4 blank spaces as padding.  In the
+second case, the string @code{"specification"} is 13 letters wide but
+is not truncated.
+
address@hidden
address@hidden
+(format "The word '%7s' has %d letters in it."
+        "foo" (length "foo"))
+     @result{} "The word '    foo' has 3 letters in it."
+(format "The word '%7s' has %d letters in it."
+        "specification" (length "specification"))
+     @result{} "The word 'specification' has 13 letters in it."
address@hidden group
address@hidden example
+
 @cindex precision in format specifications
   All the specification characters allow an optional @dfn{precision}
-before the character (after the width, if present).  The precision is
+after the field number, flags and width, if present.  The precision is
 a decimal-point @samp{.} followed by a digit-string.  For the
 floating-point specifications (@samp{%e} and @samp{%f}), the
 precision specifies how many digits following the decimal point to
diff --git a/etc/NEWS b/etc/NEWS
index 1b098f9..7972511 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -369,7 +369,7 @@ libraries: 'find-library-other-window' and 
'find-library-other-frame'.
 display of raw bytes from octal to hex.
 
 ** You can now provide explicit field numbers in format specifiers.
-For example, '(format "%2$s %1$s" 1 2)' produces "2 1".
+For example, '(format "%2$s %1$s" "X" "Y")' produces "Y X".
 
 
 * Editing Changes in Emacs 26.1
diff --git a/src/editfns.c b/src/editfns.c
index 44341ce..98187df 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4046,9 +4046,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
             field-width ::= [0-9]+
             precision ::= '.' [0-9]*
 
-             If a field-number is specified, it specifies the argument
-             number to substitute.  Otherwise, the next argument is
-             taken.
+            If present, a field-number specifies the argument number
+            to substitute.  Otherwise, the next argument is taken.
 
             If a field-width is specified, it specifies to which width
             the output should be padded with blanks, if the output
@@ -4058,28 +4057,20 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
             digits to print after the '.' for floats, or the max.
             number of chars to print from a string.  */
 
-          char *field_end;
-          uintmax_t raw_field = strtoumax (format, &field_end, 10);
-          bool has_field = false;
-          if (c_isdigit (*format) && *field_end == '$')
-            {
-              if (raw_field < 1 || raw_field >= PTRDIFF_MAX)
-                {
-                  /* doprnt doesn't support %.*s, so we need to copy
-                     the field number string.  */
-                  ptrdiff_t length = field_end - format;
-                  eassert (length > 0);
-                  eassert (length < PTRDIFF_MAX);
-                  char *field = SAFE_ALLOCA (length + 1);
-                  memcpy (field, format, length);
-                  field[length] = '\0';
-                  error ("Invalid field number `%s'", field);
-                }
-              has_field = true;
-              /* n is incremented below.  */
-              n = raw_field - 1;
-              format = field_end + 1;
-            }
+         uintmax_t num;
+         char *num_end;
+         if (c_isdigit (*format))
+           {
+             num = strtoumax (format, &num_end, 10);
+             if (*num_end == '$')
+               {
+                 if (num == 0)
+                   error ("Invalid format field number 0");
+                 n = min (num, PTRDIFF_MAX);
+                 n--;
+                 format = num_end + 1;
+               }
+           }
 
          bool minus_flag = false;
          bool  plus_flag = false;
@@ -4104,11 +4095,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
          space_flag &= ! plus_flag;
          zero_flag &= ! minus_flag;
 
-         char *num_end;
-         uintmax_t raw_field_width = strtoumax (format, &num_end, 10);
-         if (max_bufsize <= raw_field_width)
+         num = strtoumax (format, &num_end, 10);
+         if (max_bufsize <= num)
            string_overflow ();
-         ptrdiff_t field_width = raw_field_width;
+         ptrdiff_t field_width = num;
 
          bool precision_given = *num_end == '.';
          uintmax_t precision = (precision_given
@@ -4123,13 +4113,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
          memset (&discarded[format0 - format_start], 1,
                  format - format0 - (conversion == '%'));
          if (conversion == '%')
-            {
-              if (has_field)
-                /* FIXME: `error' doesn't appear to support `%%'.  */
-                error ("Field number specified together with `%c' conversion",
-                       '%');
-              goto copy_char;
-            }
+           goto copy_char;
 
          ++n;
          if (! (n < nargs))
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index f76c6c9..c5923aa 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -186,13 +186,9 @@
   (should (equal (should-error (format "a %999999$s b" 11))
                  '(error "Not enough arguments for format string")))
   (should (equal (should-error (format "a %$s b" 11))
-                 ;; FIXME: there shouldn't be two % in the error
-                 ;; string!
-                 '(error "Invalid format operation %%$")))
+                 '(error "Invalid format operation %$")))
   (should (equal (should-error (format "a %0$s b" 11))
-                 '(error "Invalid field number `0'")))
-  (should (equal
-           (should-error (format "a %1$% %s b" 11))
-           '(error "Field number specified together with `%' conversion"))))
+                 '(error "Invalid format field number 0")))
+  (should (equal (format "a %1$% %s b" 11) "a % 11 b")))
 
 ;;; editfns-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]