gfltconv.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "lib9.h"
  2. #include "mathi.h"
  3. extern char *dtoa(double, int, int, int *, int *, char **);
  4. extern void freedtoa(char*);
  5. extern int _fmtcpy(Fmt*, void*, int, int);
  6. enum
  7. {
  8. NONE = -1000,
  9. FDIGIT = 20,
  10. FDEFLT = 6,
  11. NSIGNIF = 17
  12. };
  13. int
  14. gfltconv(Fmt *f)
  15. {
  16. int flags = f->flags;
  17. int precision;
  18. int fmt = f->r;
  19. double d;
  20. int echr, exponent, sign, ndig, nout, i;
  21. char *digits, *edigits, ebuf[32], *eptr;
  22. char out[64], *pout;
  23. d = va_arg(f->args, double);
  24. echr = 'e';
  25. precision = FDEFLT;
  26. if(f->flags & FmtPrec)
  27. precision = f->prec;
  28. if(precision > FDIGIT)
  29. precision = FDIGIT;
  30. switch(fmt){
  31. case 'f':
  32. digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
  33. break;
  34. case 0x00c9: /* L'É' */
  35. case 'E':
  36. echr = 'E';
  37. fmt = 'e';
  38. /* fall through */
  39. case 'e':
  40. digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
  41. break;
  42. case 'G':
  43. echr = 'E';
  44. /* fall through */
  45. default:
  46. case 'g':
  47. if((flags&(FmtWidth|FmtPrec)) == 0){
  48. g_fmt(out, d, echr);
  49. f->flags &= FmtWidth|FmtLeft;
  50. return _fmtcpy(f, out, strlen(out), strlen(out));
  51. }
  52. if (precision > 0)
  53. digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
  54. else {
  55. digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
  56. precision = edigits - digits;
  57. if (exponent > precision && exponent <= precision + 4)
  58. precision = exponent;
  59. }
  60. if(exponent >= -3 && exponent <= precision){
  61. fmt = 'f';
  62. precision -= exponent;
  63. }else{
  64. fmt = 'e';
  65. --precision;
  66. }
  67. break;
  68. }
  69. if (exponent == 9999) {
  70. /* Infinity or Nan */
  71. precision = 0;
  72. exponent = edigits - digits;
  73. fmt = 'f';
  74. }
  75. ndig = edigits-digits;
  76. if((f->r=='g' || f->r=='G') && !(flags&FmtSharp)){ /* knock off trailing zeros */
  77. if(fmt == 'f'){
  78. if(precision+exponent > ndig) {
  79. precision = ndig - exponent;
  80. if(precision < 0)
  81. precision = 0;
  82. }
  83. }
  84. else{
  85. if(precision > ndig-1) precision = ndig-1;
  86. }
  87. }
  88. eptr = ebuf;
  89. if(fmt != 'f'){ /* exponent */
  90. for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
  91. *eptr++ = '0' + i%10;
  92. while(eptr<ebuf+2) *eptr++ = '0';
  93. }
  94. pout = out;
  95. if(sign) *pout++ = '-';
  96. else if(flags&FmtSign) *pout++ = '+';
  97. else if(flags&FmtSpace) *pout++ = ' ';
  98. if(fmt == 'f'){
  99. for(i=0; i<exponent; i++) *pout++ = i<ndig?digits[i]:'0';
  100. if(i == 0) *pout++ = '0';
  101. if(precision>0 || flags&FmtSharp) *pout++ = '.';
  102. for(i=0; i!=precision; i++)
  103. *pout++ = 0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0';
  104. }
  105. else{
  106. *pout++ = digits[0];
  107. if(precision>0 || flags&FmtSharp) *pout++ = '.';
  108. for(i=0; i!=precision; i++) *pout++ = i<ndig-1?digits[i+1]:'0';
  109. }
  110. if(fmt != 'f'){
  111. *pout++ = echr;
  112. *pout++ = exponent<=0?'-':'+';
  113. while(eptr>ebuf) *pout++ = *--eptr;
  114. }
  115. *pout = 0;
  116. freedtoa(digits);
  117. f->flags &= FmtWidth|FmtLeft;
  118. nout = pout-out;
  119. return _fmtcpy(f, out, nout, nout);
  120. }