aboutsummaryrefslogtreecommitdiffstats
path: root/src/bignum.c
diff options
context:
space:
mode:
authorPaul Eggert2018-08-31 00:25:07 -0700
committerPaul Eggert2018-08-31 00:28:58 -0700
commitdb2fed3bdfb351c3283e481829ce687931d27a3d (patch)
tree4f2674ec4f4fe450fd483132b9ddcca48f9eaf81 /src/bignum.c
parenta451c6ec12b7b024f347364becb10c49807513ed (diff)
downloademacs-db2fed3bdfb351c3283e481829ce687931d27a3d.tar.gz
emacs-db2fed3bdfb351c3283e481829ce687931d27a3d.zip
Several fixes for formatting bignums
* src/bignum.c: Include stdlib.h, for abs. (bignum_bufsize, bignum_to_c_string): New functions. * src/bignum.c (bignum_to_string): * src/print.c (print_vectorlike): Use them. * src/editfns.c (styled_format): Instead of having a separate buffer for sprintf (which does not work for bignums), just append to the main buffer. When formatting bignums, add support for the standard integer flags -, #, 0, + and space. Fix some comments. Capitalize properly when formatting bignums with %X. Use functions like c_isdigit rather than reinventing the wheel. Simplify computation of excess precision. * src/print.c: Do not include bignum.h; no longer needed. (print_vectorlike): Avoid recalculating string length. * test/src/editfns-tests.el (format-bignum): Test some of the above fixes.
Diffstat (limited to 'src/bignum.c')
-rw-r--r--src/bignum.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/src/bignum.c b/src/bignum.c
index 5dbfdb9319a..b18ceccb59d 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -23,6 +23,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
23 23
24#include "lisp.h" 24#include "lisp.h"
25 25
26#include <stdlib.h>
27
26/* Return the value of the Lisp bignum N, as a double. */ 28/* Return the value of the Lisp bignum N, as a double. */
27double 29double
28bignum_to_double (Lisp_Object n) 30bignum_to_double (Lisp_Object n)
@@ -223,18 +225,39 @@ bignum_to_uintmax (Lisp_Object x)
223 return v; 225 return v;
224} 226}
225 227
226/* Convert NUM to a base-BASE Lisp string. */ 228/* Yield an upper bound on the buffer size needed to contain a C
229 string representing the bignum NUM in base BASE. This includes any
230 preceding '-' and the terminating null. */
231ptrdiff_t
232bignum_bufsize (Lisp_Object num, int base)
233{
234 return mpz_sizeinbase (XBIGNUM (num)->value, base) + 2;
235}
236
237/* Store into BUF (of size SIZE) the value of NUM as a base-BASE string.
238 If BASE is negative, use upper-case digits in base -BASE.
239 Return the string's length.
240 SIZE must equal bignum_bufsize (NUM, abs (BASE)). */
241ptrdiff_t
242bignum_to_c_string (char *buf, ptrdiff_t size, Lisp_Object num, int base)
243{
244 eassert (bignum_bufsize (num, abs (base)) == size);
245 mpz_get_str (buf, base, XBIGNUM (num)->value);
246 ptrdiff_t n = size - 2;
247 return !buf[n - 1] ? n - 1 : n + !!buf[n];
248}
249
250/* Convert NUM to a base-BASE Lisp string.
251 If BASE is negative, use upper-case digits in base -BASE. */
227 252
228Lisp_Object 253Lisp_Object
229bignum_to_string (Lisp_Object num, int base) 254bignum_to_string (Lisp_Object num, int base)
230{ 255{
231 ptrdiff_t n = mpz_sizeinbase (XBIGNUM (num)->value, base) - 1; 256 ptrdiff_t size = bignum_bufsize (num, abs (base));
232 USE_SAFE_ALLOCA; 257 USE_SAFE_ALLOCA;
233 char *str = SAFE_ALLOCA (n + 3); 258 char *str = SAFE_ALLOCA (size);
234 mpz_get_str (str, base, XBIGNUM (num)->value); 259 ptrdiff_t len = bignum_to_c_string (str, size, num, base);
235 while (str[n]) 260 Lisp_Object result = make_unibyte_string (str, len);
236 n++;
237 Lisp_Object result = make_unibyte_string (str, n);
238 SAFE_FREE (); 261 SAFE_FREE ();
239 return result; 262 return result;
240} 263}