[Nickle] nickle: Branch 'master' - 10 commits

Keith Packard keithp at keithp.com
Wed Mar 15 14:19:20 PDT 2017


New commits:
commit c100536369045242614f71a44e09c2c3df5359ab
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 15 09:25:17 2017 -0700

    Adapt tests to new automake requirements
    
    Automake now has a separate variable for the program to run the test
    scripts with, and breaks if you try to embed that in the
    TESTS_ENVIRONMENT variable, which used to be how this was done.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/examples/smlng/Makefile.am b/examples/smlng/Makefile.am
index 32c198e..78a079d 100644
--- a/examples/smlng/Makefile.am
+++ b/examples/smlng/Makefile.am
@@ -15,7 +15,8 @@ exampledir=$(pkgdatadir)/examples/smlng
 
 example_DATA=$(NICKLEFILES) COPYING
 
-TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir):$(top_srcdir)/$(subdir) $(top_builddir)/nickle < $(top_srcdir)/$(subdir)/data.sgml > /dev/null
+TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir):$(top_srcdir)/$(subdir)
+LOG_COMPILER=$(top_builddir)/nickle < $(top_srcdir)/$(subdir)/data.sgml
 
 TESTS=test.5c
 
diff --git a/examples/turtle/Makefile.am b/examples/turtle/Makefile.am
index 96595e9..0cbda02 100644
--- a/examples/turtle/Makefile.am
+++ b/examples/turtle/Makefile.am
@@ -15,8 +15,9 @@ example_DATA=$(NICKLEFILES) snowflake.tex COPYING
 
 EXTRA_DIST=$(example_DATA) COPYING
 
-TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir):$(top_srcdir)/$(subdir) $(top_builddir)/nickle
+TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir):$(top_srcdir)/$(subdir)
 TESTS=snowflake.5c
+LOG_COMPILER=$(top_builddir)/nickle
 
 CLEANFILES=snowflake.eepic snowflake.aux snowflake.dvi snowflake.log
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 3a6dcce..683e5a8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,8 +20,9 @@ TABLES=math-tables.5c
 
 CLEANFILES=$(TABLES)
 
-TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir) ../nickle
+TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir)
 TESTS=$(check_SCRIPTS)
+LOG_COMPILER=$(top_builddir)/nickle
 
 EXTRA_DIST=$(check_SCRIPTS)
 
commit 334780afcc76da6e158aeefb5e7f3df533e5aaf2
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 15 09:24:20 2017 -0700

    Use 'G' format for elements when printing arrays in 'g' format
    
    This restricts array printing to just recurse one level.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/array.c b/array.c
