mpfmt.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "os.h"
  2. #include <mp.h>
  3. #include <libsec.h>
  4. #include "dat.h"
  5. static int
  6. to64(mpint *b, char *buf, int len)
  7. {
  8. uchar *p;
  9. int n, rv;
  10. p = nil;
  11. n = mptobe(b, nil, 0, &p);
  12. if(n < 0)
  13. return -1;
  14. rv = enc64(buf, len, p, n);
  15. free(p);
  16. return rv;
  17. }
  18. static int
  19. to32(mpint *b, char *buf, int len)
  20. {
  21. uchar *p;
  22. int n, rv;
  23. // leave room for a multiple of 5 buffer size
  24. n = b->top*Dbytes + 5;
  25. p = malloc(n);
  26. if(p == nil)
  27. return -1;
  28. n = mptobe(b, p, n, nil);
  29. if(n < 0)
  30. return -1;
  31. // round up buffer size, enc32 only accepts a multiple of 5
  32. if(n%5)
  33. n += 5 - (n%5);
  34. rv = enc32(buf, len, p, n);
  35. free(p);
  36. return rv;
  37. }
  38. static char set16[] = "0123456789ABCDEF";
  39. static int
  40. to16(mpint *b, char *buf, int len)
  41. {
  42. mpdigit *p, x;
  43. int i, j;
  44. char *out, *eout;
  45. if(len < 1)
  46. return -1;
  47. out = buf;
  48. eout = buf+len;
  49. for(p = &b->p[b->top-1]; p >= b->p; p--){
  50. x = *p;
  51. for(i = Dbits-4; i >= 0; i -= 4){
  52. j = 0xf & (x>>i);
  53. if(j != 0 || out != buf){
  54. if(out >= eout)
  55. return -1;
  56. *out++ = set16[j];
  57. }
  58. }
  59. }
  60. if(out == buf)
  61. *out++ = '0';
  62. if(out >= eout)
  63. return -1;
  64. *out = 0;
  65. return 0;
  66. }
  67. static char*
  68. modbillion(int rem, ulong r, char *out, char *buf)
  69. {
  70. ulong rr;
  71. int i;
  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. static int
  84. to10(mpint *b, char *buf, int len)
  85. {
  86. mpint *d, *r, *billion;
  87. char *out;
  88. if(len < 1)
  89. return -1;
  90. d = mpcopy(b);
  91. r = mpnew(0);
  92. billion = uitomp(1000000000, nil);
  93. out = buf+len;
  94. *--out = 0;
  95. do {
  96. mpdiv(d, billion, d, r);
  97. out = modbillion(d->top, r->p[0], out, buf);
  98. if(out == nil)
  99. break;
  100. } while(d->top != 0);
  101. mpfree(d);
  102. mpfree(r);
  103. mpfree(billion);
  104. if(out == nil)
  105. return -1;
  106. len -= out-buf;
  107. if(out != buf)
  108. memmove(buf, out, len);
  109. return 0;
  110. }
  111. int
  112. mpfmt(Fmt *fmt)
  113. {
  114. mpint *b;
  115. char *p;
  116. b = va_arg(fmt->args, mpint*);
  117. p = mptoa(b, fmt->prec, nil, 0);
  118. fmt->flags &= ~FmtPrec;
  119. if(p == nil)
  120. return fmtstrcpy(fmt, "*");
  121. else{
  122. fmtstrcpy(fmt, p);
  123. free(p);
  124. return 0;
  125. }
  126. }
  127. char*
  128. mptoa(mpint *b, int base, char *buf, int len)
  129. {
  130. char *out;
  131. int rv, alloced;
  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. if(len < 2)
  141. return nil;
  142. out = buf;
  143. if(b->sign < 0){
  144. *out++ = '-';
  145. len--;
  146. }
  147. switch(base){
  148. case 64:
  149. rv = to64(b, out, len);
  150. break;
  151. case 32:
  152. rv = to32(b, out, len);
  153. break;
  154. default:
  155. case 16:
  156. rv = to16(b, out, len);
  157. break;
  158. case 10:
  159. rv = to10(b, out, len);
  160. break;
  161. }
  162. if(rv < 0){
  163. if(alloced)
  164. free(buf);
  165. return nil;
  166. }
  167. return buf;
  168. }