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

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

unsigned S4FUNCTION file4seq_read( FILE4SEQ_READ *seq_read, void *ptr, unsigned len )
{
  CODE4 *c4 ;
  unsigned urc, buffer_i, copy_bytes ;
  long lrc ;

#ifdef S4DEBUG
  if ( seq_read == 0 || ( ptr == 0 && len ) )
    e4severe( e4parm, E4_F4SEQ_READ ) ;
  if ( seq_read->file == 0 )
    e4severe( e4info, E4_F4SEQ_READ ) ;
#endif

  c4 = seq_read->file->code_base ;
  if ( c4->error_code < 0 )
    return 0 ;

  if ( seq_read->buffer == 0 )
  {
    urc = file4read( seq_read->file, seq_read->pos, ptr, len ) ;
    seq_read->pos += urc ;
    return urc ;
  }

  if ( seq_read->avail == 0 )
  {
#ifdef S4DEBUG
    if ( seq_read->pos < 0 )
      e4severe( e4result, E4_F4SEQ_READ ) ;
#endif

#ifdef S4WINDOWS
    lrc = _llseek( seq_read->file->hand, seq_read->pos, 0 ) ;
#else
#ifdef S4MACINTOSH
    lrc = MAClseek( seq_read->file->hand, seq_read->pos, 0, 0 ) ;
#else
#ifdef S4WIN32
    if ( SetFilePointer( (HANDLE)seq_read->file->hand, seq_read->pos, NULL, FILE_BEGIN ) != (DWORD)-1 )
      lrc = seq_read->pos ;
#else
#ifdef S4LSEEK
    lrc = f4lseek( seq_read->file, seq_read->pos, 0, 0 ) ;
#else
    lrc = lseek( seq_read->file->hand, seq_read->pos, 0 ) ;
#endif
#endif
#endif
#endif
    if ( lrc != seq_read->pos )
    {
      file4read_error( seq_read->file ) ;
      return 0 ;
    }

#ifdef S4WINDOWS
    seq_read->avail = seq_read->working = (unsigned)_lread( seq_read->file->hand, seq_read->buffer, seq_read->next_read_len ) ;
#else
#ifdef S4MACINTOSH
    lrc = (long) seq_read->next_read_len ;
    urc = FSRead( seq_read->file->hand, &lrc, seq_read->buffer ) ;
    if ( urc == 0 ) urc = seq_read->next_read_len ;
    seq_read->avail = seq_read->working = urc ;
#else
#ifdef S4WIN32
    ReadFile( (HANDLE)seq_read->file->hand, seq_read->buffer, seq_read->next_read_len, (unsigned long *)&seq_read->working, NULL ) ;
    seq_read->avail = seq_read->working  ;
#else
    seq_read->avail = seq_read->working = (unsigned)read( seq_read->file->hand, seq_read->buffer, seq_read->next_read_len ) ;
#endif
#endif
#endif

    if ( seq_read->working == UINT_MAX )
    {
      file4read_error( seq_read->file ) ;
      return 0 ;
    }

#ifdef S4DEBUG
    /* Make sure reading is aligned correctly for maximum speed */
    if ( ( seq_read->pos + seq_read->next_read_len ) % 0x400 && seq_read->avail )
      e4severe( e4result, E4_F4SEQ_READ ) ;
#endif
    seq_read->pos += seq_read->working ;
    seq_read->next_read_len = seq_read->total ;
  }

  if ( seq_read->avail >= len )
  {

    buffer_i = seq_read->working - seq_read->avail ;
    memcpy( ptr, seq_read->buffer + buffer_i, len ) ;
    seq_read->avail -= len ;
    return len ;
  }
  else
  {
    if ( seq_read->avail == 0 )
      return 0 ;

    buffer_i = seq_read->working - seq_read->avail ;
    memcpy( ptr, seq_read->buffer + buffer_i, seq_read->avail ) ;

    copy_bytes = seq_read->avail ;
    seq_read->avail = 0 ;

    urc = file4seq_read( seq_read, (char *)ptr + copy_bytes, len - copy_bytes ) ;
    if ( c4->error_code < 0 )
      return 0 ;

    return urc + copy_bytes ;
  }
}

