unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Paul Eggert <eggert@cs.ucla.edu>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 32252-done@debbugs.gnu.org, eller.helmut@gmail.com
Subject: bug#32252: [PATCH] %o and %x now format signed numbers
Date: Thu, 26 Jul 2018 00:44:34 -0700	[thread overview]
Message-ID: <105453de-7910-f300-15d0-61e8dcae180a@cs.ucla.edu> (raw)
In-Reply-To: <83sh47tec7.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 699 bytes --]

Eli Zaretskii wrote:
>> Cc: eller.helmut@gmail.com, 32252@debbugs.gnu.org
>> From: Paul Eggert <eggert@cs.ucla.edu>
>>
>> That being said, it appears that there are enough qualms about the
>> change that I plan to install it with the new variable set the other
>> way. I.e., the default will be the current behavior and people can set
>> the new variable to get the new behavior, to try it this behavior out to
>> see whether they have problems.
> 
> Thank you.

OK, I installed the attached patch which does that, and am closing the bug 
report. I plan to run with binary-as-unsigned set to nil and to report any 
problems I encounter. I encourage others (particularly skeptics :-) to do the same.

[-- Attachment #2: 0001-o-and-x-can-now-format-signed-integers.txt --]
[-- Type: text/plain, Size: 8770 bytes --]

From 4a56ca5bbfabbb9c581828cd91648346e6b03844 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 26 Jul 2018 00:34:10 -0700
Subject: [PATCH] %o and %x can now format signed integers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Optionally treat integers as signed numbers with %o
and %x format specifiers, instead of treating them as
a machine-dependent two’s complement representation.
This option is more machine-independent, allows formats
like "#x%x" to be useful for reading later, and is
better-insulated for future changes involving bignums.
Setting the new variable ‘binary-as-unsigned’ to nil
enables the new behavior (Bug#32252).
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):
Document that %x and %o format negative integers in a
platform-dependent way.  Also, document how to format
numbers so that the same values can be read back in.
* etc/NEWS: Document the change.
* src/editfns.c (styled_format): Treat integers as signed
numbers even with %o and %x, if binary-as-unsigned is nil.
Support the + and space flags with %o and %x, since they’re
about signs.
(syms_of_editfns): New variable binary-as-unsigned.
* test/src/editfns-tests.el (read-large-integer):
Test that maximal integers can be read after printing
with all integer formats, if binary-as-unsigned is nil.
---
 doc/lispref/strings.texi  | 17 +++++++++++++++--
 etc/NEWS                  |  9 +++++++++
 src/editfns.c             | 43 ++++++++++++++++++++++++++++++++++++++-----
 test/src/editfns-tests.el | 10 ++++++----
 4 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 2fff3c7..3558f17 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -922,7 +922,8 @@ 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.  Negative integers are formatted in a platform-dependent
+way.  The object can also be a nonnegative floating-point
 number that is formatted as an integer, dropping any fraction, if the
 integer does not exceed machine limits.
 
@@ -935,7 +936,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
+integer.  Negative integers are formatted in a platform-dependent
+way.  @samp{%x} uses lower case and @samp{%X} uses upper
 case.  The object can also be a nonnegative floating-point number that
 is formatted as an integer, dropping any fraction, if the integer does
 not exceed machine limits.
@@ -1108,6 +1110,17 @@ Formatting Strings
 precision is what the local library functions of the @code{printf}
 family produce.
 
+@cindex formatting numbers for rereading later
+  If you plan to use @code{read} later on the formatted string to
+retrieve a copy of the formatted value, use a specification that lets
+@code{read} reconstruct the value.  To format numbers in this
+reversible way you can use @samp{%s} and @samp{%S}, to format just
+integers you can also use @samp{%d}, and to format just nonnegative
+integers you can also use @samp{#x%x} and @samp{#o%o}.  Other formats
+may be problematic; for example, @samp{%d} and @samp{%g} can mishandle
+NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o}
+can mishandle negative integers.  @xref{Input Functions}.
+
 @node Case Conversion
 @section Case Conversion in Lisp
 @cindex upper case
diff --git a/etc/NEWS b/etc/NEWS
index 995ceb6..089fc40 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -812,6 +812,15 @@ between two strings.
 ** 'print-quoted' now defaults to t, so if you want to see
 (quote x) instead of 'x you will have to bind it to nil where applicable.
 
++++
+** Numbers formatted via %o or %x may now be formatted as signed integers.
+This avoids problems in calls like (read (format "#x%x" -1)), and is
+more compatible with bignums, a planned feature.  To get this
+behavior, set the experimental variable binary-as-unsigned to nil,
+and if the new behavior breaks your code please email
+32252@debbugs.gnu.org.  Because %o and %x can now format signed
+integers, they now support the + and space flags.
+
 ** To avoid confusion caused by "smart quotes", the reader signals an
 error when reading Lisp symbols which begin with one of the following
 quotation characters: ‘’‛“”‟〞"'.  A symbol beginning with such a
diff --git a/src/editfns.c b/src/editfns.c
index 1d6040d..df25721 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,10 +4736,22 @@ 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);
+		    {
+		      if (binary_as_unsigned)
+			{
+			  x = XUINT (arg);
+			  negative = false;
+			}
+		      else
+			{
+			  EMACS_INT i = XINT (arg);
+			  negative = i < 0;
+			  x = negative ? -i : i;
+			}
+		    }
 		  else
 		    {
 		      double d = XFLOAT_DATA (arg);
@@ -4747,8 +4759,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 		      if (! (0 <= d && d < uprintmax + 1))
 			xsignal1 (Qoverflow_error, arg);
 		      x = d;
+		      negative = false;
 		    }
