diff options
| author | Philipp Stephani | 2017-06-01 00:09:43 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2017-06-02 00:22:13 +0200 |
| commit | 0dd1bbb0bb228acab21b8e16f2f2a0b5a17b19ab (patch) | |
| tree | 279fbd070724c1d04945b69db32eb69957274e72 /src | |
| parent | 404273aeacba39833ae3a38ce6764cc7a636e9d9 (diff) | |
| download | emacs-0dd1bbb0bb228acab21b8e16f2f2a0b5a17b19ab.tar.gz emacs-0dd1bbb0bb228acab21b8e16f2f2a0b5a17b19ab.zip | |
Implement field numbers in format strings
A field number explicitly specifies the argument to be formatted.
This is especially important for potential localization work, since
grammars of various languages dictate different word orders.
* src/editfns.c (Fformat): Update documentation.
(styled_format): Implement field numbers.
* doc/lispref/strings.texi (Formatting Strings): Document field numbers.
* lisp/emacs-lisp/bytecomp.el (byte-compile-format-warn): Adapt.
* test/src/editfns-tests.el (format-with-field): New unit test.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 55 |
1 files changed, 47 insertions, 8 deletions
diff --git a/src/editfns.c b/src/editfns.c index 89a67241044..44341cef2d3 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -48,6 +48,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 48 | #include <float.h> | 48 | #include <float.h> |
| 49 | #include <limits.h> | 49 | #include <limits.h> |
| 50 | 50 | ||
| 51 | #include <c-ctype.h> | ||
| 51 | #include <intprops.h> | 52 | #include <intprops.h> |
| 52 | #include <stdlib.h> | 53 | #include <stdlib.h> |
| 53 | #include <strftime.h> | 54 | #include <strftime.h> |
| @@ -3856,7 +3857,7 @@ The first argument is a format control string. | |||
| 3856 | The other arguments are substituted into it to make the result, a string. | 3857 | The other arguments are substituted into it to make the result, a string. |
| 3857 | 3858 | ||
| 3858 | The format control string may contain %-sequences meaning to substitute | 3859 | The format control string may contain %-sequences meaning to substitute |
| 3859 | the next available argument: | 3860 | the next available argument, or the argument explicitly specified: |
| 3860 | 3861 | ||
| 3861 | %s means print a string argument. Actually, prints any object, with `princ'. | 3862 | %s means print a string argument. Actually, prints any object, with `princ'. |
| 3862 | %d means print as signed number in decimal. | 3863 | %d means print as signed number in decimal. |
| @@ -3873,13 +3874,17 @@ the next available argument: | |||
| 3873 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. | 3874 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. |
| 3874 | Use %% to put a single % into the output. | 3875 | Use %% to put a single % into the output. |
| 3875 | 3876 | ||
| 3876 | A %-sequence may contain optional flag, width, and precision | 3877 | A %-sequence may contain optional field number, flag, width, and |
| 3877 | specifiers, as follows: | 3878 | precision specifiers, as follows: |
| 3878 | 3879 | ||
| 3879 | %<flags><width><precision>character | 3880 | %<field><flags><width><precision>character |
| 3880 | 3881 | ||
| 3881 | where flags is [+ #-0]+, width is [0-9]+, and precision is a literal | 3882 | where field is [0-9]+ followed by a literal dollar "$", flags is |
| 3882 | period "." followed by [0-9]+ | 3883 | [+ #-0]+, width is [0-9]+, and precision is a literal period "." |
| 3884 | followed by [0-9]+. | ||
| 3885 | |||
| 3886 | If field is given, it must be a one-based argument number; the given | ||
| 3887 | argument is substituted instead of the next one. | ||
| 3883 | 3888 | ||
| 3884 | The + flag character inserts a + before any positive number, while a | 3889 | The + flag character inserts a + before any positive number, while a |
| 3885 | space inserts a space before any positive number; these flags only | 3890 | space inserts a space before any positive number; these flags only |
| @@ -4032,14 +4037,19 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4032 | { | 4037 | { |
| 4033 | /* General format specifications look like | 4038 | /* General format specifications look like |
| 4034 | 4039 | ||
| 4035 | '%' [flags] [field-width] [precision] format | 4040 | '%' [field-number] [flags] [field-width] [precision] format |
| 4036 | 4041 | ||
| 4037 | where | 4042 | where |
| 4038 | 4043 | ||
| 4044 | field-number ::= [0-9]+ '$' | ||
| 4039 | flags ::= [-+0# ]+ | 4045 | flags ::= [-+0# ]+ |
| 4040 | field-width ::= [0-9]+ | 4046 | field-width ::= [0-9]+ |
| 4041 | precision ::= '.' [0-9]* | 4047 | precision ::= '.' [0-9]* |
| 4042 | 4048 | ||
| 4049 | If a field-number is specified, it specifies the argument | ||
| 4050 | number to substitute. Otherwise, the next argument is | ||
| 4051 | taken. | ||
| 4052 | |||
| 4043 | If a field-width is specified, it specifies to which width | 4053 | If a field-width is specified, it specifies to which width |
| 4044 | the output should be padded with blanks, if the output | 4054 | the output should be padded with blanks, if the output |
| 4045 | string is shorter than field-width. | 4055 | string is shorter than field-width. |
| @@ -4048,6 +4058,29 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4048 | digits to print after the '.' for floats, or the max. | 4058 | digits to print after the '.' for floats, or the max. |
| 4049 | number of chars to print from a string. */ | 4059 | number of chars to print from a string. */ |
| 4050 | 4060 | ||
| 4061 | char *field_end; | ||
| 4062 | uintmax_t raw_field = strtoumax (format, &field_end, 10); | ||
| 4063 | bool has_field = false; | ||
| 4064 | if (c_isdigit (*format) && *field_end == '$') | ||
| 4065 | { | ||
| 4066 | if (raw_field < 1 || raw_field >= PTRDIFF_MAX) | ||
| 4067 | { | ||
| 4068 | /* doprnt doesn't support %.*s, so we need to copy | ||
| 4069 | the field number string. */ | ||
| 4070 | ptrdiff_t length = field_end - format; | ||
| 4071 | eassert (length > 0); | ||
| 4072 | eassert (length < PTRDIFF_MAX); | ||
| 4073 | char *field = SAFE_ALLOCA (length + 1); | ||
| 4074 | memcpy (field, format, length); | ||
| 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 | |||
| 4051 | bool minus_flag = false; | 4084 | bool minus_flag = false; |
| 4052 | bool plus_flag = false; | 4085 | bool plus_flag = false; |
| 4053 | bool space_flag = false; | 4086 | bool space_flag = false; |
| @@ -4090,7 +4123,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4090 | memset (&discarded[format0 - format_start], 1, | 4123 | memset (&discarded[format0 - format_start], 1, |
| 4091 | format - format0 - (conversion == '%')); | 4124 | format - format0 - (conversion == '%')); |
| 4092 | if (conversion == '%') | 4125 | if (conversion == '%') |
| 4093 | goto copy_char; | 4126 | { |
| 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 | } | ||
| 4094 | 4133 | ||
| 4095 | ++n; | 4134 | ++n; |
| 4096 | if (! (n < nargs)) | 4135 | if (! (n < nargs)) |