Blob


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