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

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

int s4next_spool_entry( SORT4 *s4 )
{
  long last_disk_pos, disk_data_left, new_rec, spool_rec ;
  unsigned max_read, len_read ;
  int low, high, pos, rc ;
  char *new_data ;
  S4SPOOL save_spool ;

  s4->spool_pointer->pos += s4->tot_len ;
  if ( s4->spool_pointer->pos >= s4->spool_pointer->len )
  {
    s4->spool_pointer->pos = 0 ;
    if ( s4->spool_pointer->disk >= 0L )
    {
      last_disk_pos  = (s4->spool_pointer->spool_i+1) * s4->spool_disk_len  ;
      disk_data_left = last_disk_pos - s4->spool_pointer->disk ;
      max_read = s4->spool_mem_len ;
      if ( (long) s4->spool_mem_len > disk_data_left )
        max_read = (unsigned) disk_data_left ;
      len_read = file4read( &s4->file, s4->spool_pointer->disk,
                           s4->spool_pointer->ptr, max_read) ;

      if ( s4->code_base->error_code < 0 )
      {
        sort4free( s4 ) ;
        return -1 ;
      }

      s4->spool_pointer->len = len_read ;
      s4->spool_pointer->disk += len_read ;
      if ( len_read != max_read || len_read == 0 )
      {
        if ( len_read % s4->tot_len )
        {
          sort4free( s4 ) ;
          return e4( s4->code_base, e4read, s4->file.name ) ;
        }
        s4->spool_pointer->disk = -1 ;
        if ( len_read == 0 )
        {
          s4delete_spool_entry( s4 ) ;
          return 0 ;
        }
        else
          s4->spool_pointer->len = len_read ;
      }
      else  /* Check if we are out of disk entries for the spool */
        if ( s4->spool_pointer->disk >= last_disk_pos )
          s4->spool_pointer->disk = -1L ;
    }
    else
    {
      s4delete_spool_entry(s4) ;
      return 0 ;
    }
  }

  /* Position the new entry to the sorted location using a binary search */
  /* New entry is placed before 'result':  int pos >= 1  when complete */
  low = 1 ;
  high = s4->spools_n ;
  new_data = s4->spool_pointer->ptr + s4->spool_pointer->pos ;
  memcpy( (void *)&new_rec, new_data + s4->sort_len, sizeof(new_rec) ) ;

  for(;;)
  {
    pos = ( low + high ) / 2 ;
    if ( pos == low && pos == high )  /* then found */
    {
      memcpy( (void *)&save_spool, (void *)s4->spool_pointer, sizeof(S4SPOOL) ) ;
      memmove( s4->spool_pointer, s4->spool_pointer+1, sizeof(S4SPOOL)*(pos-1) ) ;
      memcpy( (void *)(s4->spool_pointer+pos-1), (void *)&save_spool, sizeof(S4SPOOL) ) ;
      return 0 ;
    }
    rc = (*s4->cmp)(new_data, s4->spool_pointer[pos].ptr + s4->spool_pointer[pos].pos, s4->sort_len) ;
    if ( rc == 0 )
    {
      memcpy( (void *)&spool_rec, s4->spool_pointer[pos].ptr + s4->spool_pointer[pos].pos + s4->sort_len, sizeof(spool_rec) ) ;
      if ( new_rec > spool_rec )
        rc = 1 ;
    }

    if ( rc > 0 )
      low = pos+1 ;
    else
      high = pos ;
#ifdef S4DEBUG
    if ( high < low )
      e4severe( e4result, E4_S4NEXT_SP_ENT ) ;
#endif
  }
}