]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmp/port/mpfmt.c
merge
[plan9front.git] / sys / src / libmp / port / mpfmt.c
1 #include "os.h"
2 #include <mp.h>
3 #include "dat.h"
4
5 static int
6 toencx(mpint *b, char *buf, int len, int (*enc)(char*, int, uchar*, int))
7 {
8         uchar *p;
9         int n, rv;
10
11         p = nil;
12         n = mptobe(b, nil, 0, &p);
13         if(n < 0)
14                 return -1;
15         rv = (*enc)(buf, len, p, n);
16         free(p);
17         return rv;
18 }
19
20 static int
21 topow2(mpint *b, char *buf, int len, int s)
22 {
23         mpdigit *p, x;
24         int i, j, sn;
25         char *out, *eout;
26
27         if(len < 1)
28                 return -1;
29
30         sn = 1<<s;
31         out = buf;
32         eout = buf+len;
33         for(p = &b->p[b->top-1]; p >= b->p; p--){
34                 x = *p;
35                 for(i = Dbits-s; i >= 0; i -= s){
36                         j = x >> i & sn - 1;
37                         if(j != 0 || out != buf){
38                                 if(out >= eout)
39                                         return -1;
40                                 *out++ = enc16chr(j);
41                         }
42                 }
43         }
44         if(out == buf)
45                 *out++ = '0';
46         if(out >= eout)
47                 return -1;
48         *out = 0;
49         return 0;
50 }
51
52 static char*
53 modbillion(int rem, ulong r, char *out, char *buf)
54 {
55         ulong rr;
56         int i;
57
58         for(i = 0; i < 9; i++){
59                 rr = r%10;
60                 r /= 10;
61                 if(out <= buf)
62                         return nil;
63                 *--out = '0' + rr;
64                 if(rem == 0 && r == 0)
65                         break;
66         }
67         return out;
68 }
69
70 static int
71 to10(mpint *b, char *buf, int len)
72 {
73         mpint *d, *r, *billion;
74         char *out;
75
76         if(len < 1)
77                 return -1;
78
79         d = mpcopy(b);
80         d->flags &= ~MPtimesafe;
81         mpnorm(d);
82         r = mpnew(0);
83         billion = uitomp(1000000000, nil);
84         out = buf+len;
85         *--out = 0;
86         do {
87                 mpdiv(d, billion, d, r);
88                 out = modbillion(d->top, r->p[0], out, buf);
89                 if(out == nil)
90                         break;
91         } while(d->top != 0);
92         mpfree(d);
93         mpfree(r);
94         mpfree(billion);
95
96         if(out == nil)
97                 return -1;
98         len -= out-buf;
99         if(out != buf)
100                 memmove(buf, out, len);
101         return 0;
102 }
103
104 static int
105 to8(mpint *b, char *buf, int len)
106 {
107         mpdigit x, y;
108         char *out;
109         int i, j;
110
111         if(len < 2)
112                 return -1;
113
114         out = buf+len;
115         *--out = 0;
116
117         i = j = 0;
118         x = y = 0;
119         while(j < b->top){
120                 y = b->p[j++];
121                 if(i > 0)
122                         x |= y << i;
123                 else
124                         x = y;
125                 i += Dbits;
126                 while(i >= 3){
127 Digout:                 i -= 3;
128                         if(out > buf)
129                                 out--;
130                         else if(x != 0)
131                                 return -1;
132                         *out = '0' + (x & 7);
133                         x = y >> Dbits-i;
134                 }
135         }
136         if(i > 0)
137                 goto Digout;
138
139         while(*out == '0') out++;
140         if(*out == '\0')
141                 *--out = '0';
142
143         len -= out-buf;
144         if(out != buf)
145                 memmove(buf, out, len);
146         return 0;
147 }
148
149 int
150 mpfmt(Fmt *fmt)
151 {
152         mpint *b;
153         char *x, *p;
154         int base;
155
156         b = va_arg(fmt->args, mpint*);
157         if(b == nil)
158                 return fmtstrcpy(fmt, "*");
159
160         base = fmt->prec;
161         if(base == 0)
162                 base = 16;      /* default */
163         fmt->flags &= ~FmtPrec;
164         p = mptoa(b, base, nil, 0);
165         if(p == nil)
166                 return fmtstrcpy(fmt, "*");
167         else{
168                 if((fmt->flags & FmtSharp) != 0){
169                         switch(base){
170                         case 16:
171                                 x = "0x";
172                                 break;
173                         case 8:
174                                 x = "0";
175                                 break;
176                         case 2:
177                                 x = "0b";
178                                 break;
179                         default:
180                                 x = "";
181                         }
182                         if(*p == '-')
183                                 fmtprint(fmt, "-%s%s", x, p + 1);
184                         else
185                                 fmtprint(fmt, "%s%s", x, p);
186                 }
187                 else
188                         fmtstrcpy(fmt, p);
189                 free(p);
190                 return 0;
191         }
192 }
193
194 char*
195 mptoa(mpint *b, int base, char *buf, int len)
196 {
197         char *out;
198         int rv, alloced;
199
200         if(base == 0)
201                 base = 16;      /* default */
202         alloced = 0;
203         if(buf == nil){
204                 /* rv <= logâ‚‚(base) */
205                 for(rv=1; (base >> rv) > 1; rv++)
206                         ;
207                 len = 10 + (b->top*Dbits / rv);
208                 buf = malloc(len);
209                 if(buf == nil)
210                         return nil;
211                 alloced = 1;
212         }
213
214         if(len < 2)
215                 return nil;
216
217         out = buf;
218         if(b->sign < 0){
219                 *out++ = '-';
220                 len--;
221         }
222         switch(base){
223         case 64:
224                 rv = toencx(b, out, len, enc64);
225                 break;
226         case 32:
227                 rv = toencx(b, out, len, enc32);
228                 break;
229         case 16:
230                 rv = topow2(b, out, len, 4);
231                 break;
232         case 10:
233                 rv = to10(b, out, len);
234                 break;
235         case 8:
236                 rv = to8(b, out, len);
237                 break;
238         case 4:
239                 rv = topow2(b, out, len, 2);
240                 break;
241         case 2:
242                 rv = topow2(b, out, len, 1);
243                 break;
244         default:
245                 abort();
246                 return nil;
247         }
248         if(rv < 0){
249                 if(alloced)
250                         free(buf);
251                 return nil;
252         }
253         return buf;
254 }