xref: /inferno-os/libmp/port/mpfmt.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
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