Package: emacs;
Reported by: Paul Eggert <eggert <at> cs.ucla.edu>
Date: Mon, 23 Jul 2018 19:14:02 UTC
Severity: normal
Tags: patch
Done: Paul Eggert <eggert <at> cs.ucla.edu>
Bug is archived. No further changes may be made.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Paul Eggert <eggert <at> cs.ucla.edu> To: bug-gnu-emacs <at> gnu.org Cc: Paul Eggert <eggert <at> cs.ucla.edu> Subject: [PATCH] %o and %x now format signed numbers Date: Mon, 23 Jul 2018 12:12:50 -0700
Treat integers as signed numbers when using the %o and %x format specifiers, instead of treating them as a machine-dependent two’s complement representation. This should make Emacs more machine-independent, and better-insulated for future changes involving bignums. The new compatibility variable ‘binary-as-unsigned’ enables the old machine-dependent behavior. This is a simplified version of the change proposed in: https://lists.gnu.org/r/emacs-devel/2018-07/msg00763.html I simplified that proposal by omitting bitwidth modifiers, as I could not find an any example uses in the Emacs source code that needed them and doing them correctly would have been quite a bit more work for apparently little benefit. * doc/lispref/strings.texi (Formatting Strings): * etc/NEWS: Document change. * src/editfns.c (styled_format): Treat integers as signed numbers even with %o and %x. Support the + and space flags with %o and %x, since they’re about signs. (syms_of_editfns): New compatibility variable binary-as-signed. * test/src/editfns-tests.el (read-large-integer): Test that maximal integers can be read after printing with all integer formats. (format-%o-invalid-float): Adjust test to match new behavior, which allows negative octal. --- doc/lispref/strings.texi | 6 +++--- etc/NEWS | 8 ++++++++ src/editfns.c | 42 ++++++++++++++++++++++++++++++++++----- test/src/editfns-tests.el | 11 +++++----- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 2fff3c7c75..582561fe42 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -922,7 +922,7 @@ Formatting Strings @item %o @cindex integer to octal Replace the specification with the base-eight representation of an -unsigned integer. The object can also be a nonnegative floating-point +integer. The object can also be a floating-point number that is formatted as an integer, dropping any fraction, if the integer does not exceed machine limits. @@ -935,8 +935,8 @@ Formatting Strings @itemx %X @cindex integer to hexadecimal Replace the specification with the base-sixteen representation of an -unsigned integer. @samp{%x} uses lower case and @samp{%X} uses upper -case. The object can also be a nonnegative floating-point number that +integer. @samp{%x} uses lower case and @samp{%X} uses upper +case. The object can also be a floating-point number that is formatted as an integer, dropping any fraction, if the integer does not exceed machine limits. diff --git a/etc/NEWS b/etc/NEWS index fc2a5d4c03..b735cf49b3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -697,6 +697,14 @@ To get the old behavior, set the new, experimental variable read-integer-overflow-as-float to t and please email 30408 <at> debbugs.gnu.org if you need that. (Bug#30408). ++++ +** Numbers formatted via %o or %x are now formatted as signed integers. +Formerly they were formatted using machine-dependent two's complement +representations. To get the old behavior, set the new, experimental +variable binary-as-unsigned to t and please email emacs-devel <at> gnu.org +if you need that. Because %o and %x now format signed integers, they +now support the + and space flags. + --- ** Some functions and variables obsolete since Emacs 22 have been removed: archive-mouse-extract, assoc-ignore-case, assoc-ignore-representation, diff --git a/src/editfns.c b/src/editfns.c index 09f836c3eb..a8fc499d63 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -4196,8 +4196,8 @@ contain either numbered or unnumbered %-sequences but not both, except that %% can be mixed with numbered %-sequences. The + flag character inserts a + before any nonnegative number, while a -space inserts a space before any nonnegative number; these flags only -affect %d, %e, %f, and %g sequences, and the + flag takes precedence. +space inserts a space before any nonnegative number; these flags +affect only numeric %-sequences, and the + flag takes precedence. The - and 0 flags affect the width specifier, as described below. The # flag means to use an alternate display form for %o, %x, %X, %e, @@ -4736,19 +4736,42 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) } else { - /* Don't sign-extend for octal or hex printing. */ uprintmax_t x; + bool negative; if (INTEGERP (arg)) - x = XUINT (arg); + { + EMACS_INT i; + if (binary_as_unsigned) + { + i = XUINT (arg); + negative = false; + } + else + { + i = XINT (arg); + negative = i < 0; + if (negative) + i = -i; + } + x = i; + } else { double d = XFLOAT_DATA (arg); double uprintmax = TYPE_MAXIMUM (uprintmax_t); + negative = d < 0; + if (negative) + d = -d; if (! (0 <= d && d < uprintmax + 1)) xsignal1 (Qoverflow_error, arg); x = d; + negative &= x != 0; } - sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); + sprintf_buf[0] = negative ? '-' : plus_flag ? '+' : ' '; + bool signedp = negative | plus_flag | space_flag; + sprintf_bytes = sprintf (sprintf_buf + signedp, + convspec, prec, x); + sprintf_bytes += signedp; } /* Now the length of the formatted item is known, except it omits @@ -5558,6 +5581,15 @@ functions if all the text being accessed has this property. */); DEFVAR_LISP ("operating-system-release", Voperating_system_release, doc: /* The release of the operating system Emacs is running on. */); + DEFVAR_BOOL ("binary-as-unsigned", + binary_as_unsigned, + doc: /* Non-nil means `format' %x and %o treat numbers as unsigned. +Nil (the default) means to treat them as signed. +Treating them as unsigned has machine-dependent results. + +This variable is experimental; email emacs-devel <at> gnu.org if you need it. */); + binary_as_unsigned = false; + defsubr (&Spropertize); defsubr (&Schar_equal); defsubr (&Sgoto_char); diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index c828000bb4..57a2081fc5 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el @@ -165,15 +165,16 @@ transpose-test-get-byte-positions :type 'overflow-error) (should-error (read (substring (format "%d" most-negative-fixnum) 1)) :type 'overflow-error) - (should-error (read (format "#x%x" most-negative-fixnum)) - :type 'overflow-error) - (should-error (read (format "#o%o" most-negative-fixnum)) - :type 'overflow-error) + (dolist (fmt '("%d" "%s" "#o%o" "#x%x")) + (dolist (val (list most-negative-fixnum (1+ most-negative-fixnum) + -1 0 1 + (1- most-positive-fixnum) most-positive-fixnum)) + (should (eq val (read (format fmt val)))))) (should-error (read (format "#32rG%x" most-positive-fixnum)) :type 'overflow-error)) (ert-deftest format-%o-invalid-float () - (should-error (format "%o" -1e-37) + (should-error (format "%o" -1e+INF) :type 'overflow-error)) ;; Bug#31938 -- 2.17.1
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.