-		  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 +5575,22 @@ 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 integers as unsigned.
+This has machine-dependent results.  Nil means to treat integers as
+signed, which is portable; for example, if N is a negative integer,
+(read (format "#x%x") N) returns N only when this variable is nil.
+
+This variable is experimental; email 32252@debbugs.gnu.org if you need
+it to be non-nil.  */);
+  /* For now, default to true if bignums exist, false in traditional Emacs.  */
+#ifdef lisp_h_FIXNUMP
+  binary_as_unsigned = true;
+#else
+  binary_as_unsigned = false;
+#endif
+
   defsubr (&Spropertize);
   defsubr (&Schar_equal);
   defsubr (&Sgoto_char);
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index c828000..2951270 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -165,10 +165,12 @@ 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)
+  (let ((binary-as-unsigned nil))
+    (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))
 
-- 
2.7.4


  reply	other threads:[~2018-07-26  7:44 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-23 19:12 bug#32252: [PATCH] %o and %x now format signed numbers Paul Eggert
2018-07-23 19:48 ` Helmut Eller
2018-07-23 19:49 ` Drew Adams
2018-07-23 23:30   ` Paul Eggert
2018-07-24  1:20     ` Drew Adams
2018-07-24  2:04       ` Paul Eggert
2018-07-24  2:38         ` Eli Zaretskii
2018-07-24  2:44           ` Paul Eggert
2018-07-24 14:29             ` Eli Zaretskii
2018-07-24  4:15         ` Drew Adams
2018-07-23 23:39 ` Paul Eggert
2018-07-24  1:16   ` Drew Adams
2018-07-25  3:53     ` Richard Stallman
2018-07-25 21:56       ` Drew Adams
2018-07-27  3:20         ` Richard Stallman
2018-07-24  4:49   ` Helmut Eller
2018-07-24 14:22     ` Paul Eggert
2018-07-24 14:35       ` Andreas Schwab
2018-07-24 18:15       ` Helmut Eller
2018-07-25  0:50         ` Paul Eggert
2018-07-25  2:41           ` Eli Zaretskii
2018-07-25 17:21             ` Paul Eggert
2018-07-25 17:28               ` Eli Zaretskii
2018-07-26  7:44                 ` Paul Eggert [this message]
2018-07-26  8:04                   ` Helmut Eller
2018-07-26  8:16                     ` Paul Eggert
2018-07-25  6:58           ` Helmut Eller
2018-07-26  7:59             ` Paul Eggert
2018-07-26  8:43               ` Helmut Eller
2018-07-26  9:15                 ` Paul Eggert
2018-07-26  9:39                   ` Helmut Eller
2018-07-26  9:31                 ` Andreas Schwab
2018-07-26  9:40                   ` Robert Pluim
2018-07-26  9:56                   ` Helmut Eller
2018-07-26 16:55                     ` Paul Eggert
2018-07-26 17:16                       ` Helmut Eller
2018-07-26 17:50                         ` Paul Eggert
2018-07-26 18:35                           ` Helmut Eller
2018-07-26 21:07                             ` Paul Eggert
2018-07-24 18:27     ` Eli Zaretskii
2018-07-25  0:54       ` Paul Eggert
2018-07-25  8:09         ` Andreas Schwab
2018-07-25 20:16           ` Paul Eggert
2018-07-25 14:17         ` Eli Zaretskii
2018-07-25 23:33         ` Brett Gilio
2018-07-26  7:26           ` Paul Eggert
2018-07-24 16:26 ` Andy Moreton
2018-07-25 10:08 ` Andy Moreton
2018-07-26 12:52 ` Andy Moreton
2018-07-26 12:54 ` Andy Moreton
2018-07-26 17:18 ` Helmut Eller
2018-08-23  9:37 ` Helmut Eller
2022-07-04  1:03 ` bug#32252: i find binary-as-unsigned to be very helpful snickerbockers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=105453de-7910-f300-15d0-61e8dcae180a@cs.ucla.edu \
    --to=eggert@cs.ucla.edu \
    --cc=32252-done@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=eller.helmut@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).