shithub: riscv

Download patch

ref: d30b160fe3b595c071d37345c51b35fffb2ad30c
parent: 39f18c9d88f52a22373790dec5721fa3521d3f00
author: cinap_lenrek <[email protected]>
date: Sun Jan 3 17:43:44 EST 2016

libmp: support for c-style base prefixes for strtomp(), octal support

--- a/sys/man/2/mp
+++ b/sys/man/2/mp
@@ -337,13 +337,22 @@
 and
 .B mpint
 representations using the base indicated.
-Only the bases 10, 16, 32, and 64 are
-supported.  Anything else defaults to 16.
+Only the bases 2, 4, 8, 10, 16, 32, and 64 are
+supported.  Base 0 defaults to 16.
 .IR Strtomp
 skips any leading spaces or tabs.
 .IR Strtomp 's
 scan stops when encountering a digit not valid in the
 base.  If
+.I base
+is zero then C-style prefixes are interpreted to
+find the base:
+.B 0x
+for hexadecimal,
+.B 0b
+for binary and
+.B 0
+for octal. Otherwise decimal is assumed.
 .I rptr
 is not zero,
 .I *rptr
--- a/sys/src/libmp/bigtest.c
+++ b/sys/src/libmp/bigtest.c
@@ -52,7 +52,7 @@
 	int i;
 
 	start = time(0);
-	fmtinstall('B', mpconv);
+	fmtinstall('B', mpfmt);
 	mpsetminbits(2*Dbits);
 
 	x = mpnew(0);
--- a/sys/src/libmp/port/mpfmt.c
+++ b/sys/src/libmp/port/mpfmt.c
@@ -4,7 +4,7 @@
 #include "dat.h"
 
 static int
-to64(mpint *b, char *buf, int len)
+toencx(mpint *b, char *buf, int len, int (*enc)(char*, int, uchar*, int))
 {
 	uchar *p;
 	int n, rv;
@@ -13,34 +13,11 @@
 	n = mptobe(b, nil, 0, &p);
 	if(n < 0)
 		return -1;
-	rv = enc64(buf, len, p, n);
+	rv = (*enc)(buf, len, p, n);
 	free(p);
 	return rv;
 }
 
-static int
-to32(mpint *b, char *buf, int len)
-{
-	uchar *p;
-	int n, rv;
-
-	// leave room for a multiple of 5 buffer size
-	n = b->top*Dbytes + 5;
-	p = malloc(n);
-	if(p == nil)
-		return -1;
-	n = mptobe(b, p, n, nil);
-	if(n < 0)
-		return -1;
-
-	// round up buffer size, enc32 only accepts a multiple of 5
-	if(n%5)
-		n += 5 - (n%5);
-	rv = enc32(buf, len, p, n);
-	free(p);
-	return rv;
-}
-
 static char set16[] = "0123456789ABCDEF";
 
 static int
@@ -103,6 +80,7 @@
 		return -1;
 
 	d = mpcopy(b);
+	d->flags &= ~MPtimesafe;
 	mpnorm(d);
 	r = mpnew(0);
 	billion = uitomp(1000000000, nil);
@@ -126,32 +104,89 @@
 	return 0;
 }
 
