/* e4expr.c   (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */

#include "d4all.h"
#ifdef __TURBOC__
#pragma hdrstop
#endif

char **expr4 ;
char  *expr4constants ;
E4INFO *expr4info_ptr ;
EXPR4 *expr4ptr ;

int S4FUNCTION expr4start( CODE4 *c4 )
{
#ifdef S4OS2SEM
#ifdef S4OS2
  APIRET rc ;

  rc = DosRequestMutexSem( c4->hmtx_expr, -1 ) ;
  if ( rc != 0 )
    return e4( c4, e4info, "OS/2 Semaphore Failure" ) ;
#endif
#endif
  expr4buf = c4->expr_work_buf ;  /* initialize the working buffer pointer */
  return 0 ;
}

static void expr4stop( CODE4 *c4 )
{
  /* clear the globals to ensure they are not used without initialization */
  expr4buf = 0 ;
  expr4 = 0 ;
  expr4ptr = 0 ;
  expr4info_ptr = 0 ;
  expr4constants = 0 ;
#ifdef S4OS2SEM
#ifdef S4OS2
  DosReleaseMutexSem( c4->hmtx_expr ) ;
#endif
#endif
}

int S4FUNCTION expr4compare_flip( int function_i )
{
  if ( function_i == E4GREATER )
    return  E4LESS_EQ ;
  if ( function_i == E4LESS )
    return  E4GREATER_EQ ;
  if ( function_i == E4GREATER_EQ )
    return  E4LESS ;
  if ( function_i == E4LESS_EQ )
    return E4GREATER ;
  return function_i ;   /* not equal, or equal do not change */
  /*   return -1 ; */
}

#ifdef S4FOX
void t4dbl_to_fox( char *result, double doub )
{
  char i ;
  int is_positive  ;
  is_positive = ( doub >= 0 ) ;

#ifdef S4BYTEORDER_3210
  for ( i = 0 ; i < 8 ; i++ )
    result[i] = *( (char *)&doub + 7 - i ) ;
  memcpy( (void *)&doub, result, sizeof(double) ) ;
#else
#ifdef S4BYTEORDER_2301
  memcpy( (char *)result, ((char *)&doub) + 4, 4 ) ;
  memcpy( ((char *)result) + 4, ((char *)&doub), 4 ) ;
  memcpy( (void *)&doub, result, sizeof(double) ) ;
#endif
#endif

  if ( is_positive )
  {
    for ( i = 0 ; i < 8 ; i++ )
      result[i] = *( (char *)&doub + 7 - i ) ;
    result[0] += (unsigned)0x80 ;
  }
  else /* negative */
    for ( i = 0 ; i < 8 ; i++ )
      result[i] = (char) (~(*( (unsigned char *)&doub + 7 - i ))) ;
}
#endif

int S4FUNCTION expr4double2( EXPR4 S4PTR *e4expr, double *result )
{
  *result = expr4double( e4expr ) ;
  if ( *result < 0.0 )
    return -1;
  return 0;
}

double S4FUNCTION expr4double( EXPR4 *e4expr )
{
  char *ptr ;
  int len ;
#ifdef S4UNIX
  double doub ;
#endif

  len = expr4vary( e4expr, &ptr ) ;
  if ( len >= 0 )
    switch( expr4type( e4expr ) )
    {
    case r4num_doub:
    case r4date_doub:
#ifdef S4UNIX
      memcpy( (void *)&doub, ptr, sizeof(double) ) ;
      return  doub ;
#else
      return  *( (double *)ptr ) ;
#endif
    case r4num:
    case r4str:
      return c4atod( ptr, len ) ;
    case r4date:
      return (double)date4long( ptr ) ;
    default:
#ifdef S4DEBUG
      e4severe( e4info, E4_EXPR4DOUBLE ) ;
#endif
      break ;
    }

  return 0.0 ;
}

int S4FUNCTION expr4execute( EXPR4 *expr, int pos, void **result_ptr_ptr )
{
  E4INFO *last_info ;
  char *pointers[E4MAX_STACK_ENTRIES] ;
  int info_pos  ;

#ifdef S4DEBUG
  if ( expr == 0 || pos < 0 || result_ptr_ptr == 0 )
    e4severe( e4parm, E4_EXPR4EXEC ) ;
#endif

  if ( expr->code_base->error_code < 0 )
    return -1 ;

  if ( expr4start( expr->code_base ) != 0 )
    return -1 ;

  expr4 = pointers ;
  expr4constants = expr->constants ;
  expr4ptr = expr ;
  last_info = expr->info + pos ;
  info_pos = pos - last_info->num_entries + 1 ;

  for( ; info_pos <= pos ; info_pos++ )
  {
    expr4info_ptr = expr->info+ info_pos ;
    (*expr4info_ptr->function)() ;
  }

  *result_ptr_ptr = pointers[0] ;
#ifdef S4DEBUG
  if ( pointers[0] != expr4[-1] )
    return e4( expr->code_base, e4result, 0 ) ;
#endif

  expr4stop( expr->code_base ) ;

  return expr->code_base->error_code ;
}

