aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-07-26 00:34:10 -0700
committerPaul Eggert2018-07-26 00:39:17 -0700
commit4a56ca5bbfabbb9c581828cd91648346e6b03844 (patch)
tree90b804ea4ec22a8b7be181f0b505b57c40a85c27 /src
parent19f5f7b19b0dcdae87476a3fd51c41f840b2b80f (diff)
downloademacs-4a56ca5bbfabbb9c581828cd91648346e6b03844.tar.gz
emacs-4a56ca5bbfabbb9c581828cd91648346e6b03844.zip
%o and %x can now format signed integers
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.
Diffstat (limited to 'src')
-rw-r--r--src/editfns.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 1d6040da3f7..df257219e8f 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4196,8 +4196,8 @@ contain either numbered or unnumbered %-sequences but not both, except
4196that %% can be mixed with numbered %-sequences. 4196that %% can be mixed with numbered %-sequences.
4197 4197
4198The + flag character inserts a + before any nonnegative number, while a 4198The + flag character inserts a + before any nonnegative number, while a
4199space inserts a space before any nonnegative number; these flags only 4199space inserts a space before any nonnegative number; these flags
4200affect %d, %e, %f, and %g sequences, and the + flag takes precedence. 4200affect only numeric %-sequences, and the + flag takes precedence.
4201The - and 0 flags affect the width specifier, as described below. 4201The - and 0 flags affect the width specifier, as described below.
4202 4202
4203The # flag means to use an alternate display form for %o, %x, %X, %e, 4203The # 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)
4736 } 4736 }
4737 else 4737 else
4738 { 4738 {
4739 /* Don't sign-extend for octal or hex printing. */
4740 uprintmax_t x; 4739 uprintmax_t x;
4740 bool negative;
4741 if (INTEGERP (arg)) 4741 if (INTEGERP (arg))
4742 x = XUINT (arg); 4742 {
4743 if (binary_as_unsigned)
4744 {
4745 x = XUINT (arg);
4746 negative = false;
4747 }
4748 else
4749 {
4750 EMACS_INT i = XINT (arg);
4751 negative = i < 0;
4752 x = negative ? -i : i;
4753 }
4754 }
4743 else 4755 else
4744 { 4756 {
4745 double d = XFLOAT_DATA (arg); 4757 double d = XFLOAT_DATA (arg);
@@ -4747,8 +4759,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4747 if (! (0 <= d && d < uprintmax + 1)) 4759 if (! (0 <= d && d < uprintmax + 1))
4748 xsignal1 (Qoverflow_error, arg); 4760 xsignal1 (Qoverflow_error, arg);
4749 x = d; 4761 x = d;
4762 negative = false;
4750 } 4763 }
4751 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); 4764 sprintf_buf[0] = negative ? '-' : plus_flag ? '+' : ' ';
4765 bool signedp = negative | plus_flag | space_flag;
4766 sprintf_bytes = sprintf (sprintf_buf + signedp,
4767 convspec, prec, x);
4768 sprintf_bytes += signedp;
4752 } 4769 }
4753 4770
4754 /* Now the length of the formatted item is known, except it omits 4771 /* 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. */);
5558 DEFVAR_LISP ("operating-system-release", Voperating_system_release, 5575 DEFVAR_LISP ("operating-system-release", Voperating_system_release,
5559 doc: /* The release of the operating system Emacs is running on. */); 5576 doc: /* The release of the operating system Emacs is running on. */);
5560 5577
5578 DEFVAR_BOOL ("binary-as-unsigned",
5579 binary_as_unsigned,
5580 doc: /* Non-nil means `format' %x and %o treat integers as unsigned.
5581This has machine-dependent results. Nil means to treat integers as
5582signed, which is portable; for example, if N is a negative integer,
5583(read (format "#x%x") N) returns N only when this variable is nil.
5584
5585This variable is experimental; email 32252@debbugs.gnu.org if you need
5586it to be non-nil. */);
5587 /* For now, default to true if bignums exist, false in traditional Emacs. */
5588#ifdef lisp_h_FIXNUMP
5589 binary_as_unsigned = true;
5590#else
5591 binary_as_unsigned = false;
5592#endif
5593
5561 defsubr (&Spropertize); 5594 defsubr (&Spropertize);
5562 defsubr (&Schar_equal); 5595 defsubr (&Schar_equal);
5563 defsubr (&Sgoto_char); 5596 defsubr (&Sgoto_char);