Commit 53247108 authored by Paul Eggert's avatar Paul Eggert Committed by Philipp Stephani
Browse files

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.
parent 0dd1bbb0
......@@ -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
@var{objects}. 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
@var{objects}. 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
@samp{$}. 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"
@end example
You can't use field numbers in a @samp{%%} specification.
@cindex field width
@cindex 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:
@example
(format "%5d is padded on the left with spaces" 123)
@result{} " 123 is padded on the left with spaces"
@end example
@noindent
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.
@example
@group
(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."
@end 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
@dfn{flag 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
@cindex field width
@cindex 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:
@example
(format "%5d is padded on the left with spaces" 123)
@result{} " 123 is padded on the left with spaces"
@end example
@noindent
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.
@example
@group
(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."
@end group
@end 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
......
......@@ -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
......
......@@ -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))
......
......@@ -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
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