diff options
-rw-r--r-- | ChangeLog | 100 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | arith.c | 139 | ||||
-rw-r--r-- | arith.h | 28 | ||||
-rwxr-xr-x | configure | 183 | ||||
-rw-r--r-- | dep.mk | 31 | ||||
-rw-r--r-- | depend.txr | 11 | ||||
-rw-r--r-- | eval.c | 2 | ||||
-rw-r--r-- | gc.c | 4 | ||||
-rw-r--r-- | hash.c | 18 | ||||
-rw-r--r-- | lib.c | 70 | ||||
-rw-r--r-- | lib.h | 24 | ||||
-rw-r--r-- | match.c | 54 | ||||
-rw-r--r-- | mpi-1.8.6.tar.gz | bin | 0 -> 154702 bytes | |||
-rw-r--r-- | mpi-patches/add-mp-hash | 48 | ||||
-rw-r--r-- | mpi-patches/add-mp-set-intptr | 77 | ||||
-rw-r--r-- | mpi-patches/add-mpi-toradix-with-case | 54 | ||||
-rw-r--r-- | mpi-patches/config-types | 120 | ||||
-rw-r--r-- | mpi-patches/export-mp-eq | 34 | ||||
-rw-r--r-- | mpi-patches/fix-mult-bug | 13 | ||||
-rw-r--r-- | mpi-patches/fix-warnings | 61 | ||||
-rw-r--r-- | mpi-patches/series | 8 | ||||
-rw-r--r-- | mpi-patches/use-txr-allocator | 70 | ||||
-rw-r--r-- | parser.l | 35 | ||||
-rw-r--r-- | parser.y | 7 | ||||
-rw-r--r-- | stream.c | 72 |
26 files changed, 1140 insertions, 137 deletions
@@ -1,3 +1,103 @@ +2011-12-09 Kaz Kylheku <kaz@kylheku.com> + + Bignum support, here we go! + + Bignums, based on Michael Fromberger's MPI library, are integrated + into the input syntax, stream output, equality testing, the garbage + collector, and hashing. + + The plus operation handles transitions between fixnums and bignums. + Other operations are still fixnum only. + + * Makefile (CFLAGS): Add mpi directory to include file search. + (OBJS): Include new arith.o module and all of MPI_OBJS. + (MPI_OBJS, MPI_OBJS_BASE): New variables. + + * configure (mpi_version, have_quilt, have_patch): New variables. + Script detects whether patch and quilt are available. Unpacks + mpi library, applies patches. Detects 128 bit integer type. + Records more information in config.h about the sizes of types. + + * dep.mk: Updated. + + * depend.txr: Make work with paths that have directory components. + + * eval.c (eval_init): Rename of nump to fixnump. + + * gc.c (finalize, mark_obj): Handle BGNUM case. + + * hash.c: (hash_c_str): Changed to return unsigned long + instead of long. + (equal_hash): Handle BGNUM case. + (eql_hash): Handle bignums with equal-hash, but other + objects as eq. + + * lib.c (num_s): Variable renamed to fixnum_s. + (bignum_s): New symbol variable. + (code2type): Follow rename of num_s. Handle BGNUM case. + (typeof): Follow rename of num_s. + (eql): Handle bignums using equal, and other types using eq. + (equal): Handle BGNUM case. + (chk_calloc): New function. + (c_num): Wording change in error message: is not a fixnum. + (nump): Renamed to fixnump. + (bignump): New function. + (plus): Function removed, reimplemented in arith.c. + (int_str): Handle integers which are too large for wcstol + using bignum conversion. Base 0 is no longer passed to + wcstol but converted to 10 because the special semantics + for 0 would be inconsistent for bignums. + (obj_init): Follow rename of num_s. Initialize bignum_s. + (obj_print, obj_pprint): Handle BGNUM. + (init): Call arith_init. + + * lib.h: Includes "mpi.h", as an exception to the project rule against + headers including headers. + (enum type): New enumeration member, BGNUM. + (struct bignum): New struct type. + (union obj): New member bn. + (mp): New inline function. + (num_s): Redeclared as fixnum_s. + (bignum_s, chk_calloc, bignump): Declared. + (nump): Redeclared as fixnump. + + * match.c (h_var, h_line, h_skip, h_coll, h_fun, format_field, v_skip, + v_freeform, v_collect, v_match_files): Follow nump to fixnump rename. + + * parser.l (NUM): New token type. Split up the parsing of identifiers + and numbers once again. But since every number is also lexically also + lexically an identifier, we put the action first. The action for + making numbers handles bignums. It produces object numbers, not + C numbers (change in yystype union). + + * parser.y (%union): num changes type from cnum to val. + + * stream.c (vformat): Handle bignums in numeric conversions. + + * arith.c: New file. + + * arith.h: New file. + + * mpi-1.8.6.tar.gz: New file. + + * mpi-patches/add-mp-hash: New file. + + * mpi-patches/add-mp-set-intptr: New file. + + * mpi-patches/add-mpi-toradix-with-case: New file. + + * mpi-patches/config-types: New file. + + * mpi-patches/export-mp-eq: New file. + + * mpi-patches/fix-mult-bug: New file. + + * mpi-patches/fix-warnings: New file. + + * mpi-patches/series: New file. + + * mpi-patches/use-txr-allocator: New file. + 2011-12-08 Kaz Kylheku <kaz@kylheku.com> C++ maintenance. @@ -30,14 +30,23 @@ include config.make CFLAGS := -I. -I$(top_srcdir) $(LANG_FLAGS) $(DIAG_FLAGS) \ $(OPT_FLAGS) $(DBG_FLAGS) $(PLATFORM_FLAGS) +CFLAGS += -I$(top_srcdir)/mpi-$(mpi_version) CFLAGS := $(filter-out $(REMOVE_FLAGS),$(CFLAGS)) ifneq ($(subst g++,@,$(notdir $(CC))),$(notdir $(CC))) CFLAGS := $(filter-out -Wmissing-prototypes -Wstrict-prototypes,$(CFLAGS)) endif +# TXR objects OBJS := txr.o lex.yy.o y.tab.o match.o lib.o regex.o gc.o unwind.o stream.o -OBJS += hash.o utf8.o filter.o debug.o eval.o +OBJS += arith.o hash.o utf8.o filter.o debug.o eval.o + +# MPI objects +MPI_OBJ_BASE=mpi.o mplogic.o + +MPI_OBJS := $(addprefix mpi-$(mpi_version)/,$(MPI_OBJ_BASE)) + +OBJS += $(MPI_OBJS) PROG := ./txr @@ -58,6 +67,9 @@ y.tab.c y.tab.h: parser.y # Bison-generated parser also tests for this lint define. y.tab.o: CFLAGS += -Dlint +$(MPI_OBJS): CFLAGS += -DXMALLOC=chk_malloc -DXREALLOC=chk_realloc +$(MPI_OBJS): CFLAGS += -DXCALLOC=chk_calloc -DXFREE=free + .PHONY: rebuild rebuild: clean $(PROG) diff --git a/arith.c b/arith.c new file mode 100644 index 00000000..a1026b37 --- /dev/null +++ b/arith.c @@ -0,0 +1,139 @@ +/* Copyright 2011 + * Kaz Kylheku <kaz@kylheku.com> + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wctype.h> +#include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <dirent.h> +#include <setjmp.h> +#include <wchar.h> +#include "config.h" +#include "lib.h" +#include "unwind.h" +#include "gc.h" +#include "arith.h" + +#define TAG_PAIR(A, B) ((A) << TAG_SHIFT | (B)) + +static mp_int NUM_MAX_MP; + +val make_bignum(void) +{ + val n = make_obj(); + n->bn.type = BGNUM; + mp_init(&n->bn.mp); + return n; +} + +static val normalize(val bignum) +{ + switch (mp_cmp_mag(mp(bignum), &NUM_MAX_MP)) { + case MP_EQ: + case MP_GT: + return bignum; + default: + { + cnum fixnum; + mp_get_intptr(mp(bignum), &fixnum); + return num(fixnum); + } + } +} + +val plus(val anum, val bnum) +{ + int tag_a = tag(anum); + int tag_b = tag(bnum); + + switch (TAG_PAIR(tag_a, tag_b)) { + case TAG_PAIR(TAG_NUM, TAG_NUM): + { + cnum a = c_num(anum); + cnum b = c_num(bnum); + cnum sum = a + b; + + if (sum < NUM_MIN || sum > NUM_MAX) { + val n = make_bignum(); + mp_set_intptr(mp(n), sum); + return n; + } + + return num(sum); + } + case TAG_PAIR(TAG_NUM, TAG_PTR): + { + val n; + type_check(bnum, BGNUM); + n = make_bignum(); + if (sizeof (int_ptr_t) <= sizeof (mp_digit)) { + mp_add_d(mp(bnum), c_num(anum), mp(n)); + } else { + mp_int tmp; + mp_init(&tmp); + mp_set_intptr(&tmp, c_num(anum)); + mp_add(mp(bnum), &tmp, mp(n)); + } + return normalize(n); + } + case TAG_PAIR(TAG_PTR, TAG_NUM): + { + val n; + type_check(anum, BGNUM); + n = make_bignum(); + if (sizeof (int_ptr_t) <= sizeof (mp_digit)) { + mp_add_d(mp(anum), c_num(bnum), mp(n)); + } else { + mp_int tmp; + mp_init(&tmp); + mp_set_intptr(&tmp, c_num(bnum)); + mp_add(mp(anum), &tmp, mp(n)); + } + return normalize(n); + } + case TAG_PAIR(TAG_PTR, TAG_PTR): + { + val n; + type_check(anum, BGNUM); + type_check(bnum, BGNUM); + n = make_bignum(); + mp_add(mp(anum), mp(bnum), mp(n)); + return normalize(n); + } + } + uw_throwf(error_s, lit("plus: invalid operands ~s ~s"), anum, bnum, nao); + abort(); +} + +void arith_init(void) +{ + mp_init(&NUM_MAX_MP); + mp_set_intptr(&NUM_MAX_MP, NUM_MAX); +} diff --git a/arith.h b/arith.h new file mode 100644 index 00000000..ba8fd958 --- /dev/null +++ b/arith.h @@ -0,0 +1,28 @@ +/* Copyright 2011 + * Kaz Kylheku <kaz@kylheku.com> + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +val make_bignum(void); +void arith_init(void); @@ -136,6 +136,9 @@ txr_dbg_opts=${txr_dbg_opts---gc-debug} valgrind=${valgrind-} lit_align=${lit_align-} extra_debugging=${extra_debugging-} +mpi_version=1.8.6 +have_quilt= +have_patch= # # If --help was given (or --help=<nonempty> or help=<nonempty>) then @@ -476,10 +479,10 @@ case "$top_srcdir" in esac if [ "$source_dir" != "." ] ; then - printf "symlinking Makefile -> $source_dir/Makefile\n" + printf "Symlinking Makefile -> $source_dir/Makefile\n" ln -sf "$source_dir/Makefile" . else - printf "warning: its recommended to build in a separate directory\n" + printf "Warning: its recommended to build in a separate directory\n" fi gen_config_make() @@ -527,6 +530,9 @@ compiler_prefix := $compiler_prefix # prefix for non-compiler toolchain commands tool_prefix := $tool_prefix +# MPI version +mpi_version := $mpi_version + CC := $cc LEX := $lex LEXLIB := $lexlib @@ -548,7 +554,7 @@ TXR_DBG_OPTS := $txr_dbg_opts # Before doing some other tests, we need a config.make # -printf "generating config.make ... " +printf "Generating config.make ... " gen_config_make printf "\n" @@ -616,17 +622,83 @@ else printf "none\n" fi +printf "Checking what C type we have for unsigned integers wider than \"long\" ... " + +for try_type in uint64 __uint64 "unsigned long long" ; do + cat > conftest.c <<! +$try_type value; +! + rm -f conftest.o + if make conftest.o > conftest.err 2>&1 ; then + ulonglong=$try_type + break + fi +done + +if [ -n "$ulonglong" ] ; then + printf '"%s"\n' "$ulonglong" + printf "#define HAVE_ULONGLONG_T 1\n" >> config.h + printf "typedef $ulonglong ulonglong_t;\n" >> config.h +else + printf "none\n" +fi + +printf "Checking what C type we have for integers wider than \"long long\" ... " + +for try_type in int128 int128_t __int128 __int128_t ; do + cat > conftest.c <<! +$try_type value; +! + rm -f conftest.o + if make conftest.o > conftest.err 2>&1 ; then + superlong=$try_type + break + fi +done + +if [ -n "$superlong" ] ; then + printf '"%s"\n' "$superlong" + printf "#define HAVE_SUPERLONG_T 1\n" >> config.h + printf "typedef $superlong superlong_t;\n" >> config.h +else + printf "none\n" +fi + +printf "Checking what C type we have for u. integers wider than \"long long\" ... " + +for try_type in uint128 uint128_t __uint128 __uint128_t ; do + cat > conftest.c <<! +$try_type value; +! + rm -f conftest.o + if make conftest.o > conftest.err 2>&1 ; then + usuperlong=$try_type + break + fi +done + +if [ -n "$usuperlong" ] ; then + printf '"%s"\n' "$usuperlong" + printf "#define HAVE_USUPERLONG_T 1\n" >> config.h + printf "typedef $usuperlong usuperlong_t;\n" >> config.h +else + printf "none\n" +fi + printf "Checking what C integer type can hold a pointer ... " if [ -z "$intptr" ] ; then cat > conftest.c <<! #include "config.h" -char sizeof_ptr[sizeof (char *)]; -char sizeof_short[sizeof (short)]; -char sizeof_int[sizeof (int)]; -char sizeof_long[sizeof (long)]; +char SIZEOF_PTR[sizeof (char *)]; +char SIZEOF_SHORT[sizeof (short)]; +char SIZEOF_INT[sizeof (int)]; +char SIZEOF_LONG[sizeof (long)]; #ifdef HAVE_LONGLONG_T -char sizeof_longlong_t[sizeof (longlong_t)]; +char SIZEOF_LONGLONG_T[sizeof (longlong_t)]; +#endif +#ifdef HAVE_SUPERLONG_T +char SIZEOF_SUPERLONG_T[sizeof (superlong_t)]; #endif ! rm -f conftest.o conftest.syms @@ -639,11 +711,12 @@ char sizeof_longlong_t[sizeof (longlong_t)]; exit 1 fi - sizeof_ptr=0 - sizeof_short=0 - sizeof_int=0 - sizeof_long=0 - sizeof_longlong_t=0 + SIZEOF_PTR=0 + SIZEOF_SHORT=0 + SIZEOF_INT=0 + SIZEOF_LONG=0 + SIZEOF_LONGLONG_T=0 + SIZEOF_SUPERLONG_T=0 while read symbol type offset size ; do size=$(( 0$size + 0 )) @@ -652,26 +725,28 @@ char sizeof_longlong_t[sizeof (longlong_t)]; size=$(( 0$offset + 0 )) fi case "$symbol" in - sizeof* ) + SIZEOF* ) eval $(printf "%s=%d\n" "$symbol" "$size") ;; esac + # retain all useful information! + printf "#define %s %s\n" "$symbol" "$size" >> config.h done < conftest.syms rm -f conftest.syms conftest.o - if [ $sizeof_ptr -eq 0 ] ; then + if [ $SIZEOF_PTR -eq 0 ] ; then printf "failed\n" exit 1 fi - if [ $sizeof_ptr -eq $sizeof_short ] ; then + if [ $SIZEOF_PTR -eq $SIZEOF_SHORT ] ; then intptr="short" - elif [ $sizeof_ptr -eq $sizeof_int ] ; then + elif [ $SIZEOF_PTR -eq $SIZEOF_INT ] ; then intptr="int" - elif [ $sizeof_ptr -eq $sizeof_long ] ; then + elif [ $SIZEOF_PTR -eq $SIZEOF_LONG ] ; then intptr="long" - elif [ $sizeof_ptr -eq $sizeof_long_long_t ] ; then + elif [ $SIZEOF_PTR -eq $SIZEOF_LONG_LONG_T ] ; then intptr="longlong_t" fi @@ -683,7 +758,7 @@ fi printf '"%s"\n' "$intptr" printf "typedef $intptr int_ptr_t;\n" >> config.h -intptr_max_expr="((((($intptr) 1 << $((sizeof_ptr * 8 - 2))) - 1) << 1) + 1)" +intptr_max_expr="((((($intptr) 1 << $((SIZEOF_PTR * 8 - 2))) - 1) << 1) + 1)" printf "#define INT_PTR_MAX %s\n" "$intptr_max_expr" >> config.h printf "#define INT_PTR_MIN (-INT_PTR_MAX)\n" >> config.h @@ -944,10 +1019,76 @@ rm -f conftest conftest.[co] conftest.{err,syms} rm -f conftest2 conftest[12].[oc] # +# What do we have for patch management. +# + +printf "Checking for quilt ... " + +if ! quilt --version > /dev/null 2>&1 ; then + printf "not found\n" +else + printf "found\n" + have_quilt=y +fi + +printf "Checking for patch ... " + +if ! patch --version > /dev/null 2>&1 ; then + printf "not found\n" + printf "\npatch tool required!\n\n" + exit 1 +else + printf "found\n" + have_patch=y +fi + +# +# Function to apply patches. +# +apply_patches() +{ + if ! [ -e patches/series ] ; then + echo "no patches" + return 0 + fi + + while read patch patchlevel ; do + case patch in + '#' ) continue ;; + * ) patch ${patchlevel:--p0} < $patch ;; + esac + done < patches/series +} + +# +# Try to extract MPI if not already. +# + +printf "Extracting MPI ... " + +if [ -e $top_srcdir/mpi-${mpi_version} ] ; then + printf "already extracted\n" +else + tar -C $top_srcdir -xzf $top_srcdir/mpi-${mpi_version}.tar.gz + printf "\n" + printf "Symlinking MPI patches ...\n" + ln -sf ../mpi-patches \ + $top_srcdir/mpi-${mpi_version}/patches + printf "Applying MPI patches ...\n" + if [ -n "$have_quilt" ] ; then + ( cd $top_srcdir/mpi-${mpi_version}/patches ; + if [ -e series ] ; then quilt push -a ; else echo "no patches" ; fi ) + else + ( cd $top_srcdir/mpi-${mpi_version} ; + apply_patches ) + fi +fi + +# # Regenerate config.make # -printf "regenerating config.make ... " +printf "Regenerating config.make ... " gen_config_make printf "\n" @@ -1,14 +1,17 @@ -txr.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/stream.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h $(top_srcdir)/parser.h $(top_srcdir)/match.h $(top_srcdir)/utf8.h $(top_srcdir)/debug.h $(top_srcdir)/txr.h -lex.yy.o: config.h $(top_srcdir)/lib.h y.tab.h $(top_srcdir)/gc.h $(top_srcdir)/stream.h $(top_srcdir)/utf8.h $(top_srcdir)/unwind.h $(top_srcdir)/hash.h $(top_srcdir)/parser.h -y.tab.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/regex.h $(top_srcdir)/utf8.h $(top_srcdir)/match.h $(top_srcdir)/hash.h $(top_srcdir)/parser.h -match.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h $(top_srcdir)/regex.h $(top_srcdir)/stream.h $(top_srcdir)/parser.h $(top_srcdir)/txr.h $(top_srcdir)/utf8.h $(top_srcdir)/filter.h $(top_srcdir)/hash.h $(top_srcdir)/debug.h $(top_srcdir)/match.h -lib.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/hash.h $(top_srcdir)/unwind.h $(top_srcdir)/stream.h $(top_srcdir)/utf8.h $(top_srcdir)/filter.h -regex.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/unwind.h $(top_srcdir)/regex.h $(top_srcdir)/txr.h -gc.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/stream.h $(top_srcdir)/hash.h $(top_srcdir)/txr.h $(top_srcdir)/gc.h -unwind.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/stream.h $(top_srcdir)/txr.h $(top_srcdir)/unwind.h -stream.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h $(top_srcdir)/stream.h $(top_srcdir)/utf8.h -hash.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h $(top_srcdir)/hash.h -utf8.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/unwind.h $(top_srcdir)/utf8.h -filter.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/hash.h $(top_srcdir)/unwind.h $(top_srcdir)/match.h $(top_srcdir)/filter.h $(top_srcdir)/gc.h -debug.o: config.h $(top_srcdir)/lib.h $(top_srcdir)/debug.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h $(top_srcdir)/stream.h $(top_srcdir)/parser.h -eval.o: $(top_srcdir)/lib.h config.h $(top_srcdir)/lib.h $(top_srcdir)/gc.h $(top_srcdir)/unwind.h +./txr.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./parser.h $(top_srcdir)/./match.h $(top_srcdir)/./utf8.h $(top_srcdir)/./debug.h $(top_srcdir)/./txr.h +./lex.yy.o: config.h $(top_srcdir)/./lib.h y.tab.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./unwind.h $(top_srcdir)/./hash.h $(top_srcdir)/./parser.h +./y.tab.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./regex.h $(top_srcdir)/./utf8.h $(top_srcdir)/./match.h $(top_srcdir)/./hash.h $(top_srcdir)/./eval.h $(top_srcdir)/./parser.h +./match.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./txr.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./eval.h $(top_srcdir)/./match.h +./lib.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./hash.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./eval.h +./regex.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./txr.h +./gc.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h $(top_srcdir)/./txr.h $(top_srcdir)/./eval.h $(top_srcdir)/./gc.h +./unwind.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./txr.h $(top_srcdir)/./unwind.h +./stream.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h +./arith.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h +./hash.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./hash.h +./utf8.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./utf8.h +./filter.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./hash.h $(top_srcdir)/./unwind.h $(top_srcdir)/./match.h $(top_srcdir)/./filter.h $(top_srcdir)/./gc.h +./debug.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./debug.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h +./eval.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./match.h $(top_srcdir)/./eval.h +mpi-1.8.6/mpi.o: $(top_srcdir)/mpi-1.8.6/../config.h $(top_srcdir)/mpi-1.8.6/mpi.h $(top_srcdir)/mpi-1.8.6/logtab.h +mpi-1.8.6/mplogic.o: $(top_srcdir)/mpi-1.8.6/../config.h $(top_srcdir)/mpi-1.8.6/mplogic.h @@ -1,17 +1,22 @@ @(next :args) @(collect) +@(cases) +@dir/@file.o +@(or) @file.o -@(next `@file.c`) +@(bind dir ".") +@(end) +@(next `@dir/@file.c`) @(collect) #include "@hdr" @(cases) @(bind hdr ("y.tab.h" "config.h")) @(bind header hdr) @(or) -@(bind header `$(top_srcdir)/@hdr`) +@(bind header `$(top_srcdir)/@dir/@hdr`) @(end) @(end) @(output) -@file.o:@(rep) @header@(end) +@dir/@file.o:@(rep) @header@(end) @(end) @(end) @@ -1156,7 +1156,7 @@ void eval_init(void) reg_fun(intern(lit("*"), user_package), func_n0v(mulv)); reg_fun(intern(lit("trunc"), user_package), func_n2(trunc)); reg_fun(intern(lit("mod"), user_package), func_n2(mod)); - reg_fun(intern(lit("numberp"), user_package), func_n1(nump)); + reg_fun(intern(lit("fixnump"), user_package), func_n1(fixnump)); reg_fun(intern(lit(">"), user_package), func_n1v(gtv)); reg_fun(intern(lit("<"), user_package), func_n1v(ltv)); @@ -209,6 +209,9 @@ static void finalize(val obj) return; case ENV: return; + case BGNUM: + mp_clear(mp(obj)); + return; } assert (0 && "corrupt type field"); @@ -262,6 +265,7 @@ tail_call: case CHR: case NUM: case LIT: + case BGNUM: return; case SYM: mark_obj(obj->s.name); @@ -75,7 +75,7 @@ static struct hash *reachable_weak_hashes; * We don't reduce the final result modulo a small prime, but leave it * as it is; let the hashing routines do their own reduction. */ -static long hash_c_str(const wchar_t *str) +static unsigned long hash_c_str(const wchar_t *str) { unsigned long h = 0; while (*str) { @@ -131,6 +131,8 @@ static cnum equal_hash(val obj) case LSTR: lazy_str_force(obj); return equal_hash(obj->ls.prefix); + case BGNUM: + return mp_hash(mp(obj)); case COBJ: return obj->co.ops->hash(obj); } @@ -140,12 +142,14 @@ static cnum equal_hash(val obj) static cnum eql_hash(val obj) { - switch (sizeof (mem_t *)) { - case 4: - return (((cnum) obj) & NUM_MAX) >> 4; - case 8: default: - return (((cnum) obj) & NUM_MAX) >> 5; - } + if (bignump(obj)) + return mp_hash(mp(obj)); + switch (sizeof (mem_t *)) { + case 4: + return (((cnum) obj) & NUM_MAX) >> 4; + case 8: default: + return (((cnum) obj) & NUM_MAX) >> 5; + } } cnum cobj_hash_op(val obj) @@ -33,6 +33,7 @@ #include <stdarg.h> #include <dirent.h> #include <setjmp.h> +#include <errno.h> #include <wchar.h> #include "config.h" #ifdef HAVE_GETENVIRONMENTSTRINGS @@ -41,6 +42,7 @@ #endif #include "lib.h" #include "gc.h" +#include "arith.h" #include "hash.h" #include "unwind.h" #include "stream.h" @@ -55,9 +57,9 @@ val packages; val system_package, keyword_package, user_package; -val null, t, cons_s, str_s, chr_s, num_s, sym_s, pkg_s, fun_s, vec_s; +val null, t, cons_s, str_s, chr_s, fixnum_s, sym_s, pkg_s, fun_s, vec_s; val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s, cptr_s; -val env_s; +val env_s, bignum_s; val var_s, expr_s, regex_s, chset_s, set_s, cset_s, wild_s, oneplus_s; val nongreedy_s, compiled_regex_s; val quote_s, qquote_s, unquote_s, splice_s; @@ -99,7 +101,7 @@ static val code2type(int code) case STR: return str_s; case LIT: return str_s; case CHR: return chr_s; - case NUM: return num_s; + case NUM: return fixnum_s; case SYM: return sym_s; case PKG: return pkg_s; case FUN: return fun_s; @@ -108,6 +110,7 @@ static val code2type(int code) case LSTR: return lstr_s; case COBJ: return cobj_s; case ENV: return env_s; + case BGNUM: return bignum_s; } return nil; } @@ -116,7 +119,7 @@ val typeof(val obj) { switch (tag(obj)) { case TAG_NUM: - return num_s; + return fixnum_s; case TAG_CHR: return chr_s; case TAG_LIT: @@ -494,6 +497,8 @@ val eql(val left, val right) /* eql is same as eq for now, but when we get bignums, eql will compare different bignum objects which are the same number as equal. */ + if (is_ptr(left) && type(left) == BGNUM) + return equal(left, right); return eq(left, right); } @@ -597,6 +602,10 @@ val equal(val left, val right) break; } return nil; + case BGNUM: + if (type(right) == BGNUM && mp_cmp(mp(left), mp(right)) == MP_EQ) + return t; + return nil; case COBJ: if (type(right) == COBJ) return left->co.ops->equal(left, right); @@ -619,6 +628,16 @@ mem_t *chk_malloc(size_t size) return ptr; } +mem_t *chk_calloc(size_t n, size_t size) +{ + mem_t *ptr = (mem_t *) calloc(n, size); + if (size && ptr == 0) { + ptr = (mem_t *) oom_realloc(0, size); + memset(ptr, 0, n * size); + } + return ptr; +} + mem_t *chk_realloc(mem_t *old, size_t size) { mem_t *newptr = (mem_t *) realloc(old, size); @@ -799,24 +818,18 @@ cnum c_num(val num) case TAG_CHR: case TAG_NUM: return ((cnum) num) >> TAG_SHIFT; default: - type_mismatch(lit("~s is not a number"), num, nao); + type_mismatch(lit("~s is not a fixnum"), num, nao); } } -val nump(val num) +val fixnump(val num) { return (is_num(num)) ? t : nil; } -val plus(val anum, val bnum) +val bignump(val num) { - cnum a = c_num(anum); - cnum b = c_num(bnum); - - numeric_assert (a <= 0 || b <= 0 || NUM_MAX - b >= a); - numeric_assert (a >= 0 || b >= 0 || NUM_MIN - b <= a); - - return num(a + b); + return (is_ptr(num) && type(num) == BGNUM) ? t : nil; } val plusv(val nlist) @@ -1449,12 +1462,27 @@ val int_str(val str, val base) const wchar_t *wcs = c_str(str); wchar_t *ptr; cnum b = c_num(base); + /* TODO: detect if we have wcstoll */ - long val = wcstol(wcs, &ptr, b); - if (val == 0 && ptr == wcs) + long value = wcstol(wcs, &ptr, b ? b : 10); + if (value == 0 && ptr == wcs) return nil; - numeric_assert (val >= NUM_MIN && val <= NUM_MAX); - return num(val); + if (((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE) || + (value < NUM_MIN || value > NUM_MAX)) + { + val bignum = make_bignum(); + unsigned char *ucs = utf8_dup_to_uc(wcs); + mp_err err = mp_read_radix(mp(bignum), ucs, b); + + free(ucs); /* TODO: make wchar_t version of mp_read_radix. */ + + if (err != MP_OKAY) + return nil; + + return bignum; + } + + return num(value); } val chrp(val chr) @@ -3057,7 +3085,7 @@ static void obj_init(void) cons_s = intern(lit("cons"), user_package); str_s = intern(lit("str"), user_package); chr_s = intern(lit("chr"), user_package); - num_s = intern(lit("num"), user_package); + fixnum_s = intern(lit("fixnum"), user_package); sym_s = intern(lit("sym"), user_package); pkg_s = intern(lit("pkg"), user_package); fun_s = intern(lit("fun"), user_package); @@ -3070,6 +3098,7 @@ static void obj_init(void) cobj_s = intern(lit("cobj"), user_package); cptr_s = intern(lit("cptr"), user_package); env_s = intern(lit("env"), user_package); + bignum_s = intern(lit("bignum"), user_package); var_s = intern(lit("var"), system_package); expr_s = intern(lit("expr"), system_package); regex_s = intern(lit("regex"), system_package); @@ -3241,6 +3270,7 @@ val obj_print(val obj, val out) } return obj; case NUM: + case BGNUM: format(out, lit("~s"), obj, nao); return obj; case SYM: @@ -3335,6 +3365,7 @@ val obj_pprint(val obj, val out) put_char(out, obj); return obj; case NUM: + case BGNUM: format(out, lit("~s"), obj, nao); return obj; case SYM: @@ -3384,6 +3415,7 @@ void init(const wchar_t *pn, mem_t *(*oom)(mem_t *, size_t), oom_realloc = oom; gc_init(stack_bottom); obj_init(); + arith_init(); uw_init(); stream_init(); eval_init(); @@ -24,6 +24,8 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#include "mpi.h" + typedef int_ptr_t cnum; #define TAG_SHIFT 2 @@ -37,7 +39,8 @@ typedef int_ptr_t cnum; typedef enum type { NUM = TAG_NUM, CHR = TAG_CHR, LIT = TAG_LIT, CONS, - STR, SYM, PKG, FUN, VEC, LCONS, LSTR, COBJ, ENV + STR, SYM, PKG, FUN, VEC, LCONS, LSTR, COBJ, ENV, + BGNUM } type_t; typedef enum functype @@ -183,6 +186,11 @@ struct env { val up_env; }; +struct bignum { + type_t type; + mp_int mp; +}; + union obj { struct any t; struct cons c; @@ -195,6 +203,7 @@ union obj { struct lazy_string ls; struct cobj co; struct env e; + struct bignum bn; }; INLINE cnum tag(val obj) { return ((cnum) obj) & TAG_MASK; } @@ -245,6 +254,11 @@ INLINE val num_fast(cnum n) return (val) ((n << TAG_SHIFT) | TAG_NUM); } +INLINE mp_int *mp(val bign) +{ + return &bign->bn.mp; +} + INLINE val chr(wchar_t ch) { return (val) (((cnum) ch << TAG_SHIFT) | TAG_CHR); @@ -259,9 +273,9 @@ INLINE val chr(wchar_t ch) #define lit(strlit) lit_noex(strlit) extern val keyword_package, system_package, user_package; -extern val null, t, cons_s, str_s, chr_s, num_s, sym_s, pkg_s, fun_s, vec_s; +extern val null, t, cons_s, str_s, chr_s, fixnum_s, sym_s, pkg_s, fun_s, vec_s; extern val stream_s, hash_s, hash_iter_s, lcons_s, lstr_s, cobj_s, cptr_s; -extern val env_s; +extern val env_s, bignum_s; extern val var_s, expr_s, regex_s, chset_s, set_s, cset_s, wild_s, oneplus_s; extern val nongreedy_s, compiled_regex_s; extern val quote_s, qquote_s, unquote_s, splice_s; @@ -328,6 +342,7 @@ val none_satisfy(val list, val pred, val key); val eql(val left, val right); val equal(val left, val right); mem_t *chk_malloc(size_t size); +mem_t *chk_calloc(size_t n, size_t size); mem_t *chk_realloc(mem_t *, size_t size); wchar_t *chk_strdup(const wchar_t *str); val cons(val car, val cdr); @@ -346,7 +361,8 @@ val proper_plist_to_alist(val list); val improper_plist_to_alist(val list, val boolean_keys); val num(cnum val); cnum c_num(val num); -val nump(val num); +val fixnump(val num); +val bignump(val num); val plus(val anum, val bnum); val plusv(val nlist); val minus(val anum, val bnum); @@ -462,7 +462,7 @@ static val h_var(match_line_ctx c, match_line_ctx *cout) val loc = source_loc(c.specline); c.specline = cons(cdr(pair), cons(pat, rest(c.specline))); rl(car(c.specline), loc); - } else if (nump(modifier)) { + } else if (fixnump(modifier)) { val past = plus(c.pos, modifier); if (length_str_lt(c.dataline, past) || lt(past, c.pos)) @@ -506,7 +506,7 @@ static val h_var(match_line_ctx c, match_line_ctx *cout) rl(car(c.specline), loc); goto repeat; } - } else if (nump(modifier)) { /* fixed field */ + } else if (fixnump(modifier)) { /* fixed field */ val past = plus(c.pos, modifier); if (length_str_lt(c.dataline, past) || lt(past, c.pos)) { @@ -625,8 +625,8 @@ static val h_skip(match_line_ctx c, match_line_ctx *cout) val elem = first(c.specline); val max = txeval(elem, second(elem), c.bindings); val min = txeval(elem, third(elem), c.bindings); - cnum cmax = nump(max) ? c_num(max) : 0; - cnum cmin = nump(min) ? c_num(min) : 0; + cnum cmax = fixnump(max) ? c_num(max) : 0; + cnum cmin = fixnump(min) ? c_num(min) : 0; val greedy = eq(max, greedy_k); val last_good_result = nil, last_good_pos = nil; @@ -703,14 +703,14 @@ static val h_coll(match_line_ctx c, match_line_ctx *cout) val chars = txeval(elem, getplist(args, chars_k), c.bindings); val have_vars; val vars = getplist_f(args, vars_k, &have_vars); - cnum cmax = nump(gap) ? c_num(gap) : (nump(max) ? c_num(max) : 0); - cnum cmin = nump(gap) ? c_num(gap) : (nump(min) ? c_num(min) : 0); + cnum cmax = fixnump(gap) ? c_num(gap) : (fixnump(max) ? c_num(max) : 0); + cnum cmin = fixnump(gap) ? c_num(gap) : (fixnump(min) ? c_num(min) : 0); cnum mincounter = cmin, maxcounter = 0; - cnum ctimax = nump(times) ? c_num(times) - : (nump(maxtimes) ? c_num(maxtimes) : 0); - cnum ctimin = nump(times) ? c_num(times) - : (nump(mintimes) ? c_num(mintimes) : 0); - cnum cchars = nump(chars) ? c_num(chars) : 0; + cnum ctimax = fixnump(times) ? c_num(times) + : (fixnump(maxtimes) ? c_num(maxtimes) : 0); + cnum ctimin = fixnump(times) ? c_num(times) + : (fixnump(mintimes) ? c_num(mintimes) : 0); + cnum cchars = fixnump(chars) ? c_num(chars) : 0; cnum timescounter = 0, charscounter = 0; val iter; @@ -1056,7 +1056,7 @@ static val h_fun(match_line_ctx c, match_line_ctx *cout) } } - if (nump(success)) + if (fixnump(success)) c.pos = success; } } @@ -1213,7 +1213,7 @@ static val format_field(val string_or_list, val modifier, val filter) for (; modifier; pop(&modifier)) { val item = first(modifier); - if (nump(item)) + if (fixnump(item)) n = item; if (regexp(item)) uw_throw(query_error_s, lit("format_field: regex modifier in output")); @@ -1717,8 +1717,8 @@ static val v_skip(match_files_ctx *c) val args = rest(first_spec); val max = txeval(skipspec, first(args), c->bindings); val min = txeval(skipspec, second(args), c->bindings); - cnum cmax = nump(max) ? c_num(max) : 0; - cnum cmin = nump(min) ? c_num(min) : 0; + cnum cmax = fixnump(max) ? c_num(max) : 0; + cnum cmin = fixnump(min) ? c_num(min) : 0; val greedy = eq(max, greedy_k); val last_good_result = nil; val last_good_line = num(0); @@ -1820,8 +1820,8 @@ static val v_freeform(match_files_ctx *c) return nil; } else { uses_or2; - val limit = or2(if2(nump(first(vals)), first(vals)), - if2(nump(second(vals)), second(vals))); + val limit = or2(if2(fixnump(first(vals)), first(vals)), + if2(fixnump(second(vals)), second(vals))); val term = or2(if2(stringp(first(vals)), first(vals)), if2(stringp(second(vals)), second(vals))); val ff_specline = first(c->spec); @@ -1836,7 +1836,7 @@ static val v_freeform(match_files_ctx *c) return nil; } - if (nump(success)) { + if (fixnump(success)) { c->data = lazy_str_get_trailing_list(ff_dataline, success); c->data_lineno = plus(c->data_lineno, num(1)); } @@ -2284,16 +2284,16 @@ static val v_collect(match_files_ctx *c) val lines = txeval(specline, getplist(args, lines_k), c->bindings); val have_vars; val vars = getplist_f(args, vars_k, &have_vars); - cnum cmax = nump(gap) ? c_num(gap) : (nump(max) ? c_num(max) : 0); - cnum cmin = nump(gap) ? c_num(gap) : (nump(min) ? c_num(min) : 0); + cnum cmax = fixnump(gap) ? c_num(gap) : (fixnump(max) ? c_num(max) : 0); + cnum cmin = fixnump(gap) ? c_num(gap) : (fixnump(min) ? c_num(min) : 0); cnum mincounter = cmin, maxcounter = 0; - cnum ctimax = nump(times) ? c_num(times) - : (nump(maxtimes) ? c_num(maxtimes) : 0); - cnum ctimin = nump(times) ? c_num(times) - : (nump(mintimes) ? c_num(mintimes) : 0); + cnum ctimax = fixnump(times) ? c_num(times) + : (fixnump(maxtimes) ? c_num(maxtimes) : 0); + cnum ctimin = fixnump(times) ? c_num(times) + : (fixnump(mintimes) ? c_num(mintimes) : 0); cnum timescounter = 0, linescounter = 0; - cnum ctimes = nump(times) ? c_num(times) : 0; - cnum clines = nump(lines) ? c_num(lines) : 0; + cnum ctimes = fixnump(times) ? c_num(times) : 0; + cnum clines = fixnump(lines) ? c_num(lines) : 0; val iter; if (gap && (max || min)) @@ -3215,7 +3215,7 @@ repeat_spec_same_data: match_line(ml_all(c.bindings, specline, dataline, zero, c.data_lineno, first(c.files)))); - if (nump(success) && c_num(success) < c_num(length_str(dataline))) { + if (fixnump(success) && c_num(success) < c_num(length_str(dataline))) { debuglf(specline, lit("spec only matches line to position ~a: ~a"), success, dataline, nao); return nil; diff --git a/mpi-1.8.6.tar.gz b/mpi-1.8.6.tar.gz Binary files differnew file mode 100644 index 00000000..43791a77 --- /dev/null +++ b/mpi-1.8.6.tar.gz diff --git a/mpi-patches/add-mp-hash b/mpi-patches/add-mp-hash new file mode 100644 index 00000000..8a2cd585 --- /dev/null +++ b/mpi-patches/add-mp-hash @@ -0,0 +1,48 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 14:10:41.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 14:26:02.000000000 -0800 +@@ -1960,6 +1960,30 @@ + + /* }}} */ + ++unsigned long mp_hash(mp_int *a) ++{ ++ unsigned long hash = 0; ++ int ix; ++ for (ix = 0; ix < USED(a); ix++) { ++ mp_digit d = DIGIT(a, ix); ++#if SIZEOF_LONG < MP_DIGIT_SIZE ++ int j; ++ for (j = 0; j < MP_DIGIT_SIZE / SIZEOF_LONG; j++) { ++ hash ^= d; ++ d >> (SIZEOF_LONG * CHAR_BIT); ++ } ++#elif SIZEOF_LONG == MP_DIGIT_SIZE ++ hash ^= d; ++#else ++ hash <<= MP_DIGIT_BITS; ++ hash ^= d; ++#endif ++ } ++ if (SIGN(a) == MP_NEG) ++ hash = (hash << 16 | hash >> (SIZEOF_LONG * CHAR_BIT - 16)); ++ return hash; ++} ++ + /*------------------------------------------------------------------------*/ + /* {{{ Number theoretic functions */ + +Index: mpi-1.8.6/mpi.h +=================================================================== +--- mpi-1.8.6.orig/mpi.h 2011-12-09 14:10:41.000000000 -0800 ++++ mpi-1.8.6/mpi.h 2011-12-09 14:10:41.000000000 -0800 +@@ -165,6 +165,8 @@ + int mp_isodd(mp_int *a); + int mp_iseven(mp_int *a); + ++unsigned long mp_hash(mp_int *a); ++ + /*------------------------------------------------------------------------*/ + /* Number theoretic */ + diff --git a/mpi-patches/add-mp-set-intptr b/mpi-patches/add-mp-set-intptr new file mode 100644 index 00000000..a5d50a33 --- /dev/null +++ b/mpi-patches/add-mp-set-intptr @@ -0,0 +1,77 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 13:52:26.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 13:56:19.000000000 -0800 +@@ -528,6 +528,59 @@ + + /* }}} */ + ++mp_err mp_set_intptr(mp_int *mp, int_ptr_t z) ++{ ++ if (sizeof z > sizeof (mp_digit)) { ++ int ix, shift; ++ unsigned long v = z > 0 ? z : -z; ++ const int nd = (sizeof v + sizeof (mp_digit) - 1) / sizeof (mp_digit); ++ ++ ARGCHK(mp != NULL, MP_BADARG); ++ ++ mp_zero(mp); ++ ++ if(z == 0) ++ return MP_OKAY; /* shortcut for zero */ ++ ++ s_mp_grow(mp, nd); ++ ++ USED(mp) = nd; ++ ++ for (ix = 0, shift = 0; ix < nd; ix++, shift += MP_DIGIT_BIT) ++ { ++ DIGIT(mp, ix) = (v >> shift) & MP_DIGIT_MAX; ++ } ++ ++ if(z < 0) ++ SIGN(mp) = MP_NEG; ++ ++ return MP_OKAY; ++ } ++ ++ mp_set(mp, z); ++ return MP_OKAY; ++} ++ ++/* ++ * No checks here: assumes that the mp is in range! ++ */ ++mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z) ++{ ++ int_ptr_t out = 0; ++ ++#if MP_DIGIT_SIZE < SIZEOF_PTR ++ int ix; ++ int nd = USED(mp); ++ for (ix = 0; ix < nd; ix++, out <<= MP_DIGIT_BIT) ++ out = DIGIT(mp, ix); ++#else ++ out = DIGIT(mp, 0); ++#endif ++ ++ *z = (SIGN(mp) == MP_NEG) ? -out : out; ++ return MP_OKAY; ++} ++ + /*------------------------------------------------------------------------*/ + /* {{{ Digit arithmetic */ + +Index: mpi-1.8.6/mpi.h +=================================================================== +--- mpi-1.8.6.orig/mpi.h 2011-12-09 13:49:20.000000000 -0800 ++++ mpi-1.8.6/mpi.h 2011-12-09 13:56:19.000000000 -0800 +@@ -94,6 +94,8 @@ + void mp_zero(mp_int *mp); + void mp_set(mp_int *mp, mp_digit d); + mp_err mp_set_int(mp_int *mp, long z); ++mp_err mp_set_intptr(mp_int *mp, int_ptr_t z); ++mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z); + + /*------------------------------------------------------------------------*/ + /* Single digit arithmetic */ diff --git a/mpi-patches/add-mpi-toradix-with-case b/mpi-patches/add-mpi-toradix-with-case new file mode 100644 index 00000000..6fe9c191 --- /dev/null +++ b/mpi-patches/add-mpi-toradix-with-case @@ -0,0 +1,54 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 19:16:58.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 19:19:23.000000000 -0800 +@@ -2624,9 +2624,9 @@ + + /* }}} */ + +-/* {{{ mp_toradix(mp, str, radix) */ ++/* {{{ mp_toradix_case(mp, str, radix, low) */ + +-mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) ++mp_err mp_toradix_case(mp_int *mp, unsigned char *str, int radix, int low) + { + int ix, pos = 0; + +@@ -2657,7 +2657,7 @@ + } + + /* Generate digits, use capital letters */ +- ch = s_mp_todigit(rem, radix, 0); ++ ch = s_mp_todigit(rem, radix, low); + + str[pos++] = ch; + } +@@ -2685,10 +2685,15 @@ + + return MP_OKAY; + +-} /* end mp_toradix() */ ++} /* end mp_toradix_case() */ + + /* }}} */ + ++mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) ++{ ++ return mp_toradix_case(mp, str, radix, 0); ++} ++ + /* {{{ mp_char2value(ch, r) */ + + int mp_char2value(char ch, int r) +Index: mpi-1.8.6/mpi.h +=================================================================== +--- mpi-1.8.6.orig/mpi.h 2011-12-09 19:16:58.000000000 -0800 ++++ mpi-1.8.6/mpi.h 2011-12-09 19:28:38.000000000 -0800 +@@ -213,6 +213,7 @@ + int mp_radix_size(mp_int *mp, int radix); + int mp_value_radix_size(int num, int qty, int radix); + mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix); ++mp_err mp_toradix_case(mp_int *mp, unsigned char *str, int radix, int low); + + int mp_char2value(char ch, int r); + diff --git a/mpi-patches/config-types b/mpi-patches/config-types new file mode 100644 index 00000000..78b672b8 --- /dev/null +++ b/mpi-patches/config-types @@ -0,0 +1,120 @@ +Index: mpi-1.8.6/mpi-types.h +=================================================================== +--- mpi-1.8.6.orig/mpi-types.h 2011-12-09 09:00:59.000000000 -0800 ++++ mpi-1.8.6/mpi-types.h 2011-12-09 14:09:59.000000000 -0800 +@@ -1,17 +1,54 @@ +-/* Type definitions generated by 'types.pl' */ ++/* ++ * Universal. We can further tweak these by making them ++ * bitfields inside the mp_int struct. ++ */ ++typedef int mp_sign; ++typedef int mp_size; + +-typedef char mp_sign; +-typedef unsigned short mp_digit; /* 2 byte type */ +-typedef unsigned int mp_word; /* 4 byte type */ +-typedef unsigned int mp_size; +-typedef int mp_err; ++/* ++ * Universal. Does not need platform configuration. ++ */ ++typedef int mp_err; + +-#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) +-#define MP_DIGIT_MAX USHRT_MAX +-#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) +-#define MP_WORD_MAX UINT_MAX ++#if HAVE_USUPERLONG_T && HAVE_ULONGLONG_T && \ ++ SIZEOF_SUPERLONG_T / 2 == SIZEOF_LONGLONG_T && \ ++ SIZEOF_PTR >= SIZEOF_LONGLONG_T ++ typedef ulonglong_t mp_digit; ++ typedef usuperlong_t mp_word; ++ #define MP_DIGIT_SIZE SIZEOF_LONGLONG_T ++ #define DIGIT_FMT "%" #SIZEOF_SUPERLONG_T "llx" ++#elif HAVE_ULONGLONG_T && SIZEOF_LONGLONG_T / 2 == SIZEOF_LONG && \ ++ SIZEOF_PTR >= SIZEOF_LONG ++ typedef unsigned long mp_digit; ++ typedef ulonglong_t mp_word; ++ #define MP_DIGIT_SIZE SIZEOF_LONG_T ++ #define DIGIT_FMT "%" #SIZEOF_LONGLONG_T "lx" ++#elif HAVE_ULONGLONG_T && SIZEOF_LONGLONG_T / 2 == SIZEOF_INT && \ ++ SIZEOF_PTR >= SIZEOF_INT ++ typedef unsigned int mp_digit; ++ typedef ulonglong_t mp_word; ++ #define MP_DIGIT_SIZE SIZEOF_INT ++ #define DIGIT_FMT "%" #SIZEOF_LONGLONG_T "lx" ++#elif SIZEOF_LONG / 2 == SIZEOF_INT && SIZEOF_PTR >= SIZEOF_INT ++ typedef unsigned int mp_digit; ++ typedef unsigned long mp_word; ++ #define MP_DIGIT_SIZE SIZEOF_INT ++ #define DIGIT_FMT "%" #SIZEOF_LONG "x" ++#elif SIZEOF_INT / 2 == SIZEOF_SHORT ++ typedef unsigned short mp_digit; ++ typedef unsigned int mp_word; ++ #define DIGIT_FMT "%" #SIZEOF_INT "x" ++#elif SIZEOF_SHORT == 2 ++ typedef unsigned char mp_digit; ++ typedef unsigned short mp_word; ++ #define DIGIT_FMT "%" #SIZEOF_SHORT "x" ++#else ++ #error Failure to configure MPI types on this target platform ++#endif + +-#define RADIX (MP_DIGIT_MAX+1) ++#define MP_DIGIT_BIT ((int) (CHAR_BIT*sizeof(mp_digit))) ++#define MP_DIGIT_MAX ((mp_digit) -1) ++#define MP_WORD_BIT ((int) (CHAR_BIT*sizeof(mp_word))) ++#define MP_WORD_MAX ((mp_word) -1) + +-#define MP_DIGIT_SIZE 2 +-#define DIGIT_FMT "%04X" ++#define RADIX (((mp_word) MP_DIGIT_MAX) + 1) +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 09:00:59.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 14:10:29.000000000 -0800 +@@ -9,6 +9,7 @@ + $Id: mpi.c,v 1.1 2004/02/08 04:29:29 sting Exp $ + */ + ++#include "../config.h" + #include "mpi.h" + #include <stdlib.h> + #include <string.h> +Index: mpi-1.8.6/mplogic.c +=================================================================== +--- mpi-1.8.6.orig/mplogic.c 2011-12-09 09:00:59.000000000 -0800 ++++ mpi-1.8.6/mplogic.c 2011-12-09 14:10:29.000000000 -0800 +@@ -9,6 +9,7 @@ + $Id: mplogic.c,v 1.1 2004/02/08 04:29:29 sting Exp $ + */ + ++#include "../config.h" + #include "mplogic.h" + #include <stdlib.h> + +Index: mpi-1.8.6/mpprime.c +=================================================================== +--- mpi-1.8.6.orig/mpprime.c 2011-12-09 09:00:59.000000000 -0800 ++++ mpi-1.8.6/mpprime.c 2011-12-09 09:01:01.000000000 -0800 +@@ -10,6 +10,7 @@ + $Id: mpprime.c,v 1.1 2004/02/08 04:29:29 sting Exp $ + */ + ++#include "../config.h" + #include "mpprime.h" + #include <stdlib.h> + +Index: mpi-1.8.6/mprsa.c +=================================================================== +--- mpi-1.8.6.orig/mprsa.c 2011-12-09 09:00:59.000000000 -0800 ++++ mpi-1.8.6/mprsa.c 2011-12-09 09:01:01.000000000 -0800 +@@ -11,6 +11,7 @@ + $Id: mprsa.c,v 1.1 2004/02/08 04:29:29 sting Exp $ + */ + ++#include "../config.h" + #include "mprsa.h" + #include <stdlib.h> + #include <string.h> diff --git a/mpi-patches/export-mp-eq b/mpi-patches/export-mp-eq new file mode 100644 index 00000000..e9ea7a49 --- /dev/null +++ b/mpi-patches/export-mp-eq @@ -0,0 +1,34 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 13:56:19.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 13:56:23.000000000 -0800 +@@ -86,14 +86,6 @@ + + /* }}} */ + +-/* {{{ Comparison constants */ +- +-#define MP_LT -1 +-#define MP_EQ 0 +-#define MP_GT 1 +- +-/* }}} */ +- + /* {{{ Constant strings */ + + /* Constant strings returned by mp_strerror() */ +Index: mpi-1.8.6/mpi.h +=================================================================== +--- mpi-1.8.6.orig/mpi.h 2011-12-09 13:56:19.000000000 -0800 ++++ mpi-1.8.6/mpi.h 2011-12-09 13:56:23.000000000 -0800 +@@ -42,6 +42,10 @@ + #define MP_UNDEF -5 /* answer is undefined */ + #define MP_LAST_CODE MP_UNDEF + ++#define MP_LT -1 ++#define MP_EQ 0 ++#define MP_GT 1 ++ + #include "mpi-types.h" + + /* Included for compatibility... */ diff --git a/mpi-patches/fix-mult-bug b/mpi-patches/fix-mult-bug new file mode 100644 index 00000000..691f3334 --- /dev/null +++ b/mpi-patches/fix-mult-bug @@ -0,0 +1,13 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-09 21:11:31.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-09 21:12:09.000000000 -0800 +@@ -3272,7 +3272,7 @@ + } + + for(ix = 0; ix < max; ix++) { +- w = (dp[ix] * d) + k; ++ w = (dp[ix] * (mp_word) d) + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + } diff --git a/mpi-patches/fix-warnings b/mpi-patches/fix-warnings new file mode 100644 index 00000000..c35e4ead --- /dev/null +++ b/mpi-patches/fix-warnings @@ -0,0 +1,61 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-08 21:03:20.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-08 21:05:04.000000000 -0800 +@@ -2401,7 +2401,7 @@ + int ix; + + d = *dp; +- for(ix = 0; ix < sizeof(mp_digit); ++ix) { ++ for(ix = 0; ix < (int) sizeof(mp_digit); ++ix) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; +@@ -2598,10 +2598,10 @@ + /* Reverse the digits and sign indicator */ + ix = 0; + while(ix < pos) { +- char tmp = str[ix]; ++ char tmp2 = str[ix]; + + str[ix] = str[pos]; +- str[pos] = tmp; ++ str[pos] = tmp2; + ++ix; + --pos; + } +@@ -2952,10 +2952,10 @@ + void s_mp_mod_2d(mp_int *mp, mp_digit d) + { + unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); +- unsigned int ix; ++ int ix; + mp_digit dmask, *dp = DIGITS(mp); + +- if(ndig >= USED(mp)) ++ if((int) ndig >= USED(mp)) + return; + + /* Flush all the bits above 2^d in its digit */ +Index: mpi-1.8.6/mplogic.c +=================================================================== +--- mpi-1.8.6.orig/mplogic.c 2011-12-08 21:03:20.000000000 -0800 ++++ mpi-1.8.6/mplogic.c 2011-12-08 21:05:16.000000000 -0800 +@@ -290,7 +290,7 @@ + for(ix = 0; ix < USED(a); ix++) { + cur = DIGIT(a, ix); + +- for(db = 0; db < sizeof(mp_digit); db++) { ++ for(db = 0; db < (int) sizeof(mp_digit); db++) { + reg = (cur >> (CHAR_BIT * db)) & UCHAR_MAX; + + nset += bitc[reg]; +@@ -319,7 +319,7 @@ + for(ix = 0; ix < USED(a); ix++) { + cur = DIGIT(a, ix); + +- for(db = 0; db < sizeof(mp_digit); db++) { ++ for(db = 0; db < (int) sizeof(mp_digit); db++) { + reg = (cur >> (CHAR_BIT * db)) & UCHAR_MAX; + + nset += bitc[UCHAR_MAX - reg]; diff --git a/mpi-patches/series b/mpi-patches/series new file mode 100644 index 00000000..71aa73ba --- /dev/null +++ b/mpi-patches/series @@ -0,0 +1,8 @@ +config-types +fix-warnings +use-txr-allocator +add-mp-set-intptr +export-mp-eq +add-mp-hash +add-mpi-toradix-with-case +fix-mult-bug diff --git a/mpi-patches/use-txr-allocator b/mpi-patches/use-txr-allocator new file mode 100644 index 00000000..2f85a574 --- /dev/null +++ b/mpi-patches/use-txr-allocator @@ -0,0 +1,70 @@ +Index: mpi-1.8.6/mpi.c +=================================================================== +--- mpi-1.8.6.orig/mpi.c 2011-12-08 22:17:15.000000000 -0800 ++++ mpi-1.8.6/mpi.c 2011-12-08 22:27:07.000000000 -0800 +@@ -15,6 +15,11 @@ + #include <string.h> + #include <ctype.h> + ++typedef unsigned char mem_t; ++extern mem_t *chk_malloc(size_t size); ++extern mem_t *chk_calloc(size_t n, size_t size); ++extern mem_t *chk_realloc(mem_t *, size_t size); ++ + #if MP_DEBUG + #include <stdio.h> + +@@ -154,7 +159,7 @@ + #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) + #endif /* MP_MEMCPY */ + +- #define s_mp_alloc(nb, ni) calloc(nb, ni) ++ #define s_mp_alloc(nb, ni) chk_calloc(nb, ni) + #define s_mp_free(ptr) {if(ptr) free(ptr);} + #endif /* MP_MACRO */ + +@@ -282,7 +287,7 @@ + { + ARGCHK(mp != NULL && prec > 0, MP_BADARG); + +- if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) ++ if((DIGITS(mp) = (mp_digit *) s_mp_alloc(prec, sizeof(mp_digit))) == NULL) + return MP_MEM; + + SIGN(mp) = MP_ZPOS; +@@ -312,7 +317,7 @@ + if(mp == from) + return MP_OKAY; + +- if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) ++ if((DIGITS(mp) = (mp_digit *) s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); +@@ -358,7 +363,7 @@ + s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); + + } else { +- if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) ++ if((tmp = (mp_digit *) s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), tmp, USED(from)); +@@ -2670,7 +2675,7 @@ + /* Set min to next nearest default precision block size */ + min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; + +- if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) ++ if((tmp = (mp_digit *) s_mp_alloc(min, sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(mp), tmp, USED(mp)); +@@ -2757,7 +2762,7 @@ + /* Allocate ni records of nb bytes each, and return a pointer to that */ + void *s_mp_alloc(size_t nb, size_t ni) + { +- return calloc(nb, ni); ++ return chk_calloc(nb, ni); + + } /* end s_mp_alloc() */ + #endif @@ -146,6 +146,7 @@ static wchar_t num_esc(char *num) %option noinput SYM [a-zA-Z0-9_]+ +NUM [+\-]?[0-9]+ NSCHR [a-zA-Z0-9!$%&*+\-<=>?\\^_~] NSYM {NSCHR}({NSCHR}|#)* TOK :?{SYM} @@ -170,12 +171,19 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} %% -<SPECIAL>{TOK} | -<NESTED>{NTOK} { - cnum val; - char *errp; +<SPECIAL,NESTED>{NUM} { + val str = string_own(utf8_dup_from(yytext)); + if (yy_top_state() == INITIAL + || yy_top_state() == QSILIT) + yy_pop_state(); + yylval.num = int_str(str, num(10)); + return NUMBER; + } + +<SPECIAL>{TOK} | +<NESTED>{NTOK} { if (yy_top_state() == INITIAL || yy_top_state() == QSILIT) yy_pop_state(); @@ -188,28 +196,9 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} yylval.lexeme = utf8_dup_from(yytext + 1); return METAVAR; default: - break; - } - - errno = 0; - - val = strtol(yytext, &errp, 10); - - if (*errp != 0) { - /* not a number */ yylval.lexeme = utf8_dup_from(yytext); return IDENT; } - - if ((val == LONG_MAX || val == LONG_MIN) - && errno == ERANGE) - yyerror("numeric overflow in token"); - - if (val < NUM_MIN || val > NUM_MAX) - yyerror("numeric overflow in token"); - - yylval.num = val; - return NUMBER; } <SPECIAL>\({WS}all{WS}\) { @@ -60,7 +60,8 @@ static val parsed_spec; wchar_t *lexeme; union obj *val; wchar_t chr; - cnum num, lineno; + union obj *num; + cnum lineno; } %token <lexeme> SPACE TEXT IDENT KEYWORD METAVAR @@ -71,7 +72,7 @@ static val parsed_spec; %token <lineno> ERRTOK /* deliberately not used in grammar */ %token <lineno> HASH_BACKSLASH -%token <num> NUMBER +%token <val> NUMBER %token <chr> REGCHAR LITCHAR %token <chr> METAPAR SPLICE @@ -646,7 +647,7 @@ expr : IDENT { $$ = rl(intern(string_own($1), nil), | METAVAR { $$ = list(var_s, intern(string_own($1), nil), nao); rl($$, num(lineno)); } - | NUMBER { $$ = num($1); } + | NUMBER { $$ = $1; } | list { $$ = $1; } | vector { $$ = $1; } | meta_expr { $$ = $1; } @@ -837,11 +837,11 @@ val vformat(val stream, val fmtstr, va_list vl) int left = 0, zeropad = 0; cnum value; void *ptr; - char num_buf[64]; for (;;) { val obj; wchar_t ch = *fmt++; + char num_buf[64], *pnum = num_buf; switch (state) { case vf_init: @@ -951,24 +951,45 @@ val vformat(val stream, val fmtstr, va_list vl) switch (ch) { case 'x': obj = va_arg(vl, val); - value = c_num(obj); - sprintf(num_buf, num_fmt->hex, value); + if (bignump(obj)) { + int nchars = mp_radix_size(mp(obj), 16); + if (nchars >= (int) sizeof (num_buf)) + pnum = (char *) chk_malloc(nchars + 1); + mp_toradix_case(mp(obj), (unsigned char *) pnum, 16, 1); + } else { + value = c_num(obj); + sprintf(num_buf, num_fmt->hex, value); + } goto output_num; case 'X': obj = va_arg(vl, val); - value = c_num(obj); - sprintf(num_buf, num_fmt->HEX, value); + if (bignump(obj)) { + int nchars = mp_radix_size(mp(obj), 16); + if (nchars >= (int) sizeof (num_buf)) + pnum = (char *) chk_malloc(nchars + 1); + mp_toradix_case(mp(obj), (unsigned char *) pnum, 16, 0); + } else { + value = c_num(obj); + sprintf(num_buf, num_fmt->HEX, value); + } goto output_num; case 'o': obj = va_arg(vl, val); - value = c_num(obj); - sprintf(num_buf, num_fmt->oct, value); + if (bignump(obj)) { + int nchars = mp_radix_size(mp(obj), 8); + if (nchars >= (int) sizeof (num_buf)) + pnum = (char *) chk_malloc(nchars + 1); + mp_toradix(mp(obj), (unsigned char *) pnum, 8); + } else { + value = c_num(obj); + sprintf(num_buf, num_fmt->oct, value); + } goto output_num; case 'a': obj = va_arg(vl, val); if (obj == nao) goto premature; - if (nump(obj)) { + if (fixnump(obj)) { value = c_num(obj); sprintf(num_buf, num_fmt->dec, value); goto output_num; @@ -976,6 +997,12 @@ val vformat(val stream, val fmtstr, va_list vl) if (!vformat_str(stream, obj, width, left, precision)) return nil; continue; + } else if (bignump(obj)) { + int nchars = mp_radix_size(mp(obj), 10); + if (nchars >= (int) sizeof (num_buf)) + pnum = (char *) chk_malloc(nchars + 1); + mp_toradix(mp(obj), (unsigned char *) pnum, 10); + goto output_num; } obj_pprint(obj, stream); continue; @@ -983,12 +1010,24 @@ val vformat(val stream, val fmtstr, va_list vl) obj = va_arg(vl, val); if (obj == nao) goto premature; - if (nump(obj)) { + if (fixnump(obj)) { value = c_num(obj); sprintf(num_buf, num_fmt->dec, value); if (!vformat_num(stream, num_buf, 0, 0, 0, 0)) return nil; continue; + } else if (bignump(obj)) { + int nchars = mp_radix_size(mp(obj), 10); + val res; + if (nchars >= (int) sizeof (num_buf)) + pnum = (char *) chk_malloc(nchars + 1); + mp_toradix(mp(obj), (unsigned char *) pnum, 10); + res = vformat_num(stream, pnum, 0, 0, 0, 0); + if (pnum != num_buf) + free(pnum); + if (!res) + return nil; + continue; } obj_print(obj, stream); continue; @@ -1001,11 +1040,16 @@ val vformat(val stream, val fmtstr, va_list vl) default: abort(); output_num: - if (!vformat_num(stream, num_buf, width, left, - precision ? 0 : zeropad, - precision ? precision : 1)) - return nil; - continue; + { + val res = vformat_num(stream, pnum, width, left, + precision ? 0 : zeropad, + precision ? precision : 1); + if (pnum != num_buf) + free(pnum); + if (!res) + return nil; + continue; + } } continue; } |