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 }