Rev 2 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "os.h"
#include <mp.h>
#include "dat.h"
#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
static int
dec16chr(int c)
{
int o;
o = between(c, '0', '9') & (1+(c-'0'));
o |= between(c, 'A', 'F') & (1+10+(c-'A'));
o |= between(c, 'a', 'f') & (1+10+(c-'a'));
return o-1;
}
static int
dec32chr(int c)
{
int o;
o = between(c, 'A', 'Z') & (1+(c-'A'));
o |= between(c, 'a', 'z') & (1+(c-'a'));
o |= between(c, '2', '7') & (1+26+(c-'2'));
return o-1;
}
static int
dec64chr(int c)
{
int o;
o = between(c, 'A', 'Z') & (1+(c-'A'));
o |= between(c, 'a', 'z') & (1+26+(c-'a'));
o |= between(c, '0', '9') & (1+52+(c-'0'));
o |= between(c, '+', '+') & (1+62);
o |= between(c, '/', '/') & (1+63);
return o-1;
}
static char*
frompow2(char *a, mpint *b, int s)
{
char *p, *next;
mpdigit x;
int i;
i = 1<<s;
for(p = a; (dec16chr(*p) & 255) < i; p++)
;
mpbits(b, (p-a)*s);
b->top = 0;
next = p;
while(p > a){
x = 0;
for(i = 0; i < Dbits; i += s){
if(p <= a)
break;
x |= dec16chr(*--p)<<i;
}
b->p[b->top++] = x;
}
return next;
}
static char*
from8(char *a, mpint *b)
{
char *p, *next;
mpdigit x, y;
int i;
for(p = a; ((*p - '0') & 255) < 8; p++)
;
mpbits(b, (p-a)*3);
b->top = 0;
next = p;
i = 0;
x = y = 0;
while(p > a){
y = *--p - '0';
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
};
static char*
from10(char *a, mpint *b)
{
ulong x, y;
mpint *pow, *r;
int i;
pow = mpnew(0);
r = mpnew(0);
b->top = 0;
for(;;){
// do a billion at a time in native arithmetic
x = 0;
for(i = 0; i < 9; i++){
y = *a - '0';
if(y > 9)
break;
a++;
x *= 10;
x += y;
}
if(i == 0)
break;
// accumulate into mpint
uitomp(mppow10[i], pow);
uitomp(x, r);
mpmul(b, pow, b);
mpadd(b, r, b);
if(i < 9)
break;
}
mpfree(pow);
mpfree(r);
return a;
}
static char*
fromdecx(char *a, mpint *b, int (*chr)(int), int (*dec)(uchar*, int, char*, int))
{
char *buf = a;
uchar *p;
int n, m;
b->top = 0;
for(; (*chr)(*a) >= 0; a++)
;
n = a-buf;
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;
}
mpint*
strtomp(char *a, char **pp, int base, mpint *b)
{
int sign;
char *e;
if(b == nil){
b = mpnew(0);
setmalloctag(b, getcallerpc(&a));
}
while(*a==' ' || *a=='\t')
a++;
sign = 1;
for(;; a++){
switch(*a){
case '-':
sign *= -1;
continue;
}
break;
}
if(base == 0){
base = 10;
if(a[0] == '0'){
if(a[1] == 'x' || a[1] == 'X') {
a += 2;
base = 16;
} else if(a[1] == 'b' || a[1] == 'B') {
a += 2;
base = 2;
} else if(a[1] >= '0' && a[1] <= '7') {
a++;
base = 8;
}
}
}
switch(base){
case 2:
e = frompow2(a, b, 1);
break;
case 4:
e = frompow2(a, b, 2);
break;
case 8:
e = from8(a, b);
break;
case 10:
e = from10(a, b);
break;
case 16:
e = frompow2(a, b, 4);
break;
case 32:
e = fromdecx(a, b, dec32chr, dec32);
break;
case 64:
e = fromdecx(a, b, dec64chr, dec64);
break;
default:
abort();
return nil;
}
if(pp != nil)
*pp = e;
// if no characters parsed, there wasn't a number to convert
if(e == a)
return nil;
b->sign = sign;
return mpnorm(b);
}