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 ) ;
 | |
| }
 |