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");