void S4FUNCTION expr4free( EXPR4 *e4expr )
{
  if ( e4expr != 0 )
    u4free( e4expr ) ;
}

int S4FUNCTION expr4key( EXPR4 *e4expr, char **ptr_ptr )
{
  int result_len ;

#ifdef S4DEBUG
  if ( e4expr == 0 || ptr_ptr == 0 )
    e4severe( e4parm, E4_EXPR4KEY ) ;
#endif

  if ( e4expr->code_base->error_code < 0 )
    return -1 ;

  result_len = expr4vary( e4expr, ptr_ptr ) ;
  if ( result_len < 0 )
    return -1 ;

  return expr4key_convert( e4expr, ptr_ptr, result_len, e4expr->type ) ;
}

int S4FUNCTION expr4key_convert( EXPR4 *e4expr, char **ptr_ptr, int result_len, int expr_type )
{
  int i ;
  double  d ;
  CODE4 *cb ;
#ifdef S4MDX
  C4BCD  bcd ;
#endif
#ifdef S4CLIPPER
  long l ;
#endif
#ifndef N4OTHER
  double *d_ptr ;
#endif

  cb = e4expr->code_base ;

  switch( expr_type )
  {
#ifdef S4FOX
  case r4num:
    d = c4atod( *ptr_ptr, result_len ) ;
    t4dbl_to_fox( cb->stored_key, d ) ;
    result_len = (int)sizeof( double ) ;
    break ;
  case r4date:
    d = (double) date4long( *ptr_ptr ) ;
    t4dbl_to_fox( cb->stored_key, d ) ;
    result_len = (int)sizeof( double ) ;
    break ;
  case r4num_doub:
  case r4date_doub:
    d_ptr = (double *) (*ptr_ptr) ;
    t4dbl_to_fox( cb->stored_key, *d_ptr ) ;
    result_len = (int)sizeof( double ) ;
    break ;
  case r4log:
    switch( *(int *)*ptr_ptr )
    {
    case 1:
      cb->stored_key[0] = 'T' ;
      break ;
    case 0:
      cb->stored_key[0] = 'F' ;
      break ;
    default:
#ifdef S4DEBUG
      e4severe( e4info, E4_INFO_FAI ) ;
#endif
      cb->stored_key[0] = 'F' ;
    }
    result_len = 1 ;
    break ;
#endif  /*  ifdef S4FOX      */
#ifdef S4CLIPPER
  case r4num:
    result_len = e4expr->key_len ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, *ptr_ptr, result_len ) ;
    c4clip( cb->stored_key, result_len ) ;
    break ;
  case r4num_doub:
    result_len = e4expr->key_len ;
    c4dtoa_clipper( *((double *)*ptr_ptr), cb->stored_key, result_len, cb->decimals ) ;
    break ;
  case r4date_doub:
    d = *( ( double  *)*ptr_ptr ) ;
    l = (long)d ;
    date4assign( cb->stored_key, l ) ;
    break ;
#endif  /*  ifdef S4CLIPPER  */
#ifdef S4NDX
  case r4num:
    d = c4atod( *ptr_ptr, result_len ) ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, &d, sizeof( d ) ) ;
    result_len = (int)sizeof( double ) ;
    break ;
  case r4date:
    date4format_mdx2( *ptr_ptr, &d ) ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, &d, sizeof(double) ) ;
    result_len = (int)sizeof( double ) ;
    break ;
#endif  /*  ifdef S4NDX  */
#ifdef S4MDX
  case r4num:
    c4bcd_from_a( (char *) &bcd, (char *) *ptr_ptr, result_len ) ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, (void *)&bcd, sizeof(C4BCD) ) ;
    result_len = (int)sizeof( C4BCD ) ;
    break ;
  case r4num_doub:
    d_ptr = (double *) (*ptr_ptr) ;
    c4bcd_from_d( (char *) &bcd, *d_ptr ) ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, (void *)&bcd, sizeof(C4BCD) ) ;
    result_len = (int)sizeof( C4BCD ) ;
    break ;
  case r4date:
    date4format_mdx2( *ptr_ptr, &d ) ;
    if ( d == 0 ) d = 1.0E300 ;
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, (void *)&d, sizeof(double) ) ;
    result_len = (int)sizeof( double ) ;
    break ;
  case r4date_doub:
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, *ptr_ptr, sizeof(double) ) ;
    d_ptr = (double *)( cb->stored_key ) ;
    if ( *d_ptr == 0 ) *d_ptr = 1.0E300 ;
    result_len = (int)sizeof( double ) ;
    break ;
