diff options
| author | Paul Eggert | 2018-03-08 20:55:55 -0800 |
|---|---|---|
| committer | Paul Eggert | 2018-03-08 20:57:01 -0800 |
| commit | 80e145fc96765cc0a0f48ae2425294c8c92bce56 (patch) | |
| tree | 25664bb27068449a082973736e35e1c43bee249b | |
| parent | cb0f6348956761880069e8ff7ed5086a177a521a (diff) | |
| download | emacs-80e145fc96765cc0a0f48ae2425294c8c92bce56.tar.gz emacs-80e145fc96765cc0a0f48ae2425294c8c92bce56.zip | |
Avoid losing info when formatting integers
* doc/lispref/numbers.texi (Integer Basics): Clarify that
out-of-range integers are treated as floating point only when the
integers are decimal.
* etc/NEWS: Mention changes.
* src/editfns.c (styled_format): Use %.0f when formatting %d or %i
values outside machine integer range, to avoid losing info.
Signal an error for %o or %x values that are too large to be
formatted, to avoid losing info.
| -rw-r--r-- | doc/lispref/numbers.texi | 5 | ||||
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | src/editfns.c | 96 |
3 files changed, 51 insertions, 57 deletions
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index e692ee1cc2f..f1180cf754b 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi | |||
| @@ -53,8 +53,9 @@ but many machines provide a wider range. Many examples in this | |||
| 53 | chapter assume the minimum integer width of 30 bits. | 53 | chapter assume the minimum integer width of 30 bits. |
| 54 | @cindex overflow | 54 | @cindex overflow |
| 55 | 55 | ||
| 56 | The Lisp reader reads an integer as a sequence of digits with optional | 56 | The Lisp reader reads an integer as a nonempty sequence |
| 57 | initial sign and optional final period. An integer that is out of the | 57 | of decimal digits with optional initial sign and optional |
| 58 | final period. A decimal integer that is out of the | ||
| 58 | Emacs range is treated as a floating-point number. | 59 | Emacs range is treated as a floating-point number. |
| 59 | 60 | ||
| 60 | @example | 61 | @example |
| @@ -302,6 +302,10 @@ as new-style, bind the new variable 'force-new-style-backquotes' to t. | |||
| 302 | 'cl-struct-define' whose name clashes with a builtin type (e.g., | 302 | 'cl-struct-define' whose name clashes with a builtin type (e.g., |
| 303 | 'integer' or 'hash-table') now signals an error. | 303 | 'integer' or 'hash-table') now signals an error. |
| 304 | 304 | ||
| 305 | ** When formatting a floating-point number as an octal or hexadecimal | ||
| 306 | integer, Emacs now signals an error if the number is too large for the | ||
| 307 | implementation to format (Bug#30408). | ||
| 308 | |||
| 305 | 309 | ||
| 306 | * Lisp Changes in Emacs 27.1 | 310 | * Lisp Changes in Emacs 27.1 |
| 307 | 311 | ||
| @@ -343,6 +347,9 @@ remote systems, which support this check. | |||
| 343 | If the optional third argument is non-nil, 'make-string' will produce | 347 | If the optional third argument is non-nil, 'make-string' will produce |
| 344 | a multibyte string even if its second argument is an ASCII character. | 348 | a multibyte string even if its second argument is an ASCII character. |
| 345 | 349 | ||
| 350 | ** (format "%d" X) no longer mishandles a floating-point number X that | ||
| 351 | does not fit in a machine integer (Bug#30408). | ||
| 352 | |||
| 346 | ** New JSON parsing and serialization functions 'json-serialize', | 353 | ** New JSON parsing and serialization functions 'json-serialize', |
| 347 | 'json-insert', 'json-parse-string', and 'json-parse-buffer'. These | 354 | 'json-insert', 'json-parse-string', and 'json-parse-buffer'. These |
| 348 | are implemented in C using the Jansson library. | 355 | are implemented in C using the Jansson library. |
diff --git a/src/editfns.c b/src/editfns.c index 96bb271b2d6..3a34dd0980b 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -4563,32 +4563,30 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4563 | and with pM inserted for integer formats. | 4563 | and with pM inserted for integer formats. |
| 4564 | At most two flags F can be specified at once. */ | 4564 | At most two flags F can be specified at once. */ |
| 4565 | char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)]; | 4565 | char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)]; |
| 4566 | { | 4566 | char *f = convspec; |
| 4567 | char *f = convspec; | 4567 | *f++ = '%'; |
| 4568 | *f++ = '%'; | 4568 | /* MINUS_FLAG and ZERO_FLAG are dealt with later. */ |
| 4569 | /* MINUS_FLAG and ZERO_FLAG are dealt with later. */ | 4569 | *f = '+'; f += plus_flag; |
| 4570 | *f = '+'; f += plus_flag; | 4570 | *f = ' '; f += space_flag; |
| 4571 | *f = ' '; f += space_flag; | 4571 | *f = '#'; f += sharp_flag; |
| 4572 | *f = '#'; f += sharp_flag; | 4572 | *f++ = '.'; |
| 4573 | *f++ = '.'; | 4573 | *f++ = '*'; |
| 4574 | *f++ = '*'; | 4574 | if (float_conversion) |
| 4575 | if (float_conversion) | 4575 | { |
| 4576 | { | 4576 | if (INT_AS_LDBL) |
| 4577 | if (INT_AS_LDBL) | 4577 | { |
| 4578 | { | 4578 | *f = 'L'; |
| 4579 | *f = 'L'; | 4579 | f += INTEGERP (arg); |
| 4580 | f += INTEGERP (arg); | 4580 | } |
| 4581 | } | 4581 | } |
| 4582 | } | 4582 | else if (conversion != 'c') |
| 4583 | else if (conversion != 'c') | 4583 | { |
| 4584 | { | 4584 | memcpy (f, pMd, pMlen); |
| 4585 | memcpy (f, pMd, pMlen); | 4585 | f += pMlen; |
| 4586 | f += pMlen; | 4586 | zero_flag &= ! precision_given; |
| 4587 | zero_flag &= ! precision_given; | 4587 | } |
| 4588 | } | 4588 | *f++ = conversion; |
| 4589 | *f++ = conversion; | 4589 | *f = '\0'; |
| 4590 | *f = '\0'; | ||
| 4591 | } | ||
| 4592 | 4590 | ||
| 4593 | int prec = -1; | 4591 | int prec = -1; |
| 4594 | if (precision_given) | 4592 | if (precision_given) |
| @@ -4630,29 +4628,20 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4630 | } | 4628 | } |
| 4631 | else if (conversion == 'd' || conversion == 'i') | 4629 | else if (conversion == 'd' || conversion == 'i') |
| 4632 | { | 4630 | { |
| 4633 | /* For float, maybe we should use "%1.0f" | ||
| 4634 | instead so it also works for values outside | ||
| 4635 | the integer range. */ | ||
| 4636 | printmax_t x; | ||
| 4637 | if (INTEGERP (arg)) | 4631 | if (INTEGERP (arg)) |
| 4638 | x = XINT (arg); | 4632 | { |
| 4633 | printmax_t x = XINT (arg); | ||
| 4634 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); | ||
| 4635 | } | ||
| 4639 | else | 4636 | else |
| 4640 | { | 4637 | { |
| 4641 | double d = XFLOAT_DATA (arg); | 4638 | strcpy (f - pMlen - 1, "f"); |
| 4642 | if (d < 0) | 4639 | double x = XFLOAT_DATA (arg); |
| 4643 | { | 4640 | sprintf_bytes = sprintf (sprintf_buf, convspec, 0, x); |
| 4644 | x = TYPE_MINIMUM (printmax_t); | 4641 | char c0 = sprintf_buf[0]; |
| 4645 | if (x < d) | 4642 | bool signedp = ! ('0' <= c0 && c0 <= '9'); |
| 4646 | x = d; | 4643 | prec = min (precision, sprintf_bytes - signedp); |
| 4647 | } | ||
| 4648 | else | ||
| 4649 | { | ||
| 4650 | x = TYPE_MAXIMUM (printmax_t); | ||
| 4651 | if (d < x) | ||
| 4652 | x = d; | ||
| 4653 | } | ||
| 4654 | } | 4644 | } |
| 4655 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); | ||
| 4656 | } | 4645 | } |
| 4657 | else | 4646 | else |
| 4658 | { | 4647 | { |
| @@ -4663,22 +4652,19 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4663 | else | 4652 | else |
| 4664 | { | 4653 | { |
| 4665 | double d = XFLOAT_DATA (arg); | 4654 | double d = XFLOAT_DATA (arg); |
| 4666 | if (d < 0) | 4655 | double uprintmax = TYPE_MAXIMUM (uprintmax_t); |
| 4667 | x = 0; | 4656 | if (! (0 <= d && d < uprintmax + 1)) |
| 4668 | else | 4657 | xsignal1 (Qoverflow_error, arg); |
| 4669 | { | 4658 | x = d; |
| 4670 | x = TYPE_MAXIMUM (uprintmax_t); | ||
| 4671 | if (d < x) | ||
| 4672 | x = d; | ||
| 4673 | } | ||
| 4674 | } | 4659 | } |
| 4675 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); | 4660 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); |
| 4676 | } | 4661 | } |
| 4677 | 4662 | ||
| 4678 | /* Now the length of the formatted item is known, except it omits | 4663 | /* Now the length of the formatted item is known, except it omits |
| 4679 | padding and excess precision. Deal with excess precision | 4664 | padding and excess precision. Deal with excess precision |
| 4680 | first. This happens only when the format specifies | 4665 | first. This happens when the format specifies ridiculously |
| 4681 | ridiculously large precision. */ | 4666 | large precision, or when %d or %i formats a float that would |
| 4667 | ordinarily need fewer digits than a specified precision. */ | ||
| 4682 | ptrdiff_t excess_precision | 4668 | ptrdiff_t excess_precision |
| 4683 | = precision_given ? precision - prec : 0; | 4669 | = precision_given ? precision - prec : 0; |
| 4684 | ptrdiff_t leading_zeros = 0, trailing_zeros = 0; | 4670 | ptrdiff_t leading_zeros = 0, trailing_zeros = 0; |