1 #include "os.h" 2 #include <mp.h> 3 #include <libsec.h> 4 #include "dat.h" 5 6 static int 7 to64(mpint *b, char *buf, int len) 8 { 9 uchar *p; 10 int n, rv; 11 12 p = nil; 13 n = mptobe(b, nil, 0, &p); 14 if(n < 0) 15 return -1; 16 rv = enc64(buf, len, p, n); 17 free(p); 18 return rv; 19 } 20 21 static int 22 to32(mpint *b, char *buf, int len) 23 { 24 uchar *p; 25 int n, rv; 26 27 // leave room for a multiple of 5 buffer size 28 n = b->top*Dbytes + 5; 29 p = malloc(n); 30 if(p == nil) 31 return -1; 32 n = mptobe(b, p, n, nil); 33 if(n < 0) 34 return -1; 35 36 // round up buffer size, enc32 only accepts a multiple of 5 37 if(n%5) 38 n += 5 - (n%5); 39 rv = enc32(buf, len, p, n); 40 free(p); 41 return rv; 42 } 43 44 static char set16[] = "0123456789ABCDEF"; 45 46 static int 47 to16(mpint *b, char *buf, int len) 48 { 49 mpdigit *p, x; 50 int i, j; 51 char *out, *eout; 52 53 if(len < 1) 54 return -1; 55 56 out = buf; 57 eout = buf+len; 58 for(p = &b->p[b->top-1]; p >= b->p; p--){ 59 x = *p; 60 for(i = Dbits-4; i >= 0; i -= 4){ 61 j = 0xf & (x>>i); 62 if(j != 0 || out != buf){ 63 if(out >= eout) 64 return -1; 65 *out++ = set16[j]; 66 } 67 } 68 } 69 if(out == buf) 70 *out++ = '0'; 71 if(out >= eout) 72 return -1; 73 *out = 0; 74 return 0; 75 } 76 77 static char* 78 modbillion(int rem, ulong r, char *out, char *buf) 79 { 80 ulong rr; 81 int i; 82 83 for(i = 0; i < 9; i++){ 84 rr = r%10; 85 r /= 10; 86 if(out <= buf) 87 return nil; 88 *--out = '0' + rr; 89 if(rem == 0 && r == 0) 90 break; 91 } 92 return out; 93 } 94 95 static int 96 to10(mpint *b, char *buf, int len) 97 { 98 mpint *d, *r, *billion; 99 char *out; 100 101 if(len < 1) 102 return -1; 103 104 d = mpcopy(b); 105 r = mpnew(0); 106 billion = uitomp(1000000000, nil); 107 out = buf+len; 108 *--out = 0; 109 do { 110 mpdiv(d, billion, d, r); 111 out = modbillion(d->top, r->p[0], out, buf); 112 if(out == nil) 113 break; 114 } while(d->top != 0); 115 mpfree(d); 116 mpfree(r); 117 mpfree(billion); 118 119 if(out == nil) 120 return -1; 121 len -= out-buf; 122 if(out != buf) 123 memmove(buf, out, len); 124 return 0; 125 } 126 127 int 128 mpfmt(Fmt *fmt) 129 { 130 mpint *b; 131 char *p; 132 133 b = va_arg(fmt->args, mpint*); 134 if(b == nil) 135 return fmtstrcpy(fmt, "*"); 136 137 p = mptoa(b, fmt->prec, nil, 0); 138 fmt->flags &= ~FmtPrec; 139 140 if(p == nil) 141 return fmtstrcpy(fmt, "*"); 142 else{ 143 fmtstrcpy(fmt, p); 144 free(p); 145 return 0; 146 } 147 } 148 149 char* 150 mptoa(mpint *b, int base, char *buf, int len) 151 { 152 char *out; 153 int rv, alloced; 154 155 alloced = 0; 156 if(buf == nil){ 157 len = ((b->top+1)*Dbits+2)/3 + 1; 158 buf = malloc(len); 159 if(buf == nil) 160 return nil; 161 alloced = 1; 162 } 163 164 if(len < 2) 165 return nil; 166 167 out = buf; 168 if(b->sign < 0){ 169 *out++ = '-'; 170 len--; 171 } 172 switch(base){ 173 case 64: 174 rv = to64(b, out, len); 175 break; 176 case 32: 177 rv = to32(b, out, len); 178 break; 179 default: 180 case 16: 181 rv = to16(b, out, len); 182 break; 183 case 10: 184 rv = to10(b, out, len); 185 break; 186 } 187 if(rv < 0){ 188 if(alloced) 189 free(buf); 190 return nil; 191 } 192 return buf; 193 } 194