diff options
| author | Paul Eggert | 2017-05-31 22:09:39 -0700 |
|---|---|---|
| committer | Philipp Stephani | 2017-06-02 00:25:48 +0200 |
| commit | 53247108411a1e9d1aa5352c231fa049f3f918aa (patch) | |
| tree | bb550ccc67607f7f3cfc6a135b0838fff4b4c8c9 | |
| parent | 0dd1bbb0bb228acab21b8e16f2f2a0b5a17b19ab (diff) | |
| download | emacs-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.texi | 119 | ||||
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | src/editfns.c | 56 | ||||
| -rw-r--r-- | 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 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 | ||
| 868 | of the format specifications contain an explicit field number, the | ||
| 869 | format specifications correspond to successive values from | ||
| 870 | @var{objects}. Thus, the first format specification in @var{string} | ||
| 871 | uses the first such value, the second format specification uses the | ||
| 872 | second such value, and so on. Any extra format specifications (those | ||
| 873 | for which there are no corresponding values) cause an error. Any | ||
| 874 | extra 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 |
| 877 | you supply a value that doesn't fit the requirements, an error is | 868 | you supply a value that doesn't fit the requirements, an error is |
| 878 | signaled. | 869 | signaled. |
| @@ -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} | ||
| 958 | uses the first such value, the second format specification uses the | ||
| 959 | second such value, and so on. Any extra format specifications (those | ||
| 960 | for which there are no corresponding values) cause an error. Any | ||
| 961 | extra 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 |
| 967 | number after the initial @samp{%}, followed by a literal dollar sign | 965 | decimal number immediately after the initial @samp{%}, followed by a |
| 968 | @samp{$}. If you provide a field number, then the argument to be | 966 | literal dollar sign @samp{$}. It causes the format specification to |
| 969 | printed corresponds to the given field number instead of the next | 967 | convert the argument with the given number instead of the next |
| 970 | argument. Field numbers start at 1. | 968 | argument. Argument 1 is the argument just after the format. |
| 971 | 969 | ||
| 972 | You can mix specifications with and without field numbers. A | 970 | You can mix specifications with and without field numbers. A |
| 973 | specification without a field number that follows a specification with | 971 | specification without a field number that follows a specification with |
| 974 | a field number will convert the argument after the one specified by | 972 | a field number will convert the argument after the one specified by |
| 975 | the field number: | 973 | the 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 | |||
| 982 | You 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 | ||
| 987 | between the @samp{%} and the specification character. If the printed | ||
| 988 | representation of the object contains fewer characters than this | ||
| 989 | width, @code{format} extends it with padding. The width specifier is | ||
| 990 | ignored for the @samp{%%} specification. Any padding introduced by | ||
| 991 | the 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 | ||
| 999 | If the width is too small, @code{format} does not truncate the | ||
| 1000 | object's printed representation. Thus, you can use a width to specify | ||
| 1001 | a minimum spacing between columns with no risk of losing information. | ||
| 1002 | In the following two examples, @samp{%7s} specifies a minimum width | ||
| 1003 | of 7. In the first case, the string inserted in place of @samp{%7s} | ||
| 1004 | has only 3 letters, and needs 4 blank spaces as padding. In the | ||
| 1005 | second case, the string @code{"specification"} is 13 letters wide but | ||
| 1006 | is 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 | ||
| 1019 | If you want to use both a field number and a width, place the field | ||
| 1020 | number before the width. For example, in @samp{%2$7s}, @samp{2} is | ||
| 1021 | the 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 |
| 1025 | also put certain @dfn{flag characters}. The flag characters need to | 982 | @dfn{flag characters}. |
| 1026 | come 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 |
| 1029 | that it always has a sign. A space character as flag inserts a space | 985 | 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}. | |||
| 1048 | These specification characters accept the @samp{0} flag, but still pad | 1004 | These specification characters accept the @samp{0} flag, but still pad |
| 1049 | with @emph{spaces}. | 1005 | with @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, |
| 1052 | specifier, if any, to be inserted on the right rather than the left. | 1008 | if specified, to be inserted on the right rather than the left. |
| 1053 | If both @samp{-} and @samp{0} are present, the @samp{0} flag is | 1009 | If both @samp{-} and @samp{0} are present, the @samp{0} flag is |
| 1054 | ignored. | 1010 | ignored. |
| 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 | ||
| 1029 | that appears after any field number and flags. If the printed | ||
| 1030 | representation of the object contains fewer characters than this | ||
| 1031 | width, @code{format} extends it with padding. The width is | ||
| 1032 | ignored for the @samp{%%} specification. Any padding introduced by | ||
| 1033 | the 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 | ||
| 1041 | If the width is too small, @code{format} does not truncate the | ||
| 1042 | object's printed representation. Thus, you can use a width to specify | ||
| 1043 | a minimum spacing between columns with no risk of losing information. | ||
| 1044 | In the following two examples, @samp{%7s} specifies a minimum width | ||
| 1045 | of 7. In the first case, the string inserted in place of @samp{%7s} | ||
| 1046 | has only 3 letters, and needs 4 blank spaces as padding. In the | ||
| 1047 | second case, the string @code{"specification"} is 13 letters wide but | ||
| 1048 | is 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} |
| 1072 | before the character (after the width, if present). The precision is | 1063 | after the field number, flags and width, if present. The precision is |
| 1073 | a decimal-point @samp{.} followed by a digit-string. For the | 1064 | a decimal-point @samp{.} followed by a digit-string. For the |
| 1074 | floating-point specifications (@samp{%e} and @samp{%f}), the | 1065 | floating-point specifications (@samp{%e} and @samp{%f}), the |
| 1075 | precision specifies how many digits following the decimal point to | 1066 | precision specifies how many digits following the decimal point to |
| @@ -369,7 +369,7 @@ libraries: 'find-library-other-window' and 'find-library-other-frame'. | |||
| 369 | display of raw bytes from octal to hex. | 369 | display 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. |
| 372 | For example, '(format "%2$s %1$s" 1 2)' produces "2 1". | 372 | For 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 |