/* cvt.c (emx+gcc) -- Copyright (c) 1994 by Eberhard Mattes */

#include <sys/emx.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <float.h>


/* Convert a non-zero floating point number to a string of decimal
   digits and an exponent.  The position of the decimal point is
   assumed to be after the first digit.  Examples:

   1234567890123456789 --> 1234567890123456789, xp = 18
   123                 --> 1230000000000000000, xp =  2
   12                  --> 1200000000000000000, xp =  1
   1.2                 --> 1200000000000000000, xp =  0
   0.12                --> 1200000000000000000, xp = -1

   This function assumes that

     LDBL_MANT_DIG <= 8 * sizeof (unsigned long long)

   which is true for the extended real format (64-bit mantissa).
   There are algothms which are more precise, but they're MUCH more
   complicated. */

int _cvt_float_decimal (DOUBLE x, char *dst)
{
  DOUBLE scaled;
  unsigned long long intg;
  int xp, len;

  xp = (int)FLOOR (LOG10 (x));
  scaled = x * POW (10.0, DIG - 1 - xp);

  intg = (unsigned long long)scaled;
  _ulltoa (intg, dst, 10);

  len = strlen (dst);
  if (len > DIG + 1)
    abort ();
  else if (len == DIG + 1)
    {
      ++xp;
      dst[DIG] = 0;
    }
  else if (len < DIG)
    {
      xp -= DIG - len;
      memset (dst + len, '0', DIG - len);
      dst[DIG] = 0;
    }

  return (xp);
}


/* Round a string of digits for truncating after PREC digits.  Adjust
   the exponent (pointed to by PXP) if required (for instance when
   rounding "9999" to "1000"). */

void _cvt_round (char *dst, int *pxp, int prec, int lim)
{

  /* Reduce the number of digits to the number of significant digits.
   This is used to print zeros instead of `random' digits when
   converting `double' floats with `long double' precision. */

  if (prec > lim)
    prec = lim;                 /* LIM is always <= DIG */
  if (prec < 1)
    prec = 1;

  if (dst[prec] >= '5')
    {
      int i = prec;
      while (i != 0 && dst[i-1] == '9')
        {
          dst[i-1] = '0';
          --i;
        }
      if (i != 0)
        ++dst[i-1];
      else
        {
          memmove (dst + 1, dst, DIG - 1);
          dst[0] = '1';
          ++*pxp;
        }
    }
  memset (dst + prec, '0', DIG - prec);
}


/* Remove trailing zeros from DIGITS for the "%g" format.  Keep at
   least KEEP digits at the start of DIGITS. */

void _cvt_remove_zeros (char *digits, int keep)
{
  int i;

  i = strlen (digits) - 1;
  while (i >= keep && digits[i] == '0')
    --i;
  digits[i+1] = 0;
}


const char *_cvt_nan (int xam)
{
  switch (xam)
    {
    case FX_P_NAN:
    case FX_N_NAN:
      return ("#NAN");
    case FX_P_INFINITY:
      return ("#INF");
    case FX_N_INFINITY:
      return ("-#INF");
    case FX_P_EMPTY:
      return ("#EMP");
    case FX_N_EMPTY:
      return ("-#EMP");
    default:
      return (NULL);
    }
}
