655 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			655 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* f4filese.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */
 | 
						|
 | 
						|
#include "d4all.h"
 | 
						|
#ifndef S4UNIX
 | 
						|
   #ifdef __TURBOC__
 | 
						|
      #pragma hdrstop
 | 
						|
   #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4ADVANCE_READ
 | 
						|
void S4CALL file4seqReadCompletionRoutine( void *advance )
 | 
						|
{
 | 
						|
   FILE4SEQ_READ *seqRead ;
 | 
						|
 | 
						|
   /* the completion data points to the entire FILE4SEQ_READ structure */
 | 
						|
   seqRead = ((FILE4SEQ_READ *)((FILE4ADVANCE_READ *)(advance))->completionData) ;
 | 
						|
 | 
						|
   if ( seqRead->buffer == seqRead->buf1 )  /* then this pre-read is the 2nd buffer */
 | 
						|
   {
 | 
						|
      seqRead->buf2status = ((FILE4ADVANCE_READ *)advance)->status ;
 | 
						|
      seqRead->buf2avail = AR4FULL ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      seqRead->buf1status = ((FILE4ADVANCE_READ *)advance)->status ;
 | 
						|
      seqRead->buf1avail = AR4FULL ;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
unsigned S4FUNCTION file4seqReadAdvance( FILE4SEQ_READ *seqRead, void *ptr, const unsigned len )
 | 
						|
{
 | 
						|
   unsigned int urc ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   /* avail is zero if here, so get the other, pre-read buffer (if/when
 | 
						|
      available).  Then set the next one to read-ahead.  Actually, set the
 | 
						|
      first one to pre-read first (since more optimized).  If neither are
 | 
						|
      set up for advance-reading (i.e., is empty and not pre-read-set), then
 | 
						|
      read the first one, and set the 2nd up for pre-reading */
 | 
						|
 | 
						|
   c4 = seqRead->file->codeBase ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( seqRead->avail != 0 )
 | 
						|
      {
 | 
						|
         error4( c4, e4parm_null, E90701 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( seqRead->doAdvance == 0 )
 | 
						|
      {
 | 
						|
         error4( c4, e4struct, E90701 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( seqRead->buffer == seqRead->buf1 )
 | 
						|
   {
 | 
						|
      while ( seqRead->buf2avail == AR4SET )  /* wait for it to finish read */
 | 
						|
         Sleep( 0 ) ;
 | 
						|
 | 
						|
      seqRead->buffer = seqRead->buf2 ;
 | 
						|
 | 
						|
      if ( seqRead->buf2avail == AR4EMPTY )  /* read current one now, advance-read other (after) */
 | 
						|
      {
 | 
						|
         urc = file4readLow( seqRead->file, seqRead->pos, seqRead->buffer, seqRead->nextReadLen ) ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         #ifdef E4ANALYZE
 | 
						|
            if ( seqRead->buf2avail != AR4FULL )  /* invalid setting */
 | 
						|
            {
 | 
						|
               error4( c4, e4struct, E90701 ) ;
 | 
						|
               return 0 ;
 | 
						|
            }
 | 
						|
         #endif
 | 
						|
         urc = seqRead->buf2status ;
 | 
						|
      }
 | 
						|
 | 
						|
      seqRead->avail = seqRead->working = urc ;
 | 
						|
 | 
						|
      if ( seqRead->working == UINT_MAX )
 | 
						|
      {
 | 
						|
         file4readError( seqRead->file, seqRead->pos, seqRead->nextReadLen, "file4seqRead" ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         /* Make sure reading is aligned correctly for maximum speed */
 | 
						|
         if ( ( seqRead->pos + seqRead->nextReadLen ) % 0x400 && seqRead->avail )
 | 
						|
         {
 | 
						|
            error4( c4, e4result, E90701 ) ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
      seqRead->pos += seqRead->working ;
 | 
						|
      seqRead->nextReadLen = seqRead->total ;
 | 
						|
 | 
						|
      /* now pre-read the first one */
 | 
						|
      if ( urc == seqRead->nextReadLen )  /* ensure that it is available for reading */
 | 
						|
      {
 | 
						|
         seqRead->buf1avail = AR4SET ;
 | 
						|
         file4advanceRead( seqRead->file, seqRead->pos, seqRead->buf1, seqRead->nextReadLen, file4seqReadCompletionRoutine, seqRead ) ;
 | 
						|
      }
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         if ( seqRead->buffer != seqRead->buf2 )
 | 
						|
         {
 | 
						|
            error4( c4, e4struct, E90701 ) ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
      while ( seqRead->buf1avail == AR4SET )  /* wait for it to finish read */
 | 
						|
         Sleep( 0 ) ;
 | 
						|
 | 
						|
      seqRead->buffer = seqRead->buf1 ;
 | 
						|
 | 
						|
      if ( seqRead->buf1avail == AR4EMPTY )  /* read current one now, advance-read other (after) */
 | 
						|
      {
 | 
						|
         urc = file4readLow( seqRead->file, seqRead->pos, seqRead->buffer, seqRead->nextReadLen ) ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         #ifdef E4ANALYZE
 | 
						|
            if ( seqRead->buf1avail != AR4FULL )  /* invalid setting */
 | 
						|
            {
 | 
						|
               error4( c4, e4struct, E90701 ) ;
 | 
						|
               return 0 ;
 | 
						|
            }
 | 
						|
         #endif
 | 
						|
         urc = seqRead->buf1status ;
 | 
						|
      }
 | 
						|
 | 
						|
      seqRead->avail = seqRead->working = urc ;
 | 
						|
 | 
						|
      if ( seqRead->working == UINT_MAX )
 | 
						|
      {
 | 
						|
         file4readError( seqRead->file, seqRead->pos, seqRead->nextReadLen, "file4seqRead" ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         /* Make sure reading is aligned correctly for maximum speed */
 | 
						|
         if ( ( seqRead->pos + seqRead->nextReadLen ) % 0x400 && seqRead->avail )
 | 
						|
         {
 | 
						|
            error4( c4, e4result, E90701 ) ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
      seqRead->pos += seqRead->working ;
 | 
						|
      seqRead->nextReadLen = seqRead->total ;
 | 
						|
 | 
						|
      /* now pre-read the first one */
 | 
						|
      if ( urc == seqRead->nextReadLen )  /* ensure that it is available for reading */
 | 
						|
      {
 | 
						|
         seqRead->buf2avail = AR4SET ;
 | 
						|
         file4advanceRead( seqRead->file, seqRead->pos, seqRead->buf2, seqRead->nextReadLen, file4seqReadCompletionRoutine, seqRead ) ;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   return urc ;
 | 
						|
}
 | 
						|
 | 
						|
/* ensures that any advance-reads are complete */
 | 
						|
void file4seqReadInitUndo( const FILE4SEQ_READ *seqRead )
 | 
						|
{
 | 
						|
   if ( seqRead->doAdvance == 1 )
 | 
						|
   {
 | 
						|
      while ( seqRead->buf1avail == AR4SET )  /* wait for it to finish read */
 | 
						|
         Sleep( 0 ) ;
 | 
						|
      while ( seqRead->buf2avail == AR4SET )  /* wait for it to finish read */
 | 
						|
         Sleep( 0 ) ;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif  /* S4ADVANCE_READ */
 | 
						|
 | 
						|
unsigned S4FUNCTION file4seqRead( FILE4SEQ_READ *seqRead, void *ptr, const unsigned len )
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
   unsigned urc, bufferI, copyBytes ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqRead == 0 || ( ptr == 0 && len ) )
 | 
						|
      {
 | 
						|
         error4( 0, e4parm_null, E90701 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( seqRead->file == 0 )
 | 
						|
      {
 | 
						|
         error4( 0, e4parm, E90701 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = seqRead->file->codeBase ;
 | 
						|
   if ( c4 == 0 )  /* file closed */
 | 
						|
      return 0 ;
 | 
						|
   if ( error4code( c4 ) < 0 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   if ( seqRead->buffer == 0 )
 | 
						|
   {
 | 
						|
      urc = file4readLow( seqRead->file, seqRead->pos, ptr, len ) ;
 | 
						|
      seqRead->pos += urc ;
 | 
						|
      return urc ;
 | 
						|
   }
 | 
						|
 | 
						|
   if ( seqRead->avail == 0 )
 | 
						|
   {
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         if ( seqRead->pos < 0 )
 | 
						|
         {
 | 
						|
            error4( c4, e4result, E90701 ) ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
 | 
						|
      #ifdef S4ADVANCE_READ
 | 
						|
         if ( seqRead->doAdvance == 1 )
 | 
						|
            file4seqReadAdvance( seqRead, ptr, len ) ;
 | 
						|
         else
 | 
						|
      #endif
 | 
						|
         {  /* brace needed for else above */
 | 
						|
            urc = file4readLow( seqRead->file, seqRead->pos, seqRead->buffer, seqRead->nextReadLen ) ;
 | 
						|
            seqRead->avail = seqRead->working = urc ;
 | 
						|
 | 
						|
            if ( seqRead->working == UINT_MAX )
 | 
						|
            {
 | 
						|
               file4readError( seqRead->file, seqRead->pos, seqRead->nextReadLen, "file4seqRead" ) ;
 | 
						|
               return 0 ;
 | 
						|
            }
 | 
						|
 | 
						|
            #ifdef E4ANALYZE
 | 
						|
               /* Make sure reading is aligned correctly for maximum speed */
 | 
						|
               if ( ( seqRead->pos + seqRead->nextReadLen ) % 0x400 && seqRead->avail )
 | 
						|
               {
 | 
						|
                  error4( c4, e4result, E90701 ) ;
 | 
						|
                  return 0 ;
 | 
						|
               }
 | 
						|
            #endif
 | 
						|
            seqRead->pos += seqRead->working ;
 | 
						|
            seqRead->nextReadLen = seqRead->total ;
 | 
						|
         }
 | 
						|
   }
 | 
						|
 | 
						|
   if ( seqRead->avail >= len )
 | 
						|
   {
 | 
						|
      bufferI = seqRead->working - seqRead->avail ;
 | 
						|
      memcpy( ptr, seqRead->buffer + bufferI, len ) ;
 | 
						|
      seqRead->avail -= len ;
 | 
						|
      return len ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      if ( seqRead->avail == 0 )
 | 
						|
         return 0 ;
 | 
						|
 | 
						|
      bufferI = seqRead->working - seqRead->avail ;
 | 
						|
      memcpy( ptr, seqRead->buffer + bufferI, seqRead->avail ) ;
 | 
						|
 | 
						|
      copyBytes = seqRead->avail ;
 | 
						|
      seqRead->avail = 0 ;
 | 
						|
 | 
						|
      urc = file4seqRead( seqRead, (char *)ptr + copyBytes, len - copyBytes ) ;
 | 
						|
      if ( error4code( c4 ) < 0 )
 | 
						|
         return 0 ;
 | 
						|
 | 
						|
      return urc + copyBytes ;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION file4seqReadAll( FILE4SEQ_READ *seqRead, void *ptr, const unsigned int len )
 | 
						|
{
 | 
						|
   unsigned lenRead ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqRead == 0 || ( ptr == 0 && len ) )
 | 
						|
         return error4( 0, e4parm_null, E90702 ) ;
 | 
						|
   #endif
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( seqRead->file == 0 )
 | 
						|
         return error4( 0, e4parm, E90702 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   lenRead = file4seqRead( seqRead, ptr, len ) ;
 | 
						|
   if ( error4code( seqRead->file->codeBase ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   if ( lenRead != len )
 | 
						|
      return file4readError( seqRead->file, seqRead->pos, seqRead->nextReadLen, "file4seqReadAll" ) ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4ADVANCE_READ
 | 
						|
/* note that setting do-advance to '1' means that an un-init routine for the
 | 
						|
   file4seqRead must be called (to ensure that there are no outstanding reads) */
 | 
						|
int S4FUNCTION file4seqReadInitDo( FILE4SEQ_READ *seqRead, FILE4 *file, const long startPos, void *ptr, const unsigned ptrLen, const int doAdvance )
 | 
						|
#else
 | 
						|
int S4FUNCTION file4seqReadInitDo( FILE4SEQ_READ *seqRead, FILE4 *file, const long startPos, void *ptr, const unsigned ptrLen )
 | 
						|
#endif
 | 
						|
{
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( startPos < 0 || seqRead == 0 || file == 0 || ( ptrLen == 0 && ptr == 0 ) )
 | 
						|
         return error4( 0, e4parm, E90703 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   memset( (void *)seqRead, 0, sizeof( FILE4SEQ_READ ) ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_OPTIMIZE
 | 
						|
      opt4fileFlush( file, 1 ) ;
 | 
						|
   #endif
 | 
						|
   if ( ptrLen > 0 )
 | 
						|
   {
 | 
						|
      #ifdef S4ADVANCE_READ
 | 
						|
         seqRead->doAdvance = doAdvance ;
 | 
						|
         if ( doAdvance == 1 )
 | 
						|
         {
 | 
						|
            seqRead->total = (ptrLen / 2) & 0xFC00 ;  /* Make it a multiple of 1K */
 | 
						|
            seqRead->buf1 = (char *)ptr ;
 | 
						|
            seqRead->buf2 = (char *)ptr + seqRead->total ;
 | 
						|
            seqRead->buf1avail = AR4EMPTY ;
 | 
						|
            seqRead->buf2avail = AR4EMPTY ;
 | 
						|
            seqRead->buffer = seqRead->buf1 ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
      #endif
 | 
						|
         {  /* braces reqd. for else inside ifdef above */
 | 
						|
            seqRead->total = ptrLen & 0xFC00 ;  /* Make it a multiple of 1K */
 | 
						|
            seqRead->buffer = (char *)ptr ;
 | 
						|
         }
 | 
						|
 | 
						|
      if ( seqRead->total > ( ((unsigned long)startPos) % 0x400 ) )
 | 
						|
         seqRead->nextReadLen = seqRead->total - (unsigned)( ((unsigned long)startPos) % 0x400 ) ;
 | 
						|
   }
 | 
						|
   seqRead->pos = startPos ;
 | 
						|
   seqRead->file = file ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4WRITE_DELAY
 | 
						|
void S4CALL file4seqWriteCompletionRoutine( void *delay )
 | 
						|
{
 | 
						|
   /* just resets the avail flag */
 | 
						|
   *((int *)(((FILE4WRITE_DELAY *)(delay))->completionData)) = 1 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION file4seqWriteDelay( FILE4SEQ_WRITE *seqWrite )   /* not static due to testing exportation */
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
   #ifdef S4WIN32
 | 
						|
      #ifndef S4WRITE_DELAY
 | 
						|
         long urc ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
   unsigned toWrite ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqWrite == 0 )
 | 
						|
         return error4( 0, e4parm_null, E90705 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( seqWrite->file == 0 )  /* nothing to flush, just return */
 | 
						|
      return 0 ;
 | 
						|
   c4 = seqWrite->file->codeBase ;
 | 
						|
 | 
						|
   if ( c4 == 0 )  /* file closed */
 | 
						|
      return error4( 0, -120, E90704 ) ;
 | 
						|
   if ( error4code( c4 ) < 0 )
 | 
						|
      return e4codeBase ;
 | 
						|
   if ( seqWrite->buffer == 0 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if( seqWrite->pos < 0 )
 | 
						|
         return error4( c4, e4result, E90705 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   toWrite = seqWrite->working - seqWrite->avail ;
 | 
						|
 | 
						|
   if ( toWrite != 0 )
 | 
						|
   {
 | 
						|
      #ifndef S4OFF_OPTIMIZE
 | 
						|
         #ifdef E4ANALYZE_ALL
 | 
						|
            if ( seqWrite->file->hasDup == 1 )
 | 
						|
               if ( file4writePart( seqWrite->buffer, seqWrite->file, seqWrite->pos, toWrite ) != 0 )
 | 
						|
                  return error4( c4, e4opt, E80602 ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         if ( seqWrite->file->doBuffer == 1 && seqWrite->file->bufferWrites == 1 )
 | 
						|
         {
 | 
						|
            if ( file4write( seqWrite->file, seqWrite->pos, seqWrite->buffer, toWrite ) != 0 )
 | 
						|
               return error4describe( seqWrite->file->codeBase, e4write, E90705, seqWrite->file->name, 0, 0 ) ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
      #endif
 | 
						|
         {   /* needed for else just above */
 | 
						|
            /* queue up the 1/2 written to buffer for a delayed write, and
 | 
						|
               then set the current buffer pointer to point to the other
 | 
						|
               half (if and when it is not waiting to be delay written) */
 | 
						|
            if ( seqWrite->buffer == seqWrite->buf1 )
 | 
						|
            {
 | 
						|
               seqWrite->buf1avail = 0 ;
 | 
						|
               file4writeDelay( seqWrite->file, seqWrite->pos, seqWrite->buffer, toWrite, file4seqWriteCompletionRoutine, &seqWrite->buf1avail ) ;
 | 
						|
               while( seqWrite->buf2avail != 1 )  /* wait for write on other buffer piece to finish */
 | 
						|
                  Sleep( 0 ) ;
 | 
						|
               seqWrite->buffer = seqWrite->buf2 ;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
               seqWrite->buf2avail = 0 ;
 | 
						|
               file4writeDelay( seqWrite->file, seqWrite->pos, seqWrite->buffer, toWrite, file4seqWriteCompletionRoutine, &seqWrite->buf2avail ) ;
 | 
						|
               while( seqWrite->buf1avail != 1 )  /* wait for write on other buffer piece to finish */
 | 
						|
                  Sleep( 0 ) ;
 | 
						|
               seqWrite->buffer = seqWrite->buf1 ;
 | 
						|
            }
 | 
						|
         }   /* needed for else above */
 | 
						|
 | 
						|
      /* file4flush( seqWrite->file )   VAX fix (flush req'd on write) */
 | 
						|
      seqWrite->pos += toWrite ;
 | 
						|
   }
 | 
						|
 | 
						|
   seqWrite->avail = seqWrite->working = seqWrite->total ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION file4seqWriteFlush( FILE4SEQ_WRITE *seqWrite )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   if ( seqWrite->file == 0 )  /* nothing to flush, just return */
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   rc = file4seqWriteDelay( seqWrite ) ;
 | 
						|
   file4writeDelayFlush( seqWrite->file, 1 ) ;
 | 
						|
 | 
						|
   /* and now, absolutely ensure that any delayed writes get to finish their
 | 
						|
      completion routine before continuing (i.e. avoid memory corruption) */
 | 
						|
   while( seqWrite->buf2avail != 1 )  /* wait for write on other buffer piece to finish */
 | 
						|
      Sleep( 0 ) ;
 | 
						|
   while( seqWrite->buf1avail != 1 )  /* wait for write on other buffer piece to finish */
 | 
						|
      Sleep( 0 ) ;
 | 
						|
 | 
						|
   /* ensure that any optimized reads are dumped in order that new delayed
 | 
						|
      writes will get recognized properly */
 | 
						|
   #ifndef S4OFF_OPTIMIZE
 | 
						|
      opt4fileFlush( seqWrite->file, 1 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
#else
 | 
						|
 | 
						|
int S4FUNCTION file4seqWriteFlush( FILE4SEQ_WRITE *seqWrite )
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
   long urc ;
 | 
						|
   unsigned int toWrite ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqWrite == 0 )
 | 
						|
         return error4( 0, e4parm_null, E90705 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( seqWrite->file == 0 )  /* nothing to flush, just return */
 | 
						|
      return 0 ;
 | 
						|
   c4 = seqWrite->file->codeBase ;
 | 
						|
 | 
						|
   if ( c4 == 0 )  /* file closed */
 | 
						|
      return error4( 0, -120, E90704 ) ;
 | 
						|
   if ( error4code( c4 ) < 0 )
 | 
						|
      return e4codeBase ;
 | 
						|
   if ( seqWrite->buffer == 0 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if( seqWrite->pos < 0 )
 | 
						|
         return error4( c4, e4result, E90705 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   toWrite = seqWrite->working - seqWrite->avail ;
 | 
						|
 | 
						|
   if ( toWrite != 0 )
 | 
						|
   {
 | 
						|
      #ifndef S4OFF_OPTIMIZE
 | 
						|
         #ifdef E4ANALYZE_ALL
 | 
						|
            if ( seqWrite->file->hasDup == 1 )
 | 
						|
               if ( file4writePart( seqWrite->buffer, seqWrite->file, seqWrite->pos, toWrite ) != 0 )
 | 
						|
                  return error4( c4, e4opt, E80602 ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         if ( seqWrite->file->doBuffer == 1 && seqWrite->file->bufferWrites == 1 )
 | 
						|
         {
 | 
						|
            if ( file4write( seqWrite->file, seqWrite->pos, seqWrite->buffer, toWrite ) != 0 )
 | 
						|
               return error4describe( seqWrite->file->codeBase, e4write, E90705, seqWrite->file->name, 0, 0 ) ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
      #endif
 | 
						|
         {   /* needed for else just above */
 | 
						|
            urc = file4writeLow( seqWrite->file, seqWrite->pos, seqWrite->buffer, toWrite, 1, 1 ) ;
 | 
						|
            if ( urc != 0 )
 | 
						|
               return (int)urc ;
 | 
						|
         }   /* needed for else above */
 | 
						|
 | 
						|
      /* file4flush( seqWrite->file )   VAX fix (flush req'd on write) */
 | 
						|
      seqWrite->pos += toWrite ;
 | 
						|
   }
 | 
						|
 | 
						|
   seqWrite->avail = seqWrite->working = seqWrite->total ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif /* S4WRITE_DELAY */
 | 
						|
 | 
						|
int S4FUNCTION file4seqWrite( FILE4SEQ_WRITE *seqWrite, const void *buffer, const unsigned ptrLen )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   unsigned firstLen ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqWrite == 0 || ( ptrLen && buffer == 0 ) )
 | 
						|
         return error4( 0, e4parm_null, E90704 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = seqWrite->file->codeBase ;
 | 
						|
   if ( c4 == 0 )  /* file closed */
 | 
						|
      return error4( 0, -120, E90704 ) ;
 | 
						|
 | 
						|
   if ( error4code( c4 ) < 0 )
 | 
						|
      return e4codeBase ;
 | 
						|
 | 
						|
   if ( seqWrite->buffer == 0 )
 | 
						|
   {
 | 
						|
      rc = file4write( seqWrite->file, seqWrite->pos, buffer, ptrLen ) ;
 | 
						|
      #ifndef S4OFF_OPTIMIZE
 | 
						|
         #ifdef E4ANALYZE_ALL
 | 
						|
            if ( seqWrite->file->hasDup == 1 )
 | 
						|
               if ( file4writePart( buffer, seqWrite->file, seqWrite->pos, ptrLen ) != 0 )
 | 
						|
                  return error4( c4, e4opt, E80602 ) ;
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
      seqWrite->pos += ptrLen ;
 | 
						|
      return rc ;
 | 
						|
   }
 | 
						|
 | 
						|
   if ( seqWrite->avail == 0 )
 | 
						|
   {
 | 
						|
      #ifdef S4WRITE_DELAY
 | 
						|
         if ( file4seqWriteDelay( seqWrite ) < 0 )
 | 
						|
            return -1 ;
 | 
						|
      #else
 | 
						|
         if ( file4seqWriteFlush( seqWrite ) < 0 )
 | 
						|
            return -1 ;
 | 
						|
      #endif
 | 
						|
   }
 | 
						|
 | 
						|
   if ( seqWrite->avail >= ptrLen )
 | 
						|
   {
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         if ( seqWrite->working < seqWrite->avail || ( seqWrite->working - seqWrite->avail + ptrLen ) > seqWrite->total )
 | 
						|
            return error4( c4, e4result, E90704 ) ;
 | 
						|
      #endif
 | 
						|
      memcpy( seqWrite->buffer + ( seqWrite->working - seqWrite->avail ), buffer, ptrLen ) ;
 | 
						|
      seqWrite->avail -= ptrLen ;
 | 
						|
      return 0 ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      firstLen = seqWrite->avail ;
 | 
						|
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         if ( seqWrite->working < seqWrite->avail || seqWrite->working > seqWrite->total )
 | 
						|
            return error4( c4, e4result, E90704 ) ;
 | 
						|
      #endif
 | 
						|
      memcpy( seqWrite->buffer + ( seqWrite->working - seqWrite->avail ), buffer, seqWrite->avail ) ;
 | 
						|
 | 
						|
      seqWrite->avail = 0 ;
 | 
						|
 | 
						|
      return file4seqWrite( seqWrite, (char *)buffer + firstLen, ptrLen - firstLen ) ;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
/* note that the sequential functions are not generally useful when hashing is in place since hashing effectively performs bufferring */
 | 
						|
int S4FUNCTION file4seqWriteInit( FILE4SEQ_WRITE *seqWrite, FILE4 *file, const long startOffset, void *ptr, const unsigned ptrLen )
 | 
						|
{
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqWrite == 0 || file == 0 || startOffset < 0 || ( ptr == 0 && ptrLen == 0 ) )
 | 
						|
         return error4( 0, e4parm, E90706 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   memset( (void *)seqWrite, 0, sizeof( FILE4SEQ_WRITE ) ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_OPTIMIZE
 | 
						|
      opt4fileFlush( file, 1 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   seqWrite->file = file ;
 | 
						|
 | 
						|
   if ( ptr != 0 )
 | 
						|
   {
 | 
						|
      #ifdef S4WRITE_DELAY
 | 
						|
         seqWrite->total = (ptrLen / 2) & 0x7E00 ;  /* Make it a multiple of 512 bytes */
 | 
						|
         seqWrite->buf1 = (char *)ptr ;
 | 
						|
         seqWrite->buf2 = (char *)ptr + seqWrite->total ;
 | 
						|
         seqWrite->buf1avail = 1 ;
 | 
						|
         seqWrite->buf2avail = 1 ;
 | 
						|
         seqWrite->buffer = seqWrite->buf1 ;
 | 
						|
      #else
 | 
						|
         seqWrite->total = ptrLen & 0xFC00 ;  /* Make it a multiple of 1K */
 | 
						|
         seqWrite->buffer = (char *)ptr ;
 | 
						|
      #endif
 | 
						|
      if ( seqWrite->total == 0 )  /* buffer is too small, so set it to 0 */
 | 
						|
         seqWrite->buffer = 0 ;
 | 
						|
      else
 | 
						|
      {
 | 
						|
         if ( seqWrite->total > (unsigned)( ((unsigned long)startOffset) % 0x400 ) )
 | 
						|
            seqWrite->avail = seqWrite->working = seqWrite->total - (unsigned)( ((unsigned long)startOffset) % 0x400 ) ;
 | 
						|
      }
 | 
						|
   }
 | 
						|
   seqWrite->pos = startOffset ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION file4seqWriteRepeat( FILE4SEQ_WRITE *seqWrite, const long nRepeat, const char ch )
 | 
						|
{
 | 
						|
   char buf[512] ;
 | 
						|
   long numRepeat ;
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( seqWrite == 0 || nRepeat < 0 )
 | 
						|
         return error4( 0, e4parm, E90707 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   numRepeat = nRepeat ;
 | 
						|
   memset( (void *)buf, ch, sizeof(buf) ) ;
 | 
						|
 | 
						|
   while ( numRepeat > sizeof(buf) )
 | 
						|
   {
 | 
						|
      rc = file4seqWrite( seqWrite, buf, (unsigned)sizeof( buf ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return error4stack( seqWrite->file->codeBase, (short)rc, E90707 ) ;
 | 
						|
      numRepeat -= sizeof(buf) ;
 | 
						|
   }
 | 
						|
 | 
						|
   return file4seqWrite( seqWrite, buf, (unsigned)numRepeat ) ;
 | 
						|
}
 |