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 upper16[] = "0123456789ABCDEF";
44 static char lower16[] = "0123456789abcdef";
45 static int
46 to16(mpint *b, char *buf, int len, char *set16)
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 static char*
127 _mptoa(mpint *b, int base, char *buf, int len, char *set16)
129 char *out;
130 int rv, alloced;
132 alloced = 0;
133 if(buf == nil){
134 len = ((b->top+1)*Dbits+2)/3 + 1;
135 buf = malloc(len);
136 if(buf == nil)
137 return nil;
138 alloced = 1;
141 if(len < 2)
142 return nil;
144 out = buf;
145 if(b->sign < 0){
146 *out++ = '-';
147 len--;
149 switch(base){
150 case 64:
151 rv = to64(b, out, len);
152 break;
153 case 32:
154 rv = to32(b, out, len);
155 break;
156 default:
157 case 16:
158 rv = to16(b, out, len, set16);
159 break;
160 case 10:
161 rv = to10(b, out, len);
162 break;
164 if(rv < 0){
165 if(alloced)
166 free(buf);
167 return nil;
169 return buf;
172 char*
173 mptoa(mpint *b, int base, char *buf, int len)
175 return _mptoa(b, base, buf, len, upper16);
178 int
179 mpfmt(Fmt *fmt)
181 mpint *b;
182 char *p;
183 char *set16;
185 b = va_arg(fmt->args, mpint*);
186 if(b == nil)
187 return fmtstrcpy(fmt, "*");
189 set16 = upper16;
190 if(fmt->flags & FmtLong)
191 set16 = lower16;
192 p = _mptoa(b, fmt->prec, nil, 0, set16);
193 fmt->flags &= ~FmtPrec;
195 if(p == nil)
196 return fmtstrcpy(fmt, "*");
197 else{
198 fmtstrcpy(fmt, p);
199 free(p);
200 return 0;