plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

mpfmt.c (2986B)


      1 #include "os.h"
      2 #include <mp.h>
      3 #include "dat.h"
      4 
      5 static int
      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
     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
     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*
     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
     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*
    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*
    173 mptoa(mpint *b, int base, char *buf, int len)
    174 {
    175 	return _mptoa(b, base, buf, len, upper16);
    176 }
    177 
    178 int
    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 }