1 #include "os.h"
2 #include <mp.h>
3 #include "dat.h"
4 
5 static int
to64(mpint * b,char * buf,int len)6 to64(mpint *b, char *buf, int len)
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 = enc64(buf, len, p, n);
16 	free(p);
17 	return rv;
18 }
19 
20 static int
to32(mpint * b,char * buf,int len)21 to32(mpint *b, char *buf, int len)
22 {
23 	uchar *p;
24 	int n, rv;
25 
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;
34 
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 }
42 
43 static char upper16[] = "0123456789ABCDEF";
44 static char lower16[] = "0123456789abcdef";
45 static int
to16(mpint * b,char * buf,int len,char * set16)46 to16(mpint *b, char *buf, int len, char *set16)
47 {
48 	mpdigit *p, x;
49 	int i, j;
50 	char *out, *eout;
51 
52 	if(len < 1)
53 		return -1;
54 
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 }
75 
76 static char*
modbillion(int rem,ulong r,char * out,char * buf)77 modbillion(int rem, ulong r, char *out, char *buf)
78 {
79 	ulong rr;
80 	int i;
81 
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 }
93 
94 static int
to10(mpint * b,char * buf,int len)95 to10(mpint *b, char *buf, int len)
96 {
97 	mpint *d, *r, *billion;
98 	char *out;
99 
100 	if(len < 1)
101 		return -1;
102 
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);
117 
118 	if(out == nil)
119 		return -1;
120 	len -= out-buf;
121 	if(out != buf)
122 		memmove(buf, out, len);
123 	return 0;
124 }
125 
126 static char*
_mptoa(mpint * b,int base,char * buf,int len,char * set16)127 _mptoa(mpint *b, int base, char *buf, int len, char *set16)
128 {
129 	char *out;
130 	int rv, alloced;
131 
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;
139 	}
140 
141 	if(len < 2)
142 		return nil;
143 
144 	out = buf;
145 	if(b->sign < 0){
146 		*out++ = '-';
147 		len--;
148 	}
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;
163 	}
164 	if(rv < 0){
165 		if(alloced)
166 			free(buf);
167 		return nil;
168 	}
169 	return buf;
170 }
171 
172 char*
mptoa(mpint * b,int base,char * buf,int len)173 mptoa(mpint *b, int base, char *buf, int len)
174 {
175 	return _mptoa(b, base, buf, len, upper16);
176 }
177 
178 int
mpfmt(Fmt * fmt)179 mpfmt(Fmt *fmt)
180 {
181 	mpint *b;
182 	char *p;
183 	char *set16;
184 
185 	b = va_arg(fmt->args, mpint*);
186 	if(b == nil)
187 		return fmtstrcpy(fmt, "*");
188 
189 	set16 = upper16;
190 	if(fmt->flags & FmtLong)
191 		set16 = lower16;
192 	p = _mptoa(b, fmt->prec, nil, 0, set16);
193 	fmt->flags &= ~FmtPrec;
194 
195 	if(p == nil)
196 		return fmtstrcpy(fmt, "*");
197 	else{
198 		fmtstrcpy(fmt, p);
199 		free(p);
200 		return 0;
201 	}
202 }
203