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

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

#ifndef S4INDEX_OFF

/* function to ensure the integrity of the seeks return value */
/* in single user mode, exclusive, or if file is locked, the data is assumed up to date, and not checked */
static int d4seek_check( DATA4 *data, TAG4 *tag, int rc, char *buf, int len )
{
   int skipped, rc2 ;
   char *dbf_key ;

   #ifndef S4SINGLE
      if ( rc == r4locked )
         return r4locked ;
   #endif

   if ( t4eof( tag ) )
      return d4go_eof( data ) ;

   if ( len > tag->header.key_len )
      len = tag->header.key_len ;

   #ifndef S4SINGLE
      if ( d4lock_test_file( data ) )
      {
   #endif
      rc2 = d4go( data, t4recno( tag ) ) ;
      if ( rc2 )
         return rc2 ;
      return rc ;
   #ifndef S4SINGLE
      }
      skipped = 0 ;
      for( ;; )
      {
         rc2 = d4go( data, t4recno( tag ) ) ;
         if ( rc2 )
            return rc2 ;

         if ( t4expr_key( tag, &dbf_key ) < 0 )
            return -1 ;
         #ifdef S4FOX
            if ( !u4memcmp( t4key( tag ), dbf_key, len ) )  /* matched */
         #else
            if ( !(*tag->cmp)( t4key( tag ), dbf_key, len ) )  /* matched */
         #endif
         {
            if ( skipped )
            {
               #ifdef S4FOX
                  rc2 = u4memcmp( dbf_key, buf, len ) ;
               #else
                  rc2 = (*tag->cmp)( dbf_key, buf, len ) ;
               #endif
               if ( rc2 == 0 )   /* worked */
               return rc2 ;
               if ( rc2 > 0 )
                  return r4after ;
               /* other wise, if < 0, can't return r4after, so go down and skip next */
            }
            else
               return rc ;
         }

         /* try next record */
         if ( t4skip( tag, 1L ) == 0 )  /* eof */
            return d4go_eof( data ) ;
         if ( data->code_base->error_code < 0 )
            return -1 ;
         skipped = 1 ;
      }
   #endif
}
int S4FUNCTION d4seek( DATA4 *data, char *str )
{
   return d4seek_n( data, str, strlen(str) ) ;
}

int S4FUNCTION d4seek_n( DATA4 *data, char *str, int len )
{
   TAG4 *tag ;
   int rc ;
   char buf[I4MAX_KEY_SIZE] ;

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E4_D4SEEK ) )
         return 0 ;
   #endif

   if ( data == 0 || str == 0 )
      #ifdef S4DEBUG
         e4severe( e4parm, E4_D4SEEK ) ;
      #else
         return -1 ;
      #endif

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

   tag = d4tag_default( data ) ;
   if ( tag == 0 )
      return r4no_tag ;

   #ifndef S4OFF_WRITE
      rc = d4update_record( data, 0 ) ; /* was 1 */
      if ( rc )
         return rc ;
   #endif

   #ifdef S4UNIX
      #ifdef S4MDX
         switch ( tag->key_type )
         {
            case r4num:
               c4bcd_from_a( buf, str, len ) ;
               break ;
            case r4date:
               t4str_to_date_mdx( buf, str, len ) ;
               break ;
            case r4str:
               t4no_change_str( buf, str, len ) ;
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4FOX
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
               t4str_to_fox( buf, str, len ) ;
               break ;
            case r4date:
            case r4date_doub:
               t4dtstr_to_fox( buf, str, len ) ;
               break ;
            case r4str:
               t4no_change_str( buf, str, len ) ;
               break ;
            case r4log:
               t4str_to_log( buf, str, len ) ;
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4CLIPPER
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
               t4str_to_clip( buf, str, len ) ;
               break ;
            case r4date:
            case r4date_doub:
            case r4str:
               t4no_change_str( buf, str, len ) ;
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4NDX
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
               t4str_to_doub( buf, str, len ) ;
               break ;
            case r4date:
            case r4date_doub:
               t4str_to_date_mdx( buf, str, len ) ;
               break ;
            case r4str:
               t4no_change_str( buf, str, len ) ;
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
   #else
      (*tag->stok)( buf, str, len ) ;
   #endif

   if ( t4type( tag ) != r4str )
      len = tag->header.key_len ;
   else
      if ( len <= 0 )  len = strlen( str ) ;

   rc = t4version_check( tag, 0, 0 ) ;
   if ( rc < 0 )
      return rc ;

   rc = t4seek( tag, buf, len ) ;

   return d4seek_check( data, tag, rc, buf, len ) ;  /* return a valid value */
}

int S4FUNCTION d4seek_double( DATA4 *data, double dkey )
{
   TAG4 *tag ;
   int    rc ;
   char buf[I4MAX_KEY_SIZE] ;
   #ifdef S4CLIPPER
      int len ;
   #endif

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E4_D4SEEK_DBL ) )
         return 0 ;
   #endif

   if ( data == 0 )
      #ifdef S4DEBUG
         e4severe( e4parm, E4_D4SEEK_DBL ) ;
      #else
         return -1 ;
      #endif

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

   tag = d4tag_default( data ) ;
   if ( tag == 0 )
      return r4no_tag ;

   #ifndef S4OFF_WRITE
      rc = d4update_record( data, 0 ) ; /* was 1 */
      if ( rc )
         return rc ;
   #endif

   #ifdef S4CLIPPER
      if ( tag->dtok == 0 )
      {
         len = tag->header.key_len ;
         c4dtoa45( dkey, buf, len, tag->header.key_dec ) ;
         if ( buf[0] == '*' )  /* unknown overflow result */
            return -1 ;
         c4clip( buf, len ) ;
      }
      else
   #else
      if ( tag->dtok == 0 )
         #ifdef S4DEBUG
            e4severe( e4info, E4_INFO_WT4 ) ;
         #else
            return -1 ;
         #endif
   #endif

   #ifdef S4UNIX
      #ifdef S4MDX
         switch ( tag->key_type )
         {
            case r4num:
               c4bcd_from_d( buf, dkey ) ;
               break ;
            case r4date:
               t4no_change_double( buf, dkey ) ;
               break ;
            case r4str:
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4FOX
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
            case r4date:
            case r4date_doub:
               t4dbl_to_fox( buf, dkey ) ;
               break ;
            case r4str:
            case r4log:
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4CLIPPER
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
            case r4str:
               break ;
            case r4date:
            case r4date_doub:
               t4date_doub_to_str( buf, dkey ) ;
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
      #ifdef S4NDX
         switch ( tag->key_type )
         {
            case r4num:
            case r4num_doub:
            case r4date:
            case r4date_doub:
               t4no_change_double( buf, dkey ) ;
               break ;
            case r4str:
               break ;
            default:
               e4severe( e4info, E4_INFO_INV ) ;
         }
      #endif
   #else
      (*tag->dtok)( buf, dkey ) ;
   #endif

   rc = t4version_check( tag, 0, 0 ) ;
   if ( rc < 0 )
      return rc ;

   rc = t4seek( tag, buf, tag->header.key_len ) ;

   return d4seek_check( data, tag, rc, buf, tag->header.key_len ) ;  /* return a valid value */
}

#endif  /* S4INDEX_OFF */

#ifdef S4VB_DOS

int d4seek_v( DATA4 *data, char *seek )
{
   return d4seek( data, c4str(seek) ) ;
}

#endif