aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2018-03-08 20:55:55 -0800
committerPaul Eggert2018-03-08 20:57:01 -0800
commit80e145fc96765cc0a0f48ae2425294c8c92bce56 (patch)
tree25664bb27068449a082973736e35e1c43bee249b
parentcb0f6348956761880069e8ff7ed5086a177a521a (diff)
downloademacs-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.texi5
-rw-r--r--etc/NEWS7
-rw-r--r--src/editfns.c96
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
53chapter assume the minimum integer width of 30 bits. 53chapter 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
57initial sign and optional final period. An integer that is out of the 57of decimal digits with optional initial sign and optional
58final period. A decimal integer that is out of the
58Emacs range is treated as a floating-point number. 59Emacs range is treated as a floating-point number.
59 60
60@example 61@example
diff --git a/etc/NEWS b/etc/NEWS
index 07f6d04a740..14926ba2e3b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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
306integer, Emacs now signals an error if the number is too large for the
307implementation 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.
343If the optional third argument is non-nil, 'make-string' will produce 347If the optional third argument is non-nil, 'make-string' will produce
344a multibyte string even if its second argument is an ASCII character. 348a 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
351does 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
348are implemented in C using the Jansson library. 355are 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;