| #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; |
| } |
| } |
| |