xref: /plan9/sys/src/libmp/port/mpfmt.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
19a747e4fSDavid du Colombier #include "os.h"
29a747e4fSDavid du Colombier #include <mp.h>
39a747e4fSDavid du Colombier #include <libsec.h>
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier static int
to64(mpint * b,char * buf,int len)79a747e4fSDavid du Colombier to64(mpint *b, char *buf, int len)
89a747e4fSDavid du Colombier {
99a747e4fSDavid du Colombier 	uchar *p;
109a747e4fSDavid du Colombier 	int n, rv;
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier 	p = nil;
139a747e4fSDavid du Colombier 	n = mptobe(b, nil, 0, &p);
149a747e4fSDavid du Colombier 	if(n < 0)
159a747e4fSDavid du Colombier 		return -1;
169a747e4fSDavid du Colombier 	rv = enc64(buf, len, p, n);
179a747e4fSDavid du Colombier 	free(p);
189a747e4fSDavid du Colombier 	return rv;
199a747e4fSDavid du Colombier }
209a747e4fSDavid du Colombier 
219a747e4fSDavid du Colombier static int
to32(mpint * b,char * buf,int len)229a747e4fSDavid du Colombier to32(mpint *b, char *buf, int len)
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier 	uchar *p;
259a747e4fSDavid du Colombier 	int n, rv;
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier 	// leave room for a multiple of 5 buffer size
289a747e4fSDavid du Colombier 	n = b->top*Dbytes + 5;
299a747e4fSDavid du Colombier 	p = malloc(n);
309a747e4fSDavid du Colombier 	if(p == nil)
319a747e4fSDavid du Colombier 		return -1;
329a747e4fSDavid du Colombier 	n = mptobe(b, p, n, nil);
339a747e4fSDavid du Colombier 	if(n < 0)
349a747e4fSDavid du Colombier 		return -1;
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier 	// round up buffer size, enc32 only accepts a multiple of 5
379a747e4fSDavid du Colombier 	if(n%5)
389a747e4fSDavid du Colombier 		n += 5 - (n%5);
399a747e4fSDavid du Colombier 	rv = enc32(buf, len, p, n);
409a747e4fSDavid du Colombier 	free(p);
419a747e4fSDavid du Colombier 	return rv;
429a747e4fSDavid du Colombier }
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier static char set16[] = "0123456789ABCDEF";
459a747e4fSDavid du Colombier 
469a747e4fSDavid du Colombier static int
to16(mpint * b,char * buf,int len)479a747e4fSDavid du Colombier to16(mpint *b, char *buf, int len)
489a747e4fSDavid du Colombier {
499a747e4fSDavid du Colombier 	mpdigit *p, x;
509a747e4fSDavid du Colombier 	int i, j;
519a747e4fSDavid du Colombier 	char *out, *eout;
529a747e4fSDavid du Colombier 
539a747e4fSDavid du Colombier 	if(len < 1)
549a747e4fSDavid du Colombier 		return -1;
559a747e4fSDavid du Colombier 
569a747e4fSDavid du Colombier 	out = buf;
579a747e4fSDavid du Colombier 	eout = buf+len;
589a747e4fSDavid du Colombier 	for(p = &b->p[b->top-1]; p >= b->p; p--){
599a747e4fSDavid du Colombier 		x = *p;
609a747e4fSDavid du Colombier 		for(i = Dbits-4; i >= 0; i -= 4){
619a747e4fSDavid du Colombier 			j = 0xf & (x>>i);
629a747e4fSDavid du Colombier 			if(j != 0 || out != buf){
639a747e4fSDavid du Colombier 				if(out >= eout)
649a747e4fSDavid du Colombier 					return -1;
659a747e4fSDavid du Colombier 				*out++ = set16[j];
669a747e4fSDavid du Colombier 			}
679a747e4fSDavid du Colombier 		}
689a747e4fSDavid du Colombier 	}
699a747e4fSDavid du Colombier 	if(out == buf)
709a747e4fSDavid du Colombier 		*out++ = '0';
719a747e4fSDavid du Colombier 	if(out >= eout)
729a747e4fSDavid du Colombier 		return -1;
739a747e4fSDavid du Colombier 	*out = 0;
749a747e4fSDavid du Colombier 	return 0;
759a747e4fSDavid du Colombier }
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier static char*
modbillion(int rem,ulong r,char * out,char * buf)789a747e4fSDavid du Colombier modbillion(int rem, ulong r, char *out, char *buf)
799a747e4fSDavid du Colombier {
809a747e4fSDavid du Colombier 	ulong rr;
819a747e4fSDavid du Colombier 	int i;
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier 	for(i = 0; i < 9; i++){
849a747e4fSDavid du Colombier 		rr = r%10;
859a747e4fSDavid du Colombier 		r /= 10;
869a747e4fSDavid du Colombier 		if(out <= buf)
879a747e4fSDavid du Colombier 			return nil;
889a747e4fSDavid du Colombier 		*--out = '0' + rr;
899a747e4fSDavid du Colombier 		if(rem == 0 && r == 0)
909a747e4fSDavid du Colombier 			break;
919a747e4fSDavid du Colombier 	}
929a747e4fSDavid du Colombier 	return out;
939a747e4fSDavid du Colombier }
949a747e4fSDavid du Colombier 
959a747e4fSDavid du Colombier static int
to10(mpint * b,char * buf,int len)969a747e4fSDavid du Colombier to10(mpint *b, char *buf, int len)
979a747e4fSDavid du Colombier {
989a747e4fSDavid du Colombier 	mpint *d, *r, *billion;
999a747e4fSDavid du Colombier 	char *out;
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier 	if(len < 1)
1029a747e4fSDavid du Colombier 		return -1;
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier 	d = mpcopy(b);
1059a747e4fSDavid du Colombier 	r = mpnew(0);
1069a747e4fSDavid du Colombier 	billion = uitomp(1000000000, nil);
1079a747e4fSDavid du Colombier 	out = buf+len;
1089a747e4fSDavid du Colombier 	*--out = 0;
1099a747e4fSDavid du Colombier 	do {
1109a747e4fSDavid du Colombier 		mpdiv(d, billion, d, r);
1119a747e4fSDavid du Colombier 		out = modbillion(d->top, r->p[0], out, buf);
1129a747e4fSDavid du Colombier 		if(out == nil)
1139a747e4fSDavid du Colombier 			break;
1149a747e4fSDavid du Colombier 	} while(d->top != 0);
1159a747e4fSDavid du Colombier 	mpfree(d);
1169a747e4fSDavid du Colombier 	mpfree(r);
1179a747e4fSDavid du Colombier 	mpfree(billion);
1189a747e4fSDavid du Colombier 
1199a747e4fSDavid du Colombier 	if(out == nil)
1209a747e4fSDavid du Colombier 		return -1;
1219a747e4fSDavid du Colombier 	len -= out-buf;
1229a747e4fSDavid du Colombier 	if(out != buf)
1239a747e4fSDavid du Colombier 		memmove(buf, out, len);
1249a747e4fSDavid du Colombier 	return 0;
1259a747e4fSDavid du Colombier }
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier int
mpfmt(Fmt * fmt)1289a747e4fSDavid du Colombier mpfmt(Fmt *fmt)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier 	mpint *b;
1319a747e4fSDavid du Colombier 	char *p;
1329a747e4fSDavid du Colombier 
1339a747e4fSDavid du Colombier 	b = va_arg(fmt->args, mpint*);
134*6b6b9ac8SDavid du Colombier 	if(b == nil)
135*6b6b9ac8SDavid du Colombier 		return fmtstrcpy(fmt, "*");
136*6b6b9ac8SDavid du Colombier 
1379a747e4fSDavid du Colombier 	p = mptoa(b, fmt->prec, nil, 0);
1389a747e4fSDavid du Colombier 	fmt->flags &= ~FmtPrec;
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier 	if(p == nil)
1419a747e4fSDavid du Colombier 		return fmtstrcpy(fmt, "*");
1429a747e4fSDavid du Colombier 	else{
1439a747e4fSDavid du Colombier 		fmtstrcpy(fmt, p);
1449a747e4fSDavid du Colombier 		free(p);
1459a747e4fSDavid du Colombier 		return 0;
1469a747e4fSDavid du Colombier 	}
1479a747e4fSDavid du Colombier }
1489a747e4fSDavid du Colombier 
1499a747e4fSDavid du Colombier char*
mptoa(mpint * b,int base,char * buf,int len)1509a747e4fSDavid du Colombier mptoa(mpint *b, int base, char *buf, int len)
1519a747e4fSDavid du Colombier {
1529a747e4fSDavid du Colombier 	char *out;
1539a747e4fSDavid du Colombier 	int rv, alloced;
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier 	alloced = 0;
1569a747e4fSDavid du Colombier 	if(buf == nil){
1579a747e4fSDavid du Colombier 		len = ((b->top+1)*Dbits+2)/3 + 1;
1589a747e4fSDavid du Colombier 		buf = malloc(len);
1599a747e4fSDavid du Colombier 		if(buf == nil)
1609a747e4fSDavid du Colombier 			return nil;
1619a747e4fSDavid du Colombier 		alloced = 1;
1629a747e4fSDavid du Colombier 	}
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	if(len < 2)
1659a747e4fSDavid du Colombier 		return nil;
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier 	out = buf;
1689a747e4fSDavid du Colombier 	if(b->sign < 0){
1699a747e4fSDavid du Colombier 		*out++ = '-';
1709a747e4fSDavid du Colombier 		len--;
1719a747e4fSDavid du Colombier 	}
1729a747e4fSDavid du Colombier 	switch(base){
1739a747e4fSDavid du Colombier 	case 64:
1749a747e4fSDavid du Colombier 		rv = to64(b, out, len);
1759a747e4fSDavid du Colombier 		break;
1769a747e4fSDavid du Colombier 	case 32:
1779a747e4fSDavid du Colombier 		rv = to32(b, out, len);
1789a747e4fSDavid du Colombier 		break;
1799a747e4fSDavid du Colombier 	default:
1809a747e4fSDavid du Colombier 	case 16:
1819a747e4fSDavid du Colombier 		rv = to16(b, out, len);
1829a747e4fSDavid du Colombier 		break;
1839a747e4fSDavid du Colombier 	case 10:
1849a747e4fSDavid du Colombier 		rv = to10(b, out, len);
1859a747e4fSDavid du Colombier 		break;
1869a747e4fSDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	if(rv < 0){
1889a747e4fSDavid du Colombier 		if(alloced)
1899a747e4fSDavid du Colombier 			free(buf);
1909a747e4fSDavid du Colombier 		return nil;
1919a747e4fSDavid du Colombier 	}
1929a747e4fSDavid du Colombier 	return buf;
1939a747e4fSDavid du Colombier }
194