@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.
@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.
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
** '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
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,
}
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);
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
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);
: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))