aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2017-05-31 22:09:39 -0700
committerPhilipp Stephani2017-06-02 00:25:48 +0200
commit53247108411a1e9d1aa5352c231fa049f3f918aa (patch)
treebb550ccc67607f7f3cfc6a135b0838fff4b4c8c9
parent0dd1bbb0bb228acab21b8e16f2f2a0b5a17b19ab (diff)
downloademacs-53247108411a1e9d1aa5352c231fa049f3f918aa.tar.gz
emacs-53247108411a1e9d1aa5352c231fa049f3f918aa.zip
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.
-rw-r--r--doc/lispref/strings.texi119
-rw-r--r--etc/NEWS2
-rw-r--r--src/editfns.c56
-rw-r--r--test/src/editfns-tests.el10
4 files changed, 79 insertions, 108 deletions
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 526b1fb4ebc..4d33e55b018 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:
864 (format "%s" @var{arbitrary-string}) 864 (format "%s" @var{arbitrary-string})
865@end example 865@end example
866 866
867 If @var{string} contains more than one format specification and none
868of the format specifications contain an explicit field number, the
869format specifications correspond to successive values from
870@var{objects}. Thus, the first format specification in @var{string}
871uses the first such value, the second format specification uses the
872second such value, and so on. Any extra format specifications (those
873for which there are no corresponding values) cause an error. Any
874extra values to be formatted are ignored.
875
876 Certain format specifications require values of particular types. If 867 Certain format specifications require values of particular types. If
877you supply a value that doesn't fit the requirements, an error is 868you supply a value that doesn't fit the requirements, an error is
878signaled. 869signaled.
@@ -962,68 +953,33 @@ operation} error.
962@end group 953@end group
963@end example 954@end example
964 955
956 By default, format specifications correspond to successive values from
957@var{objects}. Thus, the first format specification in @var{string}
958uses the first such value, the second format specification uses the
959second such value, and so on. Any extra format specifications (those
960for which there are no corresponding values) cause an error. Any
961extra values to be formatted are ignored.
962
965@cindex field numbers in format spec 963@cindex field numbers in format spec
966 A specification can have a @dfn{field number}, which is a decimal 964 A format specification can have a @dfn{field number}, which is a
967number after the initial @samp{%}, followed by a literal dollar sign 965decimal number immediately after the initial @samp{%}, followed by a
968@samp{$}. If you provide a field number, then the argument to be 966literal dollar sign @samp{$}. It causes the format specification to
969printed corresponds to the given field number instead of the next 967convert the argument with the given number instead of the next
970argument. Field numbers start at 1. 968argument. Argument 1 is the argument just after the format.
971 969
972You can mix specifications with and without field numbers. A 970 You can mix specifications with and without field numbers. A
973specification without a field number that follows a specification with 971specification without a field number that follows a specification with
974a field number will convert the argument after the one specified by 972a field number will convert the argument after the one specified by
975the field number: 973the field number:
976 974
977@example 975@example
978(format "First argument %2$s, then %s, then %1$s" 1 2 3) 976(format "Argument %2$s, then %s, then %1$s" "x" "y" "z")
979 @result{} "First argument 2, then 3, then 1" 977 @result{} "Argument y, then z, then x"
980@end example
981
982You can't use field numbers in a @samp{%%} specification.
983
984@cindex field width
985@cindex padding
986 A specification can have a @dfn{width}, which is a decimal number
987between the @samp{%} and the specification character. If the printed
988representation of the object contains fewer characters than this
989width, @code{format} extends it with padding. The width specifier is
990ignored for the @samp{%%} specification. Any padding introduced by
991the width specifier normally consists of spaces inserted on the left:
992
993@example
994(format "%5d is padded on the left with spaces" 123)
995 @result{} " 123 is padded on the left with spaces"
996@end example
997
998@noindent
999If the width is too small, @code{format} does not truncate the
1000object's printed representation. Thus, you can use a width to specify
1001a minimum spacing between columns with no risk of losing information.
1002In the following two examples, @samp{%7s} specifies a minimum width
1003of 7. In the first case, the string inserted in place of @samp{%7s}
1004has only 3 letters, and needs 4 blank spaces as padding. In the
1005second case, the string @code{"specification"} is 13 letters wide but
1006is not truncated.
1007
1008@example
1009@group
1010(format "The word '%7s' has %d letters in it."
1011 "foo" (length "foo"))
1012 @result{} "The word ' foo' has 3 letters in it."
1013(format "The word '%7s' has %d letters in it."
1014 "specification" (length "specification"))
1015 @result{} "The word 'specification' has 13 letters in it."
1016@end group
1017@end example 978@end example
1018 979
1019If you want to use both a field number and a width, place the field
1020number before the width. For example, in @samp{%2$7s}, @samp{2} is
1021the field number and @samp{7} is the width.
1022
1023@cindex flags in format specifications 980@cindex flags in format specifications
1024 After the @samp{%} and before the optional width specifier, you can 981 After the @samp{%} and any field number, you can put certain
1025also put certain @dfn{flag characters}. The flag characters need to 982@dfn{flag characters}.
1026come directly after a potential field number.
1027 983
1028 The flag @samp{+} inserts a plus sign before a positive number, so 984 The flag @samp{+} inserts a plus sign before a positive number, so
1029that it always has a sign. A space character as flag inserts a space 985that 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}.
1048These specification characters accept the @samp{0} flag, but still pad 1004These specification characters accept the @samp{0} flag, but still pad
1049with @emph{spaces}. 1005with @emph{spaces}.
1050 1006
1051 The flag @samp{-} causes the padding inserted by the width 1007 The flag @samp{-} causes any padding inserted by the width,
1052specifier, if any, to be inserted on the right rather than the left. 1008if specified, to be inserted on the right rather than the left.
1053If both @samp{-} and @samp{0} are present, the @samp{0} flag is 1009If both @samp{-} and @samp{0} are present, the @samp{0} flag is
1054ignored. 1010ignored.
1055 1011
@@ -1067,9 +1023,44 @@ ignored.
1067@end group 1023@end group
1068@end example 1024@end example
1069 1025
1026@cindex field width
1027@cindex padding
1028 A specification can have a @dfn{width}, which is a decimal number
1029that appears after any field number and flags. If the printed
1030representation of the object contains fewer characters than this
1031width, @code{format} extends it with padding. The width is
1032ignored for the @samp{%%} specification. Any padding introduced by
1033the width normally consists of spaces inserted on the left:
1034
1035@example
1036(format "%5d is padded on the left with spaces" 123)
1037 @result{} " 123 is padded on the left with spaces"
1038@end example
1039
1040@noindent
1041If the width is too small, @code{format} does not truncate the
1042object's printed representation. Thus, you can use a width to specify
1043a minimum spacing between columns with no risk of losing information.
1044In the following two examples, @samp{%7s} specifies a minimum width
1045of 7. In the first case, the string inserted in place of @samp{%7s}
1046has only 3 letters, and needs 4 blank spaces as padding. In the
1047second case, the string @code{"specification"} is 13 letters wide but
1048is not truncated.
1049
1050@example
1051@group
1052(format "The word '%7s' has %d letters in it."
1053 "foo" (length "foo"))
1054 @result{} "The word ' foo' has 3 letters in it."
1055(format "The word '%7s' has %d letters in it."
1056 "specification" (length "specification"))
1057 @result{} "The word 'specification' has 13 letters in it."
1058@end group
1059@end example
1060
1070@cindex precision in format specifications 1061@cindex precision in format specifications
1071 All the specification characters allow an optional @dfn{precision} 1062 All the specification characters allow an optional @dfn{precision}
1072before the character (after the width, if present). The precision is 1063after the field number, flags and width, if present. The precision is
1073a decimal-point @samp{.} followed by a digit-string. For the 1064a decimal-point @samp{.} followed by a digit-string. For the
1074floating-point specifications (@samp{%e} and @samp{%f}), the 1065floating-point specifications (@samp{%e} and @samp{%f}), the
1075precision specifies how many digits following the decimal point to 1066precision specifies how many digits following the decimal point to
diff --git a/etc/NEWS b/etc/NEWS
index 1b098f98425..7972511f7a1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -369,7 +369,7 @@ libraries: 'find-library-other-window' and 'find-library-other-frame'.
369display of raw bytes from octal to hex. 369display of raw bytes from octal to hex.
370 370
371** You can now provide explicit field numbers in format specifiers. 371** You can now provide explicit field numbers in format specifiers.
372For example, '(format "%2$s %1$s" 1 2)' produces "2 1". 372For example, '(format "%2$s %1$s" "X" "Y")' produces "Y X".
373 373
374 374
375* Editing Changes in Emacs 26.1 375* Editing Changes in Emacs 26.1
diff --git a/src/editfns.c b/src/editfns.c
index 44341cef2d3..98187df5d97 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4046,9 +4046,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4046 field-width ::= [0-9]+ 4046 field-width ::= [0-9]+
4047 precision ::= '.' [0-9]* 4047 precision ::= '.' [0-9]*
4048 4048
4049 If a field-number is specified, it specifies the argument 4049 If present, a field-number specifies the argument number
4050 number to substitute. Otherwise, the next argument is 4050 to substitute. Otherwise, the next argument is taken.
4051 taken.
4052 4051
4053 If a field-width is specified, it specifies to which width 4052 If a field-width is specified, it specifies to which width
4054 the output should be padded with blanks, if the output 4053 the output should be padded with blanks, if the output
@@ -4058,28 +4057,20 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4058 digits to print after the '.' for floats, or the max. 4057 digits to print after the '.' for floats, or the max.
4059 number of chars to print from a string. */ 4058 number of chars to print from a string. */
4060 4059
4061 char *field_end; 4060 uintmax_t num;
4062 uintmax_t raw_field = strtoumax (format, &field_end, 10); 4061 char *num_end;
4063 bool has_field = false; 4062 if (c_isdigit (*format))
4064 if (c_isdigit (*format) && *field_end == '$') 4063 {
4065 { 4064 num = strtoumax (format, &num_end, 10);
4066 if (raw_field < 1 || raw_field >= PTRDIFF_MAX) 4065 if (*num_end == '$')
4067 { 4066 {
4068 /* doprnt doesn't support %.*s, so we need to copy 4067 if (num == 0)
4069 the field number string. */ 4068 error ("Invalid format field number 0");
4070 ptrdiff_t length = field_end - format; 4069 n = min (num, PTRDIFF_MAX);
4071 eassert (length > 0); 4070 n--;
4072 eassert (length < PTRDIFF_MAX); 4071 format = num_end + 1;
4073 char *field = SAFE_ALLOCA (length + 1); 4072 }
4074 memcpy (field, format, length); 4073 }
4075 field[length] = '\0';
4076 error ("Invalid field number `%s'", field);
4077 }
4078 has_field = true;
4079 /* n is incremented below. */
4080 n = raw_field - 1;
4081 format = field_end + 1;
4082 }
4083 4074
4084 bool minus_flag = false; 4075 bool minus_flag = false;
4085 bool plus_flag = false; 4076 bool plus_flag = false;
@@ -4104,11 +4095,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4104 space_flag &= ! plus_flag; 4095 space_flag &= ! plus_flag;
4105 zero_flag &= ! minus_flag; 4096 zero_flag &= ! minus_flag;
4106 4097
4107 char *num_end; 4098 num = strtoumax (format, &num_end, 10);
4108 uintmax_t raw_field_width = strtoumax (format, &num_end, 10); 4099 if (max_bufsize <= num)
4109 if (max_bufsize <= raw_field_width)
4110 string_overflow (); 4100 string_overflow ();
4111 ptrdiff_t field_width = raw_field_width; 4101 ptrdiff_t field_width = num;
4112 4102
4113 bool precision_given = *num_end == '.'; 4103 bool precision_given = *num_end == '.';
4114 uintmax_t precision = (precision_given 4104 uintmax_t precision = (precision_given
@@ -4123,13 +4113,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4123 memset (&discarded[format0 - format_start], 1, 4113 memset (&discarded[format0 - format_start], 1,
4124 format - format0 - (conversion == '%')); 4114 format - format0 - (conversion == '%'));
4125 if (conversion == '%') 4115 if (conversion == '%')
4126 { 4116 goto copy_char;
4127 if (has_field)
4128 /* FIXME: `error' doesn't appear to support `%%'. */
4129 error ("Field number specified together with `%c' conversion",
4130 '%');
4131 goto copy_char;
4132 }
4133 4117
4134 ++n; 4118 ++n;
4135 if (! (n < nargs)) 4119 if (! (n < nargs))
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index f76c6c9fd36..c5923aaafb1 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -186,13 +186,9 @@
186 (should (equal (should-error (format "a %999999$s b" 11)) 186 (should (equal (should-error (format "a %999999$s b" 11))
187 '(error "Not enough arguments for format string"))) 187 '(error "Not enough arguments for format string")))
188 (should (equal (should-error (format "a %$s b" 11)) 188 (should (equal (should-error (format "a %$s b" 11))
189 ;; FIXME: there shouldn't be two % in the error 189 '(error "Invalid format operation %$")))
190 ;; string!
191 '(error "Invalid format operation %%$")))
192 (should (equal (should-error (format "a %0$s b" 11)) 190 (should (equal (should-error (format "a %0$s b" 11))
193 '(error "Invalid field number `0'"))) 191 '(error "Invalid format field number 0")))
194 (should (equal 192 (should (equal (format "a %1$% %s b" 11) "a % 11 b")))
195 (should-error (format "a %1$% %s b" 11))
196 '(error "Field number specified together with `%' conversion"))))
197 193
198;;; editfns-tests.el ends here 194;;; editfns-tests.el ends here