#endif  /* S4MDX */
  case r4str:
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, *ptr_ptr, result_len ) ;
    /* if trim, then replace nulls with blanks */
    if ( e4expr->has_trim )
      for( i = result_len - 1 ; (i >= 0) && (cb->stored_key[i] == 0) ; i-- )
        cb->stored_key[i] = ' ' ;
    break ;
  default:
#ifdef S4DEBUG
    if ( cb->stored_key == 0 )
      e4severe( e4info, E4_PARM_NSD ) ;
#endif
    memcpy( cb->stored_key, *ptr_ptr, result_len ) ;
    break ;
  }

#ifdef S4DEBUG
  if ( (unsigned)result_len >= cb->stored_key_len )
    e4severe( e4info, E4_INFO_SKL ) ;
#endif

  cb->stored_key[result_len] = 0 ;    /* null end it */
  *ptr_ptr = cb->stored_key ;
  return result_len ;
}

int S4FUNCTION expr4key_len( EXPR4 *e4expr )
{
  switch( e4expr->type )
  {
#ifdef S4FOX
  case r4num:
    return (int)sizeof( double ) ;
  case r4date:
    return (int)sizeof( double ) ;
  case r4num_doub:
    return (int)sizeof( double ) ;
  case r4log:
    return (int)sizeof( char ) ;
#endif  /*  ifdef S4FOX      */
#ifdef S4CLIPPER
  case r4num:  /* numeric field return, this fixex length problem */
    return f4len( e4expr->info[0].field_ptr ) ;
  case r4num_doub:
    return e4expr->data->code_base->numeric_str_len ;
#endif  /*  ifdef S4CLIPPER  */
#ifdef S4NDX
  case r4num:
    return (int)sizeof( double ) ;
  case r4date:
    return (int)sizeof( double ) ;
#endif  /*  ifdef S4NDX  */
#ifdef S4MDX
  case r4num:
    return (int)sizeof( C4BCD ) ;
  case r4num_doub:
    return (int)sizeof( C4BCD ) ;
  case r4date:
    return (int)sizeof( double ) ;
  case r4date_doub:
    return (int)sizeof( double ) ;
#endif  /* S4MDX */
  default:
    return expr4len( e4expr ) ;
  }
}

int S4FUNCTION expr4len( EXPR4 *e4expr )
{
  return e4expr->len ;
}

static char e4null_char = '\0' ;

char *S4FUNCTION expr4source( EXPR4 *e4expr )
{
  if ( e4expr == 0 )
    return &e4null_char ;
  return e4expr->source ;
}

int S4FUNCTION expr4true( EXPR4 *e4expr )
{
  int result_len ;
  int *i_ptr ;

  result_len = expr4vary( e4expr, (char **)&i_ptr ) ;
  if ( result_len < 0 )
    return -1 ;

  if ( expr4type( e4expr ) != r4log )
    return e4describe( e4expr->data->code_base, e4result, E4_EXPR4TRUE, E4_RESULT_EXP, (char *)0 ) ;

  return *i_ptr ;
}

int S4FUNCTION expr4type( EXPR4 *e4expr )
{
  return e4expr->type ;
}

int S4FUNCTION expr4vary( EXPR4 *expr, char **result_ptr_ptr )
{
  char *pointers[E4MAX_STACK_ENTRIES] ;
  int info_pos ;

#ifdef S4DEBUG
  if ( expr == 0 || result_ptr_ptr == 0 )
    e4severe( e4parm, E4_EXPR4VARY ) ;
#endif

  if ( expr->code_base->error_code < 0 )
    return -1 ;

  if ( expr4start( expr->code_base ) != 0 )
    return -1 ;

  expr4 = pointers ;
  expr4constants = expr->constants ;
  expr4ptr = expr ;

  for( info_pos = 0; info_pos < expr->info_n; info_pos++ )
  {
    expr4info_ptr = expr->info+ info_pos ;
    (*expr4info_ptr->function)() ;
  }

  *result_ptr_ptr = pointers[0] ;
#ifdef S4DEBUG
  if ( pointers[0] != expr4[-1] )
    return e4( expr->code_base, e4result, 0 ) ;
#endif

  expr4stop( expr->code_base ) ;

  return expr->len ;
}
