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