diff options
Diffstat (limited to 'src/libmp/port/strtomp.c')
-rw-r--r-- | src/libmp/port/strtomp.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/libmp/port/strtomp.c b/src/libmp/port/strtomp.c new file mode 100644 index 00000000..8e07f009 --- /dev/null +++ b/src/libmp/port/strtomp.c @@ -0,0 +1,205 @@ +#include "os.h" +#include <mp.h> +#include <libsec.h> +#include "dat.h" + +static struct { + int inited; + + uchar t64[256]; + uchar t32[256]; + uchar t16[256]; + uchar t10[256]; +} tab; + +enum { + INVAL= 255 +}; + +static char set64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static char set32[] = "23456789abcdefghijkmnpqrstuvwxyz"; +static char set16[] = "0123456789ABCDEF0123456789abcdef"; +static char set10[] = "0123456789"; + +static void +init(void) +{ + char *p; + + memset(tab.t64, INVAL, sizeof(tab.t64)); + memset(tab.t32, INVAL, sizeof(tab.t32)); + memset(tab.t16, INVAL, sizeof(tab.t16)); + memset(tab.t10, INVAL, sizeof(tab.t10)); + + for(p = set64; *p; p++) + tab.t64[(uchar)*p] = p-set64; + for(p = set32; *p; p++) + tab.t32[(uchar)*p] = p-set32; + for(p = set16; *p; p++) + tab.t16[(uchar)*p] = (p-set16)%16; + for(p = set10; *p; p++) + tab.t10[(uchar)*p] = (p-set10); + + tab.inited = 1; +} + +static char* +from16(char *a, mpint *b) +{ + char *p, *next; + int i; + mpdigit x; + + b->top = 0; + for(p = a; *p; p++) + if(tab.t16[*(uchar*)p] == INVAL) + break; + mpbits(b, (p-a)*4); + b->top = 0; + next = p; + while(p > a){ + x = 0; + for(i = 0; i < Dbits; i += 4){ + if(p <= a) + break; + x |= tab.t16[*(uchar*)--p]<<i; + } + b->p[b->top++] = x; + } + 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 = tab.t10[*(uchar*)a]; + if(y == INVAL) + 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* +from64(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*6); + p = malloc(n); + if(p == nil) + return a; + m = dec64(p, n, buf, n); + 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) +{ + int sign; + char *e; + + if(b == nil) + b = mpnew(0); + + if(tab.inited == 0) + init(); + + while(*a==' ' || *a=='\t') + a++; + + sign = 1; + for(;; a++){ + switch(*a){ + case '-': + sign *= -1; + continue; + } + break; + } + + switch(base){ + case 10: + e = from10(a, b); + break; + default: + case 16: + e = from16(a, b); + break; + case 32: + e = from32(a, b); + break; + case 64: + e = from64(a, b); + break; + } + + // if no characters parsed, there wasn't a number to convert + if(e == a) + return nil; + + mpnorm(b); + b->sign = sign; + if(pp != nil) + *pp = e; + + return b; +} |