#include <math.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/timeb.h>

/*
 *
 */

void
ftime( struct timeb * now )
{
    struct timeval time_val;
    struct timezone time_zone;
    struct tm * localtime_p;

    now->time     = 0;
    now->millitm  = 0;
    now->timezone = 0;
    now->dstflag  = 0;

    if( gettimeofday( &time_val, &time_zone ) )
      return;

    now->time     = time_val.tv_sec;
    now->millitm  = time_val.tv_usec * 1000;

    localtime_p   = localtime( &time_val.tv_sec );
    now->timezone = localtime_p->tm_gmtoff / 60;
    now->dstflag  = localtime_p->tm_isdst;

    return;
}

/*
 *
 */

double
strtod( const char * nstr, char ** endptr )
{
    enum State      { INITIAL, AFTER_SIGN, AFTER_POINT, BEGINNING_DIGITS,
                      ENDING_DIGITS, AFTER_E, EXPONENT_DIGITS,
                      AFTER_EXPONENT_SIGN,
                      END, ERROR
                    };
    enum State      state = INITIAL;
    register char * p = nstr;
    register char   c;
    int             ndigits = 0;
    int             neg = 1;
    int             negexp = 1;
    double          fl = 0.0;
    static double   twoemax = 9007199254740992.;      /*2^53*/
    int             exp = 0;
    int             eexp = 0;


    while( state != ERROR )
      {
        c = *p++;
        switch( state )
          {
            case INITIAL:     /* ========== */
              switch( c )
                {
                 case ' ':
                 case '\t':
                 case '\r':
                 case '\n':
                 case '\v':
                 case '\f':
                   break;

                 case '+':
                   neg = 1;
                   state = AFTER_SIGN;
                   break;

                 case '-':
                   neg = -1;
                   state = AFTER_SIGN;
                   break;

                 case '.':
                   state = AFTER_POINT;
                   break;

                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   state = BEGINNING_DIGITS;
                   fl = (double)(c - '0');
                   ndigits++;
                   break;

                 default:
                   state = ERROR;
                   break;

                }
              break;

            case AFTER_SIGN:     /* ========== */
              switch( c )
                {
                 case '.':
                   state = AFTER_POINT;
                   break;

                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   state = BEGINNING_DIGITS;
                   fl = (double)(c - '0');
                   ndigits++;
                   break;

                 default:
                   state = ERROR;
                   break;
                }
              break;

            case AFTER_POINT:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   state = ENDING_DIGITS;
                   if( fl < twoemax )
                     {
                       fl = 10 * fl + (double)(c - '0');
                       --exp;
                     }
                   ndigits++;
                   break;

                 case 'E':
                 case 'e':
                   if( ndigits )
                     state = AFTER_E;
                   else
                     state = ERROR;
                   break;

                 default:
                   if( ndigits )
                     state = END;
                   else
                     state = ERROR;
                   break;
                }
              break;

            case BEGINNING_DIGITS:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   if( fl < twoemax )
                     {
                       fl = 10 * fl + (double)(c - '0');
                     }
                   else
                     exp++;
                   ndigits++;
                   break;

                 case '.':
                   state = AFTER_POINT;
                   break;

                 case 'E':
                 case 'e':
                   state = AFTER_E;
                   break;

                 default:
                   state = END;
                   break;
                }
              break;

            case ENDING_DIGITS:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   if( fl < twoemax )
                     {
                       fl = 10 * fl + (double)(c - '0');
                       --exp;
                     }
                   ndigits++;
                   break;

                 case 'E':
                 case 'e':
                   state = AFTER_E;
                   break;

                 default:
                   state = END;
                   break;
                }
              break;

            case AFTER_E:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   state = EXPONENT_DIGITS;
                   eexp = ( c - '0' );
                   break;

                 case '+':
                   state = AFTER_EXPONENT_SIGN;
                   negexp = 1;
                   break;

                 case '-':
                   state = AFTER_EXPONENT_SIGN;
                   negexp = -1;
                   break;

                 default:
                   state = ERROR;
                }
              break;

            case EXPONENT_DIGITS:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   eexp = eexp * 10 + ( c - '0' );
                   break;

                 default:
                   state = END;
                }
              break;

            case AFTER_EXPONENT_SIGN:     /* ========== */
              switch( c )
                {
                 case '0':
                 case '1':
                 case '2':
                 case '3':
                 case '4':
                 case '5':
                 case '6':
                 case '7':
                 case '8':
                 case '9':
                   state = EXPONENT_DIGITS;
                   eexp = ( c - '0' );
                   break;

                 default:
                   state = ERROR;
                }
              break;

            case END:     /* ========== */
              if( endptr != (char **)0 )
                *endptr = p - 2;
              if( negexp < 0 )
                exp -= eexp;
              else
                exp += eexp;
              fl *= pow( 10.0, (double)(exp) );
              return ( neg < 0 ? -fl : fl );

            default:     /* ========== */
              state = ERROR;
              break;
          } /* end main switch */
      } /* end main loop */

    /* invalid format of nstr */
    if( endptr != (char **)0 )
      *endptr= nstr;
    return (double)0;
}

/*
 *
 */

/*
double
rint( double x )
{
    long k;

    k = (long)x;

    return (double)k;
}
*/

/*
 * it is real patch, not port :-(
 */

static char ecvt_buf[512];

char *
ecvt( double value, int ndigit, int * decpt, int * sign )
{
    long  lval;

    if( value < 0.0 )
      {
        *sign = -1;
        value = -value;
      }
    else
      *sign = 0;

    *decpt = 0;

    /* force (1, 0.1] range */
    /* log10 using will be better ! */
    if( value >= 1.0 )
      {
        while( value >= 1.0 )
          {
            value /= 10.0;
            (*decpt)++;
          }
      }
    else
      {
        while( value < 0.1 )
          {
            value *= 10.0;
            (*decpt)--;
          }
      }

    value *= pow( 10.0, (double)ndigit );
    lval = (long)value + 0.5; /* I don't know what mean Fortran rounding */

    sprintf( ecvt_buf, "%ld", lval );

    return ecvt_buf;
}

/*
 * because it is patch only I copeid ecvt
 */
char *
fcvt( double value, int ndigit, int * decpt, int * sign )
{
    long  lval;

    if( value < 0.0 )
      {
        *sign = -1;
        value = -value;
      }
    else
      *sign = 0;

    *decpt = 0;

    /* force (1, 0.1] range */
    /* log10 using will be better ! */
    if( value >= 1.0 )
      {
        while( value >= 1.0 )
          {
            value /= 10.0;
            (*decpt)++;
          }
      }
    else
      {
        while( value < 0.1 )
          {
            value *= 10.0;
            (*decpt)--;
          }
      }

    value *= pow( 10.0, (double)ndigit );
    lval = (long)value + 0.5;

    sprintf( ecvt_buf, "%ld", lval );

    return ecvt_buf;
}

/*
 *
 */
char *
gcvt( double value, int ndigits, char * buf )
{
    sprintf( buf, "%0.*G", ndigits, value );
    return buf;
}
