Subversion Repositories planix.SVN

Rev

Rev 33 | Details | Compare with Previous | Last modification | View Log | RSS feed

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