campo-sirio/cb/source/f4filese.c
alex af15e0698b Codebase
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-06-16 13:01:08 +00:00

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