index 2c762f0..aa096ad 100644
--- a/array.c
+++ b/array.c
@@ -123,7 +123,7 @@ ArrayPrint (Value f, Value av, char format, int base, int width, int prec, int f
 	i = 0;
 	while (i < limit)
 	{
-	    if (!Print (f, ArrayValueGet (a, i), format, base, width, prec, fill))
+	    if (!Print (f, ArrayValueGet (a, i), down_format, base, width, prec, fill))
 	    {
 		ret = False;
 		break;
commit a251ccf47ef335f293d3e53dd8fd9f03c9901bc0
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 15 08:52:48 2017 -0700

    When using pointer as hash, first cast to intptr_t
    
    This avoids a compiler warning when pointers are not the same size as
    HashValues.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/foreign.c b/foreign.c
index bcbe2f4..5a1247d 100644
--- a/foreign.c
+++ b/foreign.c
@@ -26,7 +26,7 @@ ForeignPrint (Value f, Value av, char format, int base, int width, int prec, int
 static HashValue
 ForeignHash (Value av)
 {
-    return (HashValue) av->foreign.data;
+    return (HashValue) (intptr_t) av->foreign.data;
 }
 
 static void
commit 3337ca1580d84430246ed8693a200031474f60e9
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 15 08:42:41 2017 -0700

    Initialize 'replace' in NewTypedBox
    
    When left uninitialized, undefined results will occur. This caused a
    test failure on MIPS when being built with PIE support.
    
    Debian bug 857840.
    
    Reported-by: James Cowgill <jcowgill at debian.org>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/box.c b/box.c
index 549d97f..8c4021b 100644
--- a/box.c
+++ b/box.c
@@ -55,10 +55,10 @@ NewTypedBox (Bool array, BoxTypesPtr bt)
 
     box = ALLOCATE (&BoxType, sizeof (Box) + bt->count * sizeof (Value));
     box->constant = False;
-/*    box->array = array; */
     box->homogeneous = False;
-    box->u.types = bt;
+    box->replace = False;
     box->nvalues = bt->count;
+    box->u.types = bt;
     for (i = 0; i < bt->count; i++)
 	BoxValueSet (box, i, 0);
     RETURN (box);
commit c4f176d76f88a2046619fce0af7f7cc8cef7c1de
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Mar 15 08:39:16 2017 -0700

    Open quote character is a single char, not a string
    
    When checking to see if a string needs to be dequoted, check the first
    character of the string against the quote character, rather than
    checking the whole string.
    
    Probably using strings for the quote markers wasn't the best API
    choice as this would have been caught by typechecking had the quote
    characters been an int instead.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/string.5c b/string.5c
index 52e3878..a53c656 100644
--- a/string.5c
+++ b/string.5c
@@ -214,7 +214,7 @@ extend namespace String {
 	    string curs = "";
 	    void consume() {
 		string t = chomp(curs);
-		if (t != "" && t == q.oq)
+		if (t != "" && t[0] == q.oq[0])
 		    t = dq(t);
 		ss[dim(ss)] = t;
 		curs = "";
commit 74e92c3ff8b3b8478d44ee5e9b1f0fc75283fd88
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Jul 8 16:32:55 2016 +0200

    Define release date in configure.ac and use that instead of build date
    
    This avoids encoding the current date into the resulting output so
    that it can be reproduced.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/Makefile.am b/Makefile.am
index b4e11ce..70b19aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,7 +7,7 @@
 AUTOMAKE_OPTIONS = foreign
 SUBDIRS = bench test examples doc
 
-BUILD_DATE := $(shell sh $(top_builddir)/date-sh)
+RELEASE_DATE := @RELEASE_DATE@
 
 NICKLEFILES = builtin.5c math.5c scanf.5c mutex.5c \
 	arc4.5c prng.5c command.5c abort.5c \
@@ -64,7 +64,7 @@ man_MANS = nickle.1
 AM_YFLAGS = -d
 
 AM_CPPFLAGS = \
-	-DBUILD=\""$(BUILD_DATE)"\" \
+	-DBUILD=\""$(RELEASE_DATE)"\" \
 	-DBUILD_VERSION=\""$(VERSION)"\" \
 	-DLOCAL_BUILD \
 	-DNICKLELIBDIR=\"@nicklelibdir@\"
diff --git a/configure.ac b/configure.ac
index 23e55c9..3a4d01f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ dnl for licensing information.
 AC_PREREQ([2.64])
 
 AC_INIT([nickle],[2.77],[http://nickle.org],[nickle])
-
+RELEASE_DATE="2016-07-08"
 AC_CONFIG_SRCDIR([nickle.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR(.)
@@ -16,6 +16,7 @@ AM_INIT_AUTOMAKE([foreign])
 
 AM_MAINTAINER_MODE
 
+AC_SUBST([RELEASE_DATE])
 dnl Checks for programs.
 AC_PROG_CC
 AC_PROG_INSTALL
@@ -26,8 +27,6 @@ AC_CHECK_PROGS([YACC], byacc yacc bison, yacc)
 case "$YACC" in
 *bison)	YACC="$YACC -y"	;;
 esac
-AC_PROG_AWK
-AC_CHECK_PROGS([DATE], date)
 
 dnl Checks for libraries.
 AC_CHECK_FUNC(log,,AC_CHECK_LIB(m, log))
@@ -135,7 +134,6 @@ AC_CONFIG_FILES(
  examples/smlng/Makefile
  examples/turtle/Makefile
  doc/Makefile
- doc/tutorial/Makefile
- date-sh)
+ doc/tutorial/Makefile)
 
 AC_OUTPUT
diff --git a/date-sh.in b/date-sh.in
deleted file mode 100755
index 6777a7f..0000000
--- a/date-sh.in
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-#
-# Copyright © 1988-2004 Keith Packard and Bart Massey.
-# All Rights Reserved.  See the file COPYING in this directory
-# for licensing information.
-#
- at DATE@ |
- at AWK@ '
-BEGIN {
-	monthnum["Jan"] = 1
-	monthnum["Feb"] = 2
-	monthnum["Mar"] = 3
-	monthnum["Apr"] = 4
-	monthnum["May"] = 5
-	monthnum["Jun"] = 6
-	monthnum["Jul"] = 7
-	monthnum["Aug"] = 8
-	monthnum["Sep"] = 9
-	monthnum["Oct"] = 10
-	monthnum["Nov"] = 11
-	monthnum["Dec"] = 12
-}
-{
-	printf "%04d/%02d/%02d\n", $6, monthnum[$2], $3;
-}'
diff --git a/nickle.1.in b/nickle.1.in
index 7a6d88b..bff6d0e 100644
--- a/nickle.1.in
+++ b/nickle.1.in
@@ -1,4 +1,4 @@
-.TH NICKLE 1 "@BUILD_DATE@"
+.TH NICKLE 1 "@RELEASE_DATE@"
 .\" $Header$
 .SH NAME
 nickle \- a desk calculator language
commit 0da19be66deb245f83e17c6f2a998a7c7702835f
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Jul 7 17:57:40 2016 +0200

    Add JSON input/output code
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/Makefile.am b/Makefile.am
index 2b31c0b..b4e11ce 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,8 @@ NICKLEFILES = builtin.5c math.5c scanf.5c mutex.5c \
 	arc4.5c prng.5c command.5c abort.5c \
         printf.5c history.5c ctype.5c string.5c socket.5c \
 	file.5c parse-args.5c svg.5c process.5c \
-	prime_sieve.5c factorial.5c gamma.5c sort.5c list.5c skiplist.5c
+	prime_sieve.5c factorial.5c gamma.5c sort.5c list.5c skiplist.5c \
+	json.5c
 
 DEBIAN = debian/changelog debian/compat \
 	 debian/control debian/copyright debian/rules debian/lintian.override
diff --git a/json.5c b/json.5c
new file mode 100644
index 0000000..60c71fb
--- /dev/null
+++ b/json.5c
@@ -0,0 +1,293 @@
+/*
+ * Emit and parse JSON
+ */
+
+autoload Sort;
+autoload Ctype;
+
+namespace JSON {
+
+    string quote(string a) {
+	string result = "\"";
+	for (int i = 0; i < String::length(a); i++) {
+	    int c = a[i];
+	    switch (c) {
+	    case '"':
+	    case '\\':
+		result = result + "\\" + String::new(c);
+		break;
+	    case '\n':
+		result = result + "\\n";
+		break;
+	    default:
+		result = result + String::new(c);
+		break;
+	    }
+	}
+	return result + "\"";
+    }
+
+    public string to_json(poly arg)
+    {
+	string do_indent(int indent) {
+	    string result = "\n";
+	    for (int i = 0; i < indent; i++)
+		result = result + "\t";
+	    return result;
+	}
+
+	string json(poly arg, int indent);
+
+	string json_hash(poly[string] a, int indent) {
+	    string[] keys = hash_keys(a);
+	    string result = "{";
+	    bool first = true;
+
+	    Sort::qsort(&keys, bool func(poly a, poly b) { return a > b; });
+	    for (int i = 0; i < dim(keys); i++) {
+		string key = keys[i];
+		string value = json(a[key], indent+1);
+
+		if (!first)
+		    result = result + ",";
+		first = false;
+		result = result + do_indent(indent+1);
+		result = result + quote(key) + ": " + value;
+	    }
+	    result = result + do_indent(indent) + "}";
+	    return result;
+	}
+
+	string json_array(poly[] a, int indent) {
+	    string result = "[";
+	    bool first = true;
+
+	    for (int i = 0; i < dim(a); i++) {
+		if (!first)
+		    result = result + ",";
+		first = false;
+		result = result + do_indent(indent+1);
+		result = result + to_json(a[i]);
+	    }
+	    result = result + do_indent(indent) + "]";
+	    return result;
+	}
+
+	string json_string(string arg) {
+	    return quote(arg);
+	}
+
+	string json_int(int arg) {
+	    return sprintf ("%d", arg);
+	}
+
+	json = string func(poly arg, int indent) {
+	    if (is_hash(arg))
+		return json_hash(arg, indent);
+	    if (is_array(arg))
+		return json_array(arg, indent);
+	    if (is_string(arg))
+		return json_string(arg);
+	    if (is_int(arg))
+		return json_int(arg);
+	    return "";
+	};
+
+	return json(arg, 0);
+    }
+
+    typedef enum {
+	_string,
+	_int,
+	_oc,
+	_cc,
+	_os,
+	_cs,
+	_comma,
+	_colon,
+	_end,
+	_error
+    } term_t;
+
+    typedef struct {
+	union {
+	    int	ival;
+	    string	sval;
+	} val;
+	term_t	token;
+    } token_t;
+
+    typedef struct {
+	file	f;
+	int	line;
+	string	token;
+    } json_input_t;
+
+    json_input_t start_json(string s) {
+	return (json_input_t) { .f = File::string_read(s), .line = 1 };
+    }
+
+    token_t lex(*json_input_t f) {
+
+	int ch() {
+	    int c = File::getc(f->f);
+	    if (c == '\n')
+		f->line++;
+	    f->token = f->token + String::new(c);
+	    return c;
+	}
+
+	void unch(int c) {
+	    if (c == '\n')
+		f->line--;
+	    f->token = String::substr(f->token, 0, String::length(f->token) - 1);
+	    File::ungetc(c, f->f);
+	}
+
+	try {
+	    f->token = "";
+	    for (;;) {
+		int	c = ch();
+
+		switch (c) {
+		case '\n':
+		case ' ':
+		case '\t':
+		    continue;
+		case '{':
+		    return (token_t) { .token = term_t._oc };
+		case '}':
+		    return (token_t) { .token = term_t._cc };
+		case '[':
+		    return (token_t) { .token = term_t._os };
+		case ']':
+		    return (token_t) { .token = term_t._cs };
+		case ',':
+		    return (token_t) { .token = term_t._comma };
+		case ':':
+		    return (token_t) { .token = term_t._colon };
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+		    int ival = 0;
+		    while (Ctype::isdigit(c)) {
+			ival = ival * 10 + c - '0';
+			c = ch();
+		    }
+		    unch(c);
+		    return (token_t) { .val = { .ival = ival }, .token = term_t._int };
+		case '"':
+		    string sval = "";
+		    for (;;) {
+			c = ch();
+			if (c == '"')
+			    break;
+			if (c == '\\') {
+			    c = ch();
+			    switch (c) {
+			    case 'n':
+				c = '\n';
+				break;
+			    case 't':
+				c = '\t';
+				break;
+			    default:
+				break;
+			    }
+			}
+			sval = sval + String::new(c);
+		    }
+		    return (token_t) { .val = { .sval = sval }, .token = term_t._string };
+		default:
+		    break;
+		}
+		break;
+	    }
+	}
+	catch File::io_eof(file f) {
+	    return (token_t) { .token = term_t._end };
+	}
+	return (token_t) { .token = term_t._error };
+    }
+
+    public exception json_parse_error(int line, string token);
+
+    public poly from_json(string arg) {
+	json_input_t f = start_json(arg);
+
+	token_t	token;
+
+	void next() {
+	    token = lex(&f);
+	}
+
+	void expect(term_t t) {
+	    if (token.token != t)
+		raise json_parse_error(f.line, f.token);
+	}
+
+	poly value();
+
+	poly[string] hash() {
+	    poly[string] ret = {};
+	    for (;;) {
+		expect(term_t._string);
+		string name = token.val.sval;
+		next();
+		expect(term_t._colon);
+		next();
+		poly val = value();
+		ret[name] = val;
+		switch (token.token) {
+		case term_t._comma:
+		    next();
+		    continue;
+		case term_t._cc:
+		    next();
+		    return ret;
+		default:
+		    raise json_parse_error(f.line, f.token);
+		}
+	    }
+	}
+
+	poly[] array() {
+	    poly[...] ret = {};
+	    for (;;) {
+		poly val = value();
+		ret[dim(ret)] = val;
+		switch (token.token) {
+		case term_t._comma:
+		    next();
+		    continue;
+		case term_t._cs:
+		    next();
+		    return ret;
+		default:
+		    raise json_parse_error(f.line, f.token);
+		}
+	    }
+	}
+
+	value = poly func() {
+	    switch (token.token) {
+	    case term_t._oc:
+	    next();
+	    return hash();
+	    case term_t._os:
+	    next();
+	    return array();
+	    case term_t._int:
+	    int ival = token.val.ival;
+	    next();
+	    return ival;
+	    case term_t._string:
+	    string sval = token.val.sval;
+	    next();
+	    return sval;
+	    }
+	};
+
+	next();
+	return value();
+    }
+}
commit a6a9375b89b3281b6ed670619e6d317a1d8af7e8
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Jul 7 17:54:56 2016 +0200

    Reverse data written in linked FileChains
    
    FileChains are linked in newest-in order, so they need to be written
    last-first.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/file.c b/file.c
index d088d44..a22e30b 100644
--- a/file.c
+++ b/file.c
@@ -916,6 +916,15 @@ FileStringWrite (void)
     RETURN (file);
 }
 
+static char *
+write_chain(char *s, FileChainPtr out)
+{
+    if (out->next)
+	s = write_chain(s, out->next);
+    memcpy(s, FileBuffer(out), out->used);
+    return s + out->used;
+}
+
 Value
 FileStringString (Value file)
 {
@@ -936,12 +945,8 @@ FileStringString (Value file)
     for (out = file->file.output; out; out = out->next)
 	len += out->used;
     str = NewString (len);
-    s = StringChars (&str->string);
-    for (out = file->file.output; out; out = out->next)
-    {
-	memcpy (s, FileBuffer(out), out->used);
-	s += out->used;
-    }
+    StringChars (&str->string);
+    s = write_chain(StringChars(&str->string), file->file.output);
     *s = '\0';
     RETURN (str);
 }
commit 18aa99c09b5be9561be9f908ed5a5aaee55e04e3
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Jul 7 17:54:11 2016 +0200

    Add is_hash primitive
    
    Checks whether a value is a hash
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/builtin-toplevel.c b/builtin-toplevel.c
index 73c6573..825a66c 100644
--- a/builtin-toplevel.c
+++ b/builtin-toplevel.c
@@ -90,6 +90,10 @@ import_Toplevel_namespace()
 	    " bool is_func (poly v)\n"
 	    "\n"
 	    " Return whether 'v' is an func value.\n" },
+        { do_is_hash, "is_hash", "b", "p", "\n"
+	    " bool is_hash (poly v)\n"
+	    "\n"
+	    " Return whether 'v' is an hash value.\n" },
         { do_is_int, "is_int", "b", "p" , "\n"
 	    " bool is_int (poly v)\n"
 	    "\n"
@@ -880,6 +884,21 @@ do_is_array (Value av)
 }
 
 Value
+do_is_hash(Value av)
+{
+    ENTER();
+    switch(ValueTag(av)) {
+    case rep_hash:
+	av = TrueVal;
+	break;
+    default:
+	av = FalseVal;
+	break;
+    }
+    RETURN(av);
+}
+
+Value
 do_is_ref (Value av)
 {
     ENTER ();
diff --git a/nickle.h b/nickle.h
index cd2aba0..3c900e7 100644
--- a/nickle.h
+++ b/nickle.h
@@ -927,6 +927,7 @@ Value	do_is_thread (Value);
 Value	do_is_semaphore (Value);
 Value	do_is_continuation (Value);
 Value	do_is_array (Value);
+Value	do_is_hash (Value);
 Value	do_is_ref (Value);
 Value	do_is_struct (Value);
 Value	do_is_func (Value);
commit 7fd6e3c6727983c10098d92a469dd802c3196142
Author: Keith Packard <keithp at keithp.com>
Date:   Sat Jun 21 21:24:02 2014 -0700

    Abort karatsuba multiply in more places

diff --git a/natural.c b/natural.c
index 0a01535..6459cfb 100644
--- a/natural.c
+++ b/natural.c
@@ -420,6 +420,9 @@ DigitsKaratsuba (digit *x, int xlen, digit *y, int ylen, digit *result, digit *t
     int	    flen, m1len, m2len;
     int	    rlen;
     
+    if (aborting)
+	return 0;
+
     if (xlen < KARATSUBA_LIMIT || ylen < KARATSUBA_LIMIT)
 	return DigitsGradeSchool (x, xlen, y, ylen, result);
 
@@ -480,6 +483,8 @@ DigitsKaratsuba (digit *x, int xlen, digit *y, int ylen, digit *result, digit *t
     {
 	memset (result, 0, off * sizeof (digit));
 	rlen = DigitsKaratsuba (m1, m1len, m2, m2len, result + off, next_tmp) + off;
+	if (aborting)
+	    return rlen;
     }
     
     /*
@@ -488,6 +493,8 @@ DigitsKaratsuba (digit *x, int xlen, digit *y, int ylen, digit *result, digit *t
     if (x1len && y1len)
     {
 	flen = DigitsKaratsuba (x1, x1len, y1, y1len, f, next_tmp);
+	if (aborting)
+	    return rlen;
 	rlen = DigitsAddInPlace (result, rlen, f, flen, off2);
 	rlen = DigitsSubInPlace (result, rlen, f, flen, off);
     }
@@ -499,6 +506,8 @@ DigitsKaratsuba (digit *x, int xlen, digit *y, int ylen, digit *result, digit *t
     if (x0len && y0len)
     {
 	flen = DigitsKaratsuba (x0, x0len, y0, y0len, f, next_tmp);
+	if (aborting)
+	    return rlen;
 	rlen = DigitsAddInPlace (result, rlen, f, flen, 0);
 	rlen = DigitsSubInPlace (result, rlen, f, flen, off);
     }
@@ -583,6 +592,8 @@ NaturalTimes (Natural *a, Natural *b)
 	tmp_len = rlen << 3;
 	tmp = AllocateTemp (tmp_len * sizeof (digit));
 	rlen = DigitsKaratsuba (data(a), length (a), data(b), length (b), data(result), tmp);
+	if (aborting)
+	    RETURN(zero_natural);
 	tmp = data(result) + (rlen - 1);
 	while (rlen && *tmp == 0)
 	{
@@ -985,8 +996,14 @@ NaturalSprint (char *result, Natural *a, int base, int *width)
 	    divisors[idivisor++] = divisor;
 	    divisor = NaturalTimes (divisor, divisor);
 	    digits = digits * 2;
+	    if (aborting)
+	    {
+		r = 0;
+		break;
+	    }
 	} while (NaturalLess (divisor, a));
-	r = NaturalSplit (r, a, divisors + idivisor - 1, base, digits, False);
+	if (!aborting)
+	    r = NaturalSplit (r, a, divisors + idivisor - 1, base, digits, False);
 	free (divisors);
     }
     if (width && r)


More information about the Nickle mailing list