|  | #include "os.h" | 
|  | #include <mp.h> | 
|  | #include "dat.h" | 
|  |  | 
|  | static int | 
|  | to64(mpint *b, char *buf, int len) | 
|  | { | 
|  | uchar *p; | 
|  | int n, rv; | 
|  |  | 
|  | p = nil; | 
|  | n = mptobe(b, nil, 0, &p); | 
|  | if(n < 0) | 
|  | return -1; | 
|  | rv = enc64(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 upper16[] = "0123456789ABCDEF"; | 
|  | static char lower16[] = "0123456789abcdef"; | 
|  | static int | 
|  | to16(mpint *b, char *buf, int len, char *set16) | 
|  | { | 
|  | mpdigit *p, x; | 
|  | int i, j; | 
|  | char *out, *eout; | 
|  |  | 
|  | if(len < 1) | 
|  | return -1; | 
|  |  | 
|  | out = buf; | 
|  | eout = buf+len; | 
|  | for(p = &b->p[b->top-1]; p >= b->p; p--){ | 
|  | x = *p; | 
|  | for(i = Dbits-4; i >= 0; i -= 4){ | 
|  | j = 0xf & (x>>i); | 
|  | if(j != 0 || out != buf){ | 
|  | if(out >= eout) | 
|  | return -1; | 
|  | *out++ = set16[j]; | 
|  | } | 
|  | } | 
|  | } | 
|  | if(out == buf) | 
|  | *out++ = '0'; | 
|  | if(out >= eout) | 
|  | return -1; | 
|  | *out = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char* | 
|  | modbillion(int rem, ulong r, char *out, char *buf) | 
|  | { | 
|  | ulong rr; | 
|  | int i; | 
|  |  | 
|  | for(i = 0; i < 9; i++){ | 
|  | rr = r%10; | 
|  | r /= 10; | 
|  | if(out <= buf) | 
|  | return nil; | 
|  | *--out = '0' + rr; | 
|  | if(rem == 0 && r == 0) | 
|  | break; | 
|  | } | 
|  | return out; | 
|  | } | 
|  |  | 
|  | static int | 
|  | to10(mpint *b, char *buf, int len) | 
|  | { | 
|  | mpint *d, *r, *billion; | 
|  | char *out; | 
|  |  | 
|  | if(len < 1) | 
|  | return -1; | 
|  |  | 
|  | d = mpcopy(b); | 
|  | r = mpnew(0); | 
|  | billion = uitomp(1000000000, nil); | 
|  | out = buf+len; | 
|  | *--out = 0; | 
|  | do { | 
|  | mpdiv(d, billion, d, r); | 
|  | out = modbillion(d->top, r->p[0], out, buf); | 
|  | if(out == nil) | 
|  | break; | 
|  | } while(d->top != 0); | 
|  | mpfree(d); | 
|  | mpfree(r); | 
|  | mpfree(billion); | 
|  |  | 
|  | if(out == nil) | 
|  | return -1; | 
|  | len -= out-buf; | 
|  | if(out != buf) | 
|  | memmove(buf, out, len); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char* | 
|  | _mptoa(mpint *b, int base, char *buf, int len, char *set16) | 
|  | { | 
|  | char *out; | 
|  | int rv, alloced; | 
|  |  | 
|  | alloced = 0; | 
|  | if(buf == nil){ | 
|  | len = ((b->top+1)*Dbits+2)/3 + 1; | 
|  | buf = malloc(len); | 
|  | if(buf == nil) | 
|  | return nil; | 
|  | alloced = 1; | 
|  | } | 
|  |  | 
|  | if(len < 2) | 
|  | return nil; | 
|  |  | 
|  | out = buf; | 
|  | if(b->sign < 0){ | 
|  | *out++ = '-'; | 
|  | len--; | 
|  | } | 
|  | switch(base){ | 
|  | case 64: | 
|  | rv = to64(b, out, len); | 
|  | break; | 
|  | case 32: | 
|  | rv = to32(b, out, len); | 
|  | break; | 
|  | default: | 
|  | case 16: | 
|  | rv = to16(b, out, len, set16); | 
|  | break; | 
|  | case 10: | 
|  | rv = to10(b, out, len); | 
|  | break; | 
|  | } | 
|  | if(rv < 0){ | 
|  | if(alloced) | 
|  | free(buf); | 
|  | return nil; | 
|  | } | 
|  | return buf; | 
|  | } | 
|  |  | 
|  | char* | 
|  | mptoa(mpint *b, int base, char *buf, int len) | 
|  | { | 
|  | return _mptoa(b, base, buf, len, upper16); | 
|  | } | 
|  |  | 
|  | int | 
|  | mpfmt(Fmt *fmt) | 
|  | { | 
|  | mpint *b; | 
|  | char *p; | 
|  | char *set16; | 
|  |  | 
|  | b = va_arg(fmt->args, mpint*); | 
|  | if(b == nil) | 
|  | return fmtstrcpy(fmt, "*"); | 
|  |  | 
|  | set16 = upper16; | 
|  | if(fmt->flags & FmtLong) | 
|  | set16 = lower16; | 
|  | p = _mptoa(b, fmt->prec, nil, 0, set16); | 
|  | fmt->flags &= ~FmtPrec; | 
|  |  | 
|  | if(p == nil) | 
|  | return fmtstrcpy(fmt, "*"); | 
|  | else{ | 
|  | fmtstrcpy(fmt, p); | 
|  | free(p); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  |