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

This commit is contained in:
cinap_lenrek 2016-01-03 22:43:44 +01:00
parent 39f18c9d88
commit d30b160fe3
5 changed files with 194 additions and 99 deletions

View file

@ -337,13 +337,22 @@ convert between
and and
.B mpint .B mpint
representations using the base indicated. representations using the base indicated.
Only the bases 10, 16, 32, and 64 are Only the bases 2, 4, 8, 10, 16, 32, and 64 are
supported. Anything else defaults to 16. supported. Base 0 defaults to 16.
.IR Strtomp .IR Strtomp
skips any leading spaces or tabs. skips any leading spaces or tabs.
.IR Strtomp 's .IR Strtomp 's
scan stops when encountering a digit not valid in the scan stops when encountering a digit not valid in the
base. If 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 .I rptr
is not zero, is not zero,
.I *rptr .I *rptr

View file

@ -52,7 +52,7 @@ main(int argc, char **argv)
int i; int i;
start = time(0); start = time(0);
fmtinstall('B', mpconv); fmtinstall('B', mpfmt);
mpsetminbits(2*Dbits); mpsetminbits(2*Dbits);
x = mpnew(0); x = mpnew(0);

View file

@ -4,7 +4,7 @@
#include "dat.h" #include "dat.h"
static int static int
to64(mpint *b, char *buf, int len) toencx(mpint *b, char *buf, int len, int (*enc)(char*, int, uchar*, int))
{ {
uchar *p; uchar *p;
int n, rv; int n, rv;
@ -13,30 +13,7 @@ to64(mpint *b, char *buf, int len)
n = mptobe(b, nil, 0, &p); n = mptobe(b, nil, 0, &p);
if(n < 0) if(n < 0)
return -1; 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); free(p);
return rv; return rv;
} }
@ -103,6 +80,7 @@ to10(mpint *b, char *buf, int len)
return -1; return -1;
d = mpcopy(b); d = mpcopy(b);
d->flags &= ~MPtimesafe;
mpnorm(d); mpnorm(d);
r = mpnew(0); r = mpnew(0);
billion = uitomp(1000000000, nil); billion = uitomp(1000000000, nil);
@ -126,32 +104,89 @@ to10(mpint *b, char *buf, int len)
return 0; 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 int
mpfmt(Fmt *fmt) mpfmt(Fmt *fmt)
{ {
mpint *b; mpint *b;
char *p, f; char *x, *p;
int base;
b = va_arg(fmt->args, mpint*); b = va_arg(fmt->args, mpint*);
if(b == nil) if(b == nil)
return fmtstrcpy(fmt, "*"); return fmtstrcpy(fmt, "*");
f = b->flags; base = fmt->prec;
b->flags &= ~MPtimesafe; if(base == 0)
base = 16; /* default */
p = mptoa(b, fmt->prec, nil, 0);
fmt->flags &= ~FmtPrec; fmt->flags &= ~FmtPrec;
p = mptoa(b, base, nil, 0);
b->flags = f;
if(p == nil) if(p == nil)
return fmtstrcpy(fmt, "*"); return fmtstrcpy(fmt, "*");
else{ 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 == '-') if(*p == '-')
fmtprint(fmt, "-0x%s", p + 1); fmtprint(fmt, "-%s%s", x, p + 1);
else else
fmtprint(fmt, "0x%s", p); fmtprint(fmt, "%s%s", x, p);
}
else else
fmtstrcpy(fmt, p); fmtstrcpy(fmt, p);
free(p); free(p);
@ -165,9 +200,14 @@ mptoa(mpint *b, int base, char *buf, int len)
char *out; char *out;
int rv, alloced; int rv, alloced;
if(base == 0)
base = 16; /* default */
alloced = 0; alloced = 0;
if(buf == nil){ 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); buf = malloc(len);
if(buf == nil) if(buf == nil)
return nil; return nil;
@ -184,24 +224,29 @@ mptoa(mpint *b, int base, char *buf, int len)
} }
switch(base){ switch(base){
case 64: case 64:
rv = to64(b, out, len); rv = toencx(b, out, len, enc64);
break; break;
case 32: case 32:
rv = to32(b, out, len); rv = toencx(b, out, len, enc32);
break; break;
default:
case 16: case 16:
rv = topow2(b, out, len, 4); rv = topow2(b, out, len, 4);
break; break;
case 10: case 10:
rv = to10(b, out, len); rv = to10(b, out, len);
break; break;
case 8:
rv = to8(b, out, len);
break;
case 4: case 4:
rv = topow2(b, out, len, 2); rv = topow2(b, out, len, 2);
break; break;
case 2: case 2:
rv = topow2(b, out, len, 1); rv = topow2(b, out, len, 1);
break; break;
default:
abort();
return nil;
} }
if(rv < 0){ if(rv < 0){
if(alloced) if(alloced)

View file

@ -53,11 +53,13 @@ frompow2(char *a, mpint *b, int s)
sn = 1<<s; sn = 1<<s;
for(p = a; *p; p++) for(p = a; *p; p++)
if((uchar)tab.t16[*(uchar*)p] >= sn) if(tab.t16[*(uchar*)p] >= sn)
break; break;
mpbits(b, (p-a)*4);
mpbits(b, (p-a)*s);
b->top = 0; b->top = 0;
next = p; next = p;
while(p > a){ while(p > a){
x = 0; x = 0;
for(i = 0; i < Dbits; i += s){ for(i = 0; i < Dbits; i += s){
@ -70,6 +72,40 @@ frompow2(char *a, mpint *b, int s)
return next; 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[] = { static ulong mppow10[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
}; };
@ -113,42 +149,25 @@ from10(char *a, mpint *b)
} }
static char* static char*
from64(char *a, mpint *b) fromdecx(char *a, mpint *b, uchar tab[256], int (*dec)(uchar*, int, char*, int))
{ {
char *buf = a; char *buf = a;
uchar *p; uchar *p;
int n, m; int n, m;
for(; tab.t64[*(uchar*)a] != INVAL; a++) b->top = 0;
for(; tab[*(uchar*)a] != INVAL; a++)
; ;
n = a-buf; n = a-buf;
mpbits(b, n*6); if(n > 0){
p = malloc(n); p = malloc(n);
if(p == nil) if(p == nil)
return a; sysfatal("malloc: %r");
m = dec64(p, n, buf, n); m = (*dec)(p, n, buf, n);
betomp(p, m, b); if(m > 0)
free(p); betomp(p, m, b);
return a; free(p);
} }
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; return a;
} }
@ -179,6 +198,21 @@ strtomp(char *a, char **pp, int base, mpint *b)
break; 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){ switch(base){
case 2: case 2:
e = frompow2(a, b, 1); e = frompow2(a, b, 1);
@ -187,21 +221,23 @@ strtomp(char *a, char **pp, int base, mpint *b)
e = frompow2(a, b, 2); e = frompow2(a, b, 2);
break; break;
case 8: case 8:
e = frompow2(a, b, 3); e = from8(a, b);
break; break;
case 10: case 10:
e = from10(a, b); e = from10(a, b);
break; break;
default:
case 16: case 16:
e = frompow2(a, b, 4); e = frompow2(a, b, 4);
break; break;
case 32: case 32:
e = from32(a, b); e = fromdecx(a, b, tab.t32, dec32);
break; break;
case 64: case 64:
e = from64(a, b); e = fromdecx(a, b, tab.t64, dec64);
break; break;
default:
abort();
return nil;
} }
// if no characters parsed, there wasn't a number to convert // if no characters parsed, there wasn't a number to convert

View file

@ -30,34 +30,34 @@ prng(uchar *p, int n)
void void
testconv(char *str) testconv(char *str)
{ {
int i, base[] = {2,8,10,16,32,64};
mpint *b; mpint *b;
char *p; char *p;
print("testconv \"%s\":\n", str);
b = strtomp(str, nil, 16, nil); b = strtomp(str, nil, 16, nil);
p = mptoa(b, 10, nil, 0); for(i=0; i<nelem(base); i++){
print("%s = ", p); p = mptoa(b, base[i], nil, 0);
strtomp(p, nil, 10, b); print("base%d: %s = ", base[i], p);
free(p); strtomp(p, nil, base[i], b);
print("%B\n", b); free(p);
print("%B\n", b, base[i], b);
p = mptoa(b, 16, nil, 0); switch(base[i]){
print("%s = ", p); case 2:
strtomp(p, nil, 16, b); case 8:
free(p); case 10:
print("%B\n", b); 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); mpfree(b);
} }
@ -419,6 +419,11 @@ main(int argc, char **argv)
testconv("0"); testconv("0");
testconv("-abc0123456789abcedf"); testconv("-abc0123456789abcedf");
testconv("abc0123456789abcedf"); testconv("abc0123456789abcedf");
testconv("ffffffff");
testconv("aaaaaaaaaaaaaaaaa");
testconv("1111111111111111");
testconv("33333333333333333333333333333333");
testvecdigmulsub("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2); testvecdigmulsub("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
testsub1("1FFFFFFFE00000000", "FFFFFFFE00000001"); testsub1("1FFFFFFFE00000000", "FFFFFFFE00000001");
testmul1("ffffffff", "f"); testmul1("ffffffff", "f");