int S4FUNCTION file4seq_read_all( FILE4SEQ_READ *seq_read, void *ptr, unsigned len )
{
  unsigned len_read ;

#ifdef S4DEBUG
  if ( seq_read == 0 || ( ptr == 0 && len ) )
    e4severe( e4parm, E4_F4SEQ_READ_ALL ) ;
  if ( seq_read->file == 0 )
    e4severe( e4info, E4_F4SEQ_READ_ALL ) ;
#endif

  len_read = file4seq_read( seq_read, ptr, len ) ;
  if ( seq_read->file->code_base->error_code < 0 )
    return -1 ;

  if ( len_read != len )
    return file4read_error( seq_read->file ) ;
  return 0 ;
}

void S4FUNCTION file4seq_read_init( FILE4SEQ_READ *seq_read, FILE4 *file, long start_pos, void *buffer, unsigned buffer_len )
{
#ifdef S4DEBUG
  if ( start_pos < 0 || seq_read == 0 || file == 0 )
    e4severe( e4parm, E4_F4SEQ_READ_IN ) ;
#endif

  memset( (void *)seq_read, 0, sizeof( FILE4SEQ_READ ) ) ;

#ifndef S4OPTIMIZE_OFF
  file4low_flush( file, 1 ) ;
#endif
  if ( buffer_len > 0 )
  {
    seq_read->total = buffer_len & 0xFC00 ;  /* Make it a multiple of 1K */
    if ( seq_read->total > (unsigned)( start_pos % 0x400 ) )
      seq_read->next_read_len = seq_read->total - (unsigned)( start_pos % 0x400 ) ;
    seq_read->buffer = (char *)buffer ;
  }
  seq_read->pos = start_pos ;
  seq_read->file = file ;
}

int S4FUNCTION file4seq_write( FILE4SEQ_WRITE *seq_write, void *buffer, unsigned ptr_len )
{
  int rc ;
  unsigned first_len ;

#ifdef S4DEBUG
  if ( seq_write == 0 || ( ptr_len && buffer == 0 ) )
    e4severe( e4parm, E4_F4SEQ_WRITE ) ;
#endif

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

  if ( seq_write->buffer == 0 )
  {
    rc = file4write( seq_write->file, seq_write->pos, buffer, ptr_len ) ;
#ifndef S4OPTIMIZE_OFF
#ifdef S4DEBUG_DEV
    if ( seq_write->file->has_dup == 1 )
      if ( file4write_part( buffer, seq_write->file, seq_write->pos, ptr_len ) != 0 )
        e4severe( e4opt, "file4write() - file corruption" ) ;
#endif
#endif
    seq_write->pos += ptr_len ;
    return rc ;
  }

  if ( seq_write->avail == 0 )
    if ( file4seq_write_flush( seq_write ) < 0 )
      return -1 ;

  if ( seq_write->avail >= ptr_len )
  {
#ifdef S4DEBUG
    if ( seq_write->working < seq_write->avail || ( seq_write->working - seq_write->avail + ptr_len ) > seq_write->total )
      e4severe( e4result, E4_F4SEQ_WRITE ) ;
#endif
    memcpy( seq_write->buffer + ( seq_write->working - seq_write->avail ), buffer, ptr_len ) ;
    seq_write->avail -= ptr_len ;
    return 0 ;
  }
  else
  {
    first_len = seq_write->avail ;

#ifdef S4DEBUG
    if ( seq_write->working < seq_write->avail || seq_write->working > seq_write->total )
      e4severe( e4result, E4_F4SEQ_WRITE ) ;
#endif
    memcpy( seq_write->buffer + ( seq_write->working - seq_write->avail ), buffer, seq_write->avail ) ;

    seq_write->avail = 0 ;

    return file4seq_write( seq_write, (char *)buffer + first_len, ptr_len - first_len ) ;
  }
}