+static int
+to8(mpint *b, char *buf, int len)
+{
+	mpdigit x, y;
+	char *out;
+	int i, j;
+
+	if(len < 2)
+		return -1;
+
+	out = buf+len;
+	*--out = 0;
+
+	i = j = 0;
+	x = y = 0;
+	while(j < b->top){
+		y = b->p[j++];
+		if(i > 0)
+			x |= y << i;
+		else
+			x = y;
+		i += Dbits;
+		while(i >= 3){
+Digout:			i -= 3;
+			if(out > buf)
+				out--;
+			else if(x != 0)
+				return -1;
+			*out = '0' + (x & 7);
+			x = y >> Dbits-i;
+		}
+	}
+	if(i > 0)
+		goto Digout;
+
+	while(*out == '0') out++;
+	if(*out == '\0')
+		*--out = '0';
+
+	len -= out-buf;
+	if(out != buf)
+		memmove(buf, out, len);
+	return 0;
+}
+
 int
 mpfmt(Fmt *fmt)
 {
 	mpint *b;
-	char *p, f;
+	char *x, *p;
+	int base;
 
 	b = va_arg(fmt->args, mpint*);
 	if(b == nil)
 		return fmtstrcpy(fmt, "*");
 
-	f = b->flags;
-	b->flags &= ~MPtimesafe;
-
-	p = mptoa(b, fmt->prec, nil, 0);
+	base = fmt->prec;
+	if(base == 0)
+		base = 16;	/* default */
 	fmt->flags &= ~FmtPrec;
-
-	b->flags = f;
-
+	p = mptoa(b, base, nil, 0);
 	if(p == nil)
 		return fmtstrcpy(fmt, "*");
 	else{
-		if((fmt->flags & FmtSharp) != 0 && fmt->prec!=10 && fmt->prec!=32 && fmt->prec!=64)
+		if((fmt->flags & FmtSharp) != 0){
+			switch(base){
+			case 16:
+				x = "0x";
+				break;
+			case 8:
+				x = "0";
+				break;
+			case 2:
+				x = "0b";
+				break;
+			default:
+				x = "";
+			}
 			if(*p == '-')
-				fmtprint(fmt, "-0x%s", p + 1);
+				fmtprint(fmt, "-%s%s", x, p + 1);
 			else
-				fmtprint(fmt, "0x%s", p);
+				fmtprint(fmt, "%s%s", x, p);
+		}
 		else
 			fmtstrcpy(fmt, p);
 		free(p);
@@ -165,9 +200,14 @@
 	char *out;
 	int rv, alloced;
 
+	if(base == 0)
+		base = 16;	/* default */
 	alloced = 0;
 	if(buf == nil){
-		len = ((b->top+1)*Dbits+2)/3 + 1;
+		/* rv <= log₂(base) */
+		for(rv=1; (base >> rv) > 1; rv++)
+			;
+		len = 10 + (b->top*Dbits / rv);
 		buf = malloc(len);
 		if(buf == nil)
 			return nil;
@@ -184,12 +224,11 @@
 	}
 	switch(base){
 	case 64:
-		rv = to64(b, out, len);
+		rv = toencx(b, out, len, enc64);
 		break;
 	case 32:
-		rv = to32(b, out, len);
+		rv = toencx(b, out, len, enc32);
 		break;
-	default:
 	case 16:
 		rv = topow2(b, out, len, 4);
 		break;
@@ -196,6 +235,9 @@
 	case 10:
 		rv = to10(b, out, len);
 		break;
+	case 8:
+		rv = to8(b, out, len);
+		break;
 	case 4:
 		rv = topow2(b, out, len, 2);
 		break;
@@ -202,6 +244,9 @@
 	case 2:
 		rv = topow2(b, out, len, 1);
 		break;
+	default:
+		abort();
+		return nil;
 	}
 	if(rv < 0){
 		if(alloced)
--- a/sys/src/libmp/port/strtomp.c
+++ b/sys/src/libmp/port/strtomp.c
@@ -53,11 +53,13 @@
 
 	sn = 1<<s;
 	for(p = a; *p; p++)
-		if((uchar)tab.t16[*(uchar*)p] >= sn)
+		if(tab.t16[*(uchar*)p] >= sn)
 			break;
-	mpbits(b, (p-a)*4);
+
+	mpbits(b, (p-a)*s);
 	b->top = 0;
 	next = p;
+
 	while(p > a){
 		x = 0;
 		for(i = 0; i < Dbits; i += s){
@@ -70,6 +72,40 @@
 	return next;
 }
 
+static char*
+from8(char *a, mpint *b)
+{
+	char *p, *next;
+	mpdigit x, y;
+	int i;
+
+	for(p = a; *p; p++)
+		if(tab.t10[*(uchar*)p] >= 8)
+			break;
+
+	mpbits(b, (a-p)*3);
+	b->top = 0;
+	next = p;
+
+	i = 0;
+	x = 0;
+	while(p > a){
+		y = tab.t10[*(uchar*)--p];
+		x |= y << i;
+		i += 3;
+		if(i >= Dbits){
+Digout:
+			i -= Dbits;
+			b->p[b->top++] = x;
+			x = y >> 3-i;
+		}
+	}
+	if(i > 0)
+		goto Digout;
+
+	return next;
+}
+
 static ulong mppow10[] = {
 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
 };
@@ -113,45 +149,28 @@
 }
 
 static char*
-from64(char *a, mpint *b)
+fromdecx(char *a, mpint *b, uchar tab[256], int (*dec)(uchar*, int, char*, int))
 {
 	char *buf = a;
 	uchar *p;
 	int n, m;
 
-	for(; tab.t64[*(uchar*)a] != INVAL; a++)
+	b->top = 0;
+	for(; tab[*(uchar*)a] != INVAL; a++)
 		;
 	n = a-buf;
-	mpbits(b, n*6);
-	p = malloc(n);
-	if(p == nil)
-		return a;
-	m = dec64(p, n, buf, n);
-	betomp(p, m, b);
-	free(p);
+	if(n > 0){
+		p = malloc(n);
+		if(p == nil)
+			sysfatal("malloc: %r");
+		m = (*dec)(p, n, buf, n);
+		if(m > 0)
+			betomp(p, m, b);
+		free(p);
+	}
 	return a;
 }
 
-static char*
-from32(char *a, mpint *b)
-{
-	char *buf = a;
-	uchar *p;
-	int n, m;
-
-	for(; tab.t64[*(uchar*)a] != INVAL; a++)
-		;
-	n = a-buf;
-	mpbits(b, n*5);
-	p = malloc(n);
-	if(p == nil)
-		return a;
-	m = dec32(p, n, buf, n);
-	betomp(p, m, b);
-	free(p);
-	return a;
-}
-
 mpint*
 strtomp(char *a, char **pp, int base, mpint *b)
 {
@@ -179,6 +198,21 @@
 		break;
 	}
 
+	if(base == 0){
+		if(*a == '0'){
+			a++;
+			if(*a == 'x' || *a == 'X') {
+				a++;
+				base = 16;
+			} else if(*a == 'b' || *a == 'B') {
+				a++;
+				base = 2;
+			} else
+				base = 8;
+		} else
+			base = 10;
+	}
+
 	switch(base){
 	case 2:
 		e = frompow2(a, b, 1);
@@ -187,21 +221,23 @@
 		e = frompow2(a, b, 2);
 		break;
 	case 8:
-		e = frompow2(a, b, 3);
+		e = from8(a, b);
 		break;
 	case 10:
 		e = from10(a, b);
 		break;
-	default:
 	case 16:
 		e = frompow2(a, b, 4);
 		break;
 	case 32:
-		e = from32(a, b);
+		e = fromdecx(a, b, tab.t32, dec32);
 		break;
 	case 64:
-		e = from64(a, b);
+		e = fromdecx(a, b, tab.t64, dec64);
 		break;
+	default:
+		abort();
+		return nil;
 	}
 
 	// if no characters parsed, there wasn't a number to convert
--- a/sys/src/libmp/test.c
+++ b/sys/src/libmp/test.c
@@ -30,35 +30,35 @@
 void
 testconv(char *str)
 {
+	int i, base[] = {2,8,10,16,32,64};
 	mpint *b;
 	char *p;
 
+	print("testconv \"%s\":\n", str);
 	b = strtomp(str, nil, 16, nil);
 
-	p = mptoa(b, 10, nil, 0);
-	print("%s = ", p);
-	strtomp(p, nil, 10, b);
-	free(p);
-	print("%B\n", b);
+	for(i=0; i<nelem(base); i++){
+		p = mptoa(b, base[i], nil, 0);
+		print("base%d: %s = ", base[i], p);
+		strtomp(p, nil, base[i], b);
+		free(p);
+		print("%B\n", b, base[i], b);
 
-	p = mptoa(b, 16, nil, 0);
-	print("%s = ", p);
-	strtomp(p, nil, 16, b);
-	free(p);
-	print("%B\n", b);
+		switch(base[i]){
+		case 2:
+		case 8:
+		case 10:
+		case 16:
+			p = smprint("%#.*B", base[i], b);
+			print("# %s = ", p);
+			strtomp(p, nil, 0, b);
+			free(p);
+			print("%#.*B\n", base[i], b);
+			break;
+		}
 
-	p = mptoa(b, 32, nil, 0);
-	print("%s = ", p);
-	strtomp(p, nil, 32, b);
-	free(p);
-	print("%B\n", b);
+	}
 
-	p = mptoa(b, 64, nil, 0);
-	print("%s = ", p);
-	strtomp(p, nil, 64, b);
-	free(p);
-	print("%B\n", b);
-
 	mpfree(b);
 }
 
@@ -419,6 +419,11 @@
 	testconv("0");
 	testconv("-abc0123456789abcedf");
 	testconv("abc0123456789abcedf");
+	testconv("ffffffff");
+	testconv("aaaaaaaaaaaaaaaaa");
+	testconv("1111111111111111");
+	testconv("33333333333333333333333333333333");
+
 	testvecdigmulsub("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
 	testsub1("1FFFFFFFE00000000", "FFFFFFFE00000001");
 	testmul1("ffffffff", "f");