/*  c4bcd.c   (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */
/*                binary digit is:   xxxx xxxx  xxxx xx01                */
/*                                   sig dig    |||| ||||                */
/*                                              |||| ||always 01         */
/*                                              |length                  */
/*                                              sign                     */

#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif  /* __TUROBC__ */
#endif  /* S4UNIX */

#ifdef S4MDX

/* MDX */
int S4CALL c4bcd_cmp( S4CMP_PARM a_ptr, S4CMP_PARM b_ptr, size_t dummy_len )
{
  int a_sign, b_sign, a_len, b_len, a_sig_dig, b_sig_dig, compare_len, rc ;

  if ( ((C4BCD *)a_ptr)->digit_info  & 0x80 )  /* get digit sign */
    a_sign = -1 ;
  else
    a_sign =  1 ;

  if ( ((C4BCD *)b_ptr)->digit_info & 0x80 )
    b_sign = -1 ;
  else
    b_sign =  1 ;

  if ( a_sign != b_sign )
    return a_sign ;

  a_len = ( (((C4BCD *)a_ptr)->digit_info >> 2) & 0x1F ) ; /* get digit length */
  b_len = ( (((C4BCD *)b_ptr)->digit_info >> 2) & 0x1F ) ;

  if ( a_len == 0 )
    a_sig_dig = 0 ;
  else
    a_sig_dig = ((C4BCD *)a_ptr)->sig_dig ;  /* get digit significant digit */

  if ( b_len == 0 )
    b_sig_dig = 0 ;
  else
    b_sig_dig = ((C4BCD *)b_ptr)->sig_dig ;

  if ( a_sig_dig != b_sig_dig )
  {
    if ( a_sig_dig < b_sig_dig )
      return -a_sign ;
    else
      return a_sign ;
  }

  compare_len = (a_len < b_len) ? b_len : a_len ;  /* Use Max */

  compare_len = (compare_len+1)/2 ;

  rc = c4memcmp( ((C4BCD *)a_ptr)->bcd, ((C4BCD *)b_ptr)->bcd, compare_len ) ;
  if ( a_sign < 0 )  return -rc ;

  return rc ;
}

/* MDX */
void c4bcd_from_a( char *result, char *input_ptr, int input_ptr_len )
{
  char *ptr ;
  unsigned len ;
  int n, last_pos, pos, is_before_dec, zero_count ;

  memset( result, 0, sizeof(C4BCD) ) ;

  last_pos = input_ptr_len - 1 ;
  pos = 0 ;
  for ( ; pos <= last_pos; pos++ )
    if ( input_ptr[pos] != ' ' )  break ;

  if ( pos <= last_pos )
  {
    if ( input_ptr[pos] == '-' )
    {
      ((C4BCD *)result)->digit_info=(unsigned char)((int)((C4BCD *)result)->digit_info | 0x80) ;
      pos++ ;
    }
    else
    {
      if ( input_ptr[pos] == '+' )  pos++ ;
    }
  }

  for ( ; pos <= last_pos; pos++ )
    if ( input_ptr[pos] != ' ' && input_ptr[pos] != '0' )  break ;

  is_before_dec = 1 ;

  ((C4BCD *)result)->sig_dig = 0x34 ;
  if ( pos <= last_pos )
    if ( input_ptr[pos] == '.' )
    {
      is_before_dec = 0 ;
      pos++ ;
      for ( ; pos <= last_pos; pos++ )
      {
        if ( input_ptr[pos] != '0' )  break ;
        ((C4BCD *)result)->sig_dig-- ;
      }
    }

  ptr = (char *) ((C4BCD *)result)->bcd ; ;
  zero_count = 0 ;

  for ( n=0; pos <= last_pos; pos++ )
  {
    if ( input_ptr[pos] >= '0' && input_ptr[pos] <= '9' )
    {
      if ( input_ptr[pos] == '0' )
        zero_count++ ;
      else
        zero_count = 0 ;
      if ( n >= 20 )  break ;
      if ( n & 1 )
        *ptr++ |= input_ptr[pos] - '0' ;
      else
        *ptr += (unsigned char)( (unsigned char)((unsigned char)input_ptr[pos] - (unsigned char)'0') << 4 ) ;
    }
    else
    {
      if ( input_ptr[pos] != '.'  ||  ! is_before_dec )
        break ;

      is_before_dec = 0 ;
      continue ;
    }
    if ( is_before_dec )
      ((C4BCD *)result)->sig_dig++ ;

    n++ ;
  }
  /* 'always one' bit filled  */
  ((C4BCD *)result)->digit_info = (unsigned char)( ((C4BCD *)result)->digit_info | 0x1 ) ;

#ifdef S4DEBUG
  if ( n - zero_count < 0 )
    e4severe( e4info, E4_C4BCD_FROM_A ) ;
#endif

  len = n - zero_count ;
  if (len > 31)
    len = 31 ;

  ((C4BCD *)result)->digit_info = (unsigned char)( ((C4BCD *)result)->digit_info | (len << 2) ) ;

  if ( len == 0 )
    ((C4BCD *)result)->digit_info = (unsigned char)( ((C4BCD *)result)->digit_info & 0x7F ) ;
}

/* MDX */
void  c4bcd_from_d( char *result, double doub )
{
  char  temp_str[258], *ptr ;
  int   sign, dec, len, pos ;

#ifdef S4NO_ECVT
  ptr = f4ecvt( doub, E4ACCURACY_DIGITS, &dec, &sign ) ;
#else
  ptr = ecvt( doub, E4ACCURACY_DIGITS, &dec, &sign ) ;
#endif

  if ( sign )
  {
    pos = 1 ;
    temp_str[0] = '-' ;
  }
  else
    pos = 0 ;

  if ( dec < 0 )
  {
    dec = -dec ;
    len = dec+1+pos ;
    memcpy( temp_str+len, ptr, E4ACCURACY_DIGITS ) ;
    memset( temp_str+pos, '0', len-pos ) ;
    temp_str[pos] = '.' ;

    c4bcd_from_a( result, temp_str, E4ACCURACY_DIGITS + len ) ;
  }
  else
  {
    memcpy( temp_str+pos, ptr, dec ) ;
    pos += dec ;
    if ( dec < E4ACCURACY_DIGITS )
    {
      temp_str[pos++] = '.' ;

      len = E4ACCURACY_DIGITS - dec ;
      memcpy( temp_str+pos, ptr+dec, len ) ;
      pos += len ;
    }
    c4bcd_from_a( result, temp_str, pos ) ;
  }
}

#endif  /* S4MDX */