int S4FUNCTION file4seq_write_flush( FILE4SEQ_WRITE *seq_write )
{
  unsigned to_write ;
#ifdef S4MACINTOSH
  long long_to_write ;
  short vRefNum ;
#endif

#ifdef S4DEBUG
  if ( seq_write == 0 )
    e4severe( e4parm, E4_F4SEQ_WRT_FLSH ) ;
#endif

  if ( seq_write->file->code_base->error_code < 0 )
    return -1 ;
  if ( seq_write->buffer == 0 )
    return 0 ;

#ifdef S4DEBUG
  if( seq_write->pos < 0 )
    e4severe( e4result, (char *) 0 ) ;
#endif

  to_write = seq_write->working - seq_write->avail ;

#ifndef S4OPTIMIZE_OFF
#ifdef S4DEBUG_DEV
  if ( seq_write->file->has_dup == 1 )
    if ( file4write_part( seq_write->buffer, seq_write->file, seq_write->pos, to_write ) != 0 )
      e4severe( e4opt, "file4write() - file corruption" ) ;
#endif

  if ( seq_write->file->do_buffer == 1 && seq_write->file->buffer_writes == 1 )
  {
    if ( file4write( seq_write->file, seq_write->pos, seq_write->buffer, to_write ) != 0 )
      return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
  }
  else
#endif
#ifdef S4WINDOWS
  {
    if ( _llseek( seq_write->file->hand, seq_write->pos, 0 ) != seq_write->pos )
      return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
    if ( (unsigned)_lwrite( seq_write->file->hand, seq_write->buffer, to_write) != to_write)
      return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
  }
#else
{
#ifdef S4MACINTOSH
  if ( MAClseek( seq_write->file->hand, seq_write->pos, 0, 1 ) != seq_write->pos )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
  long_to_write = (long ) to_write ;
  if ( FSWrite( seq_write->file->hand, &long_to_write, seq_write->buffer ) < 0 )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;

  if (GetVRefNum( seq_write->file->hand, &vRefNum ) != 0 )
    return e4( seq_write->file->code_base, e4write, 0 ) ;

  if (FlushVol( 0, vRefNum ) != 0 )
    return e4( seq_write->file->code_base, e4write, 0 ) ;
#else
#ifdef S4WIN32
  long urc ;
  if ( SetFilePointer( (HANDLE)seq_write->file->hand, seq_write->pos, NULL, FILE_BEGIN ) == (DWORD)-1 )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
  WriteFile( (HANDLE)seq_write->file->hand, seq_write->buffer, to_write, (unsigned long *)&urc, NULL ) ;
  if ( urc != to_write )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
#else
#ifdef S4LSEEK
  if ( f4lseek( seq_write->file, seq_write->pos, 0, 1 ) != seq_write->pos )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
#else
  if ( lseek( seq_write->file->hand, seq_write->pos, 0 ) != seq_write->pos )
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
#endif
  if ( (unsigned)write( seq_write->file->hand, seq_write->buffer, to_write) != to_write)
    return e4( seq_write->file->code_base, e4write, seq_write->file->name ) ;
#endif
#endif
}
#endif

/* file4flush( seq_write->file )   VAX fix (flush req'd on write) */
seq_write->pos += to_write ;

seq_write->avail = seq_write->working = seq_write->total ;
return 0 ;
}

/* note that the sequential functions are not generally useful when hashing is in place since hashing effectively performs bufferring */
void  S4FUNCTION file4seq_write_init( FILE4SEQ_WRITE *seq_write, FILE4 *file, long start_offset, void *ptr, unsigned ptr_len )
{
#ifdef S4DEBUG
  if ( seq_write == 0 || file == 0 )
    e4severe( e4parm, E4_F4SEQ_WRT_INIT ) ;
#endif

  memset( (void *)seq_write, 0, sizeof( FILE4SEQ_WRITE ) ) ;

#ifndef S4OPTIMIZE_OFF
  file4low_flush( file, 1 ) ;
#endif

  seq_write->file = file ;

  if ( ptr_len > 0 )
  {
    seq_write->total = ptr_len & 0xFC00 ;  /* Make it a multiple of 1K */
    seq_write->buffer = (char *)ptr ;
    if ( seq_write->total > (unsigned)( start_offset % 0x400 ) )
      seq_write->avail = seq_write->working = seq_write->total - (unsigned)( start_offset % 0x400 ) ;
  }
  seq_write->pos = start_offset ;
}

int  S4FUNCTION file4seq_write_repeat( FILE4SEQ_WRITE *seq_write, long num_repeat, char ch )
{
  char buf[512] ;

#ifdef S4DEBUG
  if ( seq_write == 0 || num_repeat < 0 )
    e4severe( e4parm, E4_F4SEQ_WRT_REP ) ;
#endif

  memset( (void *)buf, ch, sizeof(buf) ) ;

  while ( num_repeat > sizeof(buf) )
  {
    if ( file4seq_write( seq_write, buf, (unsigned)sizeof( buf ) ) < 0 )
      return -1 ;
    num_repeat -= sizeof(buf) ;
  }

  return file4seq_write( seq_write, buf, (unsigned)num_repeat ) ;
}
