campo-sirio/cb/source/m4file.c

723 lines
22 KiB
C
Raw Normal View History

/* m4file.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif
#endif
#ifndef S4CLIENT
#ifndef S4MEMO_OFF
#ifndef S4OFF_MULTI
/* ndx/clipper versions have no free chain--do not lock memo file */
#ifndef N4OTHER
/* the lock is forced since a memo file lock only lasts if the .dbf file is locked */
int memo4fileLock( MEMO4FILE *f4memo )
{
int rc, oldAttempts ;
if ( f4memo->fileLock == 1 )
return 0 ;
if ( f4memo->file.hand == -1 )
return -1 ;
oldAttempts = f4memo->file.codeBase->lockAttempts ;
f4memo->file.codeBase->lockAttempts = WAIT4EVER ;
#ifdef S4MDX
rc = file4lock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
#endif
#ifdef S4FOX
rc = file4lock( &f4memo->file, L4LOCK_POS_OLD, 1L ) ;
#endif
f4memo->file.codeBase->lockAttempts = oldAttempts ;
if ( rc == 0 )
f4memo->fileLock = 1 ;
#ifndef S4OPTIMIZE_OFF
file4refresh( &f4memo->file ) ; /* make sure all up to date */
#endif
return rc ;
}
int memo4fileUnlock( MEMO4FILE *f4memo )
{
int rc ;
if ( f4memo->fileLock == 0 )
return 0 ;
#ifdef S4MDX
rc = file4unlock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
#endif
#ifdef S4FOX
rc = file4unlock( &f4memo->file, L4LOCK_POS_OLD, 1L ) ;
#endif
if ( rc == 0 )
f4memo->fileLock = 0 ;
return rc ;
}
#endif
#endif
int memo4fileOpen( MEMO4FILE *f4memo, DATA4FILE *d4, char *name )
{
MEMO4HEADER header ;
int rc ;
f4memo->data = d4 ;
if ( file4open( &f4memo->file, d4->c4, name, 1 ) )
return -1 ;
#ifndef S4OPTIMIZE_OFF
file4optimize( &f4memo->file, d4->c4->optimize, OPT4OTHER ) ;
#endif
if ( (rc = file4readAll(&f4memo->file, 0L, &header, sizeof(header))) < 0 )
return -1 ;
#ifdef S4BYTE_SWAP
header.nextBlock = x4reverseLong( (void *)&header.nextBlock ) ;
#ifndef S4MNDX
#ifndef S4MFOX
header.x102 = 0x201 ;
#endif
header.blockSize = x4reverseShort( (void *)&header.blockSize ) ;
#endif
#endif
#ifdef S4MFOX
f4memo->blockSize = x4reverseShort( (void *)&header.blockSize ) ;
#else
#ifdef S4MNDX
f4memo->blockSize = MEMO4SIZE ;
#else
f4memo->blockSize = header.blockSize ;
#endif
#endif
return rc ;
}
#ifdef S4MFOX
/* offset is # bytes from start of memo that reading should begin, readMax is
the maximum possible that can be read (limited to an unsigned int, so is
16-bit/32-bit compiler dependent.
*/
int memo4fileReadPart( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned *lenPtr, unsigned long offset, const unsigned readMax, long *type )
{
unsigned long pos, avail ;
MEMO4BLOCK memoBlock ;
if ( memoId <= 0L )
{
*lenPtr = 0 ;
return 0 ;
}
pos = (unsigned long)memoId * f4memo->blockSize ;
if ( file4readAll( &f4memo->file, pos, &memoBlock, sizeof( MEMO4BLOCK ) ) < 0)
return -1 ;
#ifdef S4BYTE_SWAP
#ifdef S4MFOX
memoBlock.type = x4reverseLong( (void *)&memoBlock.type ) ;
#else
memoBlock.startPos = x4reverseShort( (void *)&memoBlock.startPos ) ;
#endif
memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
#endif
memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
avail = memoBlock.numChars - offset ;
if ( avail > (unsigned long)readMax )
avail = readMax ;
if ( avail > (unsigned long)*lenPtr )
{
if ( *lenPtr > 0 )
u4free( *ptrPtr ) ;
*ptrPtr = (char *)u4allocEr( f4memo->file.codeBase, avail + 1 ) ;
if ( *ptrPtr == 0 )
return e4memory ;
}
*lenPtr = (unsigned)avail ;
*type = x4reverseLong( &memoBlock.type ) ;
return (int)file4readAll( &f4memo->file, offset + pos + (long)(2*sizeof(S4LONG)), *ptrPtr, *lenPtr ) ;
}
#endif
#ifdef S4MNDX
extern char f4memoNullChar ;
#endif
#ifdef S4MFOX
int memo4fileRead( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned int *ptrLen, long *mType )
#else
int memo4fileRead( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned int *ptrLen )
#endif
{
#ifdef S4MFOX
return memo4fileReadPart( f4memo, memoId, ptrPtr, ptrLen, 0L, UINT_MAX -100, mType ) ;
#else
long pos ;
CODE4 *c4 ;
#ifdef S4MNDX
unsigned int amtRead, lenRead, loop ;
char *tPtr ;
#else
MEMO4BLOCK memoBlock ;
unsigned finalLen ;
#endif
c4 = f4memo->file.codeBase ;
#ifdef S4MNDX
if ( memoId <= 0L )
{
if ( *ptrPtr != &f4memoNullChar )
u4free( *ptrPtr ) ;
*ptrPtr = 0 ;
*ptrLen = 0 ;
return 0 ;
}
pos = memoId * f4memo->blockSize ;
amtRead = 0 ;
if ( c4->memoUseBuffer == 0 )
{
c4->memoUseBuffer = (char*)u4allocEr( c4, MEMO4SIZE ) ;
if ( c4->memoUseBuffer == 0 )
return e4memory ;
}
for( amtRead = 0 ;; )
{
lenRead = file4read( &f4memo->file, pos + amtRead, c4->memoUseBuffer, MEMO4SIZE ) ;
if ( lenRead <= 0 )
return -1 ;
for ( loop = 0 ; lenRead > 0 ; loop++, lenRead-- )
{
if ( c4->memoUseBuffer[loop] == 0x1A ) /* if done */
{
if ( loop + amtRead > 0 )
{
if ( *ptrLen < amtRead + loop )
{
tPtr = (char *)u4allocEr( c4, amtRead + loop + 1 ) ;
if ( tPtr == 0 )
return e4memory ;
memcpy( tPtr, *ptrPtr, (int)amtRead ) ;
if ( *ptrPtr != &f4memoNullChar )
u4free( *ptrPtr ) ;
*ptrPtr = tPtr ;
}
*ptrLen = amtRead + loop ;
memcpy( *ptrPtr + amtRead, c4->memoUseBuffer, loop ) ;
(*ptrPtr)[amtRead+loop] = 0 ;
return 0 ;
}
else
{
tPtr = 0 ;
if ( *ptrPtr != &f4memoNullChar )
u4free( *ptrPtr ) ;
*ptrPtr = 0 ;
*ptrLen = 0 ;
}
return 0 ;
}
}
lenRead = loop ;
if ( *ptrLen < amtRead + lenRead )
{
tPtr = (char *)u4allocEr( c4, amtRead + lenRead + 1 ) ;
if ( tPtr == 0 )
return e4memory ;
if ( *ptrLen > 0 )
{
memcpy( tPtr, *ptrPtr, *ptrLen ) ;
u4free( *ptrPtr ) ;
}
*ptrPtr = tPtr ;
*ptrLen = (unsigned)( amtRead + lenRead ) ;
}
memcpy( *ptrPtr + amtRead, c4->memoUseBuffer, lenRead ) ;
amtRead += lenRead ;
}
#else
if ( memoId <= 0L )
{
*ptrLen = 0 ;
return 0 ;
}
pos = memoId * f4memo->blockSize ;
if ( file4readAll( &f4memo->file, pos, &memoBlock, sizeof( MEMO4BLOCK ) ) < 0)
return -1 ;
#ifdef S4BYTE_SWAP
memoBlock.startPos = x4reverseShort( (void *)&memoBlock.startPos ) ;
memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
#endif
if ( memoBlock.minusOne != -1 ) /* must be an invalid entry, so return an empty entry */
{
*ptrLen = 0 ;
return 0 ;
}
else
{
if ( memoBlock.numChars >= UINT_MAX )
return error4( c4, e4info, E95210 ) ;
finalLen = (unsigned)memoBlock.numChars - 2 * ( sizeof(short) ) - ( sizeof(S4LONG) ) ;
if ( finalLen > *ptrLen )
{
if ( *ptrLen > 0 )
u4free( *ptrPtr ) ;
*ptrPtr = (char *)u4allocEr( c4, finalLen + 1 ) ;
if ( *ptrPtr == 0 )
return e4memory ;
}
*ptrLen = finalLen ;
return file4readAll( &f4memo->file, pos+ memoBlock.startPos, *ptrPtr, finalLen ) ;
}
#endif
#endif
}
#ifndef S4OFF_WRITE
#ifdef S4MFOX
/* Writes partial data to a memo record.
Usage rules:
Must call this function with an offset == 0 to write 1st part of block
before any additional writing. In addition, the memoLen must be
accurately set during the first call in order to reserve the correct
amount of memo space ahead of time. Later calls just fill in data to
the reserved disk space.
lenWrite is the amount of data to write, offset is the number of
bytes from the beginning of the memo in which to write the data
Secondary calls to this function assume that everything has been
previously set up, and merely performs a file write to the reserved
space. The space is not checked to see whether or not it actually
is in the bounds specified, so use with care.
*/
int memo4fileWritePart( MEMO4FILE *f4memo, long *memoIdPtr, const char *ptr, const long memoLen, const long offset, const unsigned lenWrite, const long type )
{
int strNumBlocks ;
long pos ;
#ifndef S4OFF_MULTI
#ifndef N4OTHER
int rc, lockCond ;
#endif
#endif
MEMO4BLOCK oldMemoBlock ;
MEMO4HEADER mh ;
unsigned lenRead ;
long blockNo ;
unsigned nEntryBlks = 0 ;
#ifdef E4PARM_LOW
if ( memoIdPtr == 0 )
return error4( 0, e4parm_null, E95208 ) ;
if ( f4memo->file.hand == -1 ) /* file closed! */
return error4( 0, e4parm, E95208 ) ;
#endif
if ( offset == 0 ) /* must do the set-up work */
{
if ( memoLen == 0 )
{
*memoIdPtr = 0L ;
return 0 ;
}
#ifdef E4MISC
if ( f4memo->blockSize <= 1 )
return error4( f4memo->data->c4, e4info, E85202 ) ;
#endif
strNumBlocks = (int) ((memoLen + sizeof(MEMO4BLOCK) + f4memo->blockSize-1) / f4memo->blockSize) ;
if ( *memoIdPtr <= 0L )
blockNo = 0L ;
else
{
blockNo = *memoIdPtr ;
pos = blockNo * f4memo->blockSize ;
file4readAll( &f4memo->file, pos, (char *)&oldMemoBlock, sizeof(oldMemoBlock) ) ;
#ifdef S4BYTE_SWAP
#ifdef S4MFOX
oldMemoBlock.type = x4reverseLong( (void *)&oldMemoBlock.type ) ;
#else
oldMemoBlock.startPos = x4reverseShort( (void *)&oldMemoBlock.startPos ) ;
#endif
oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
#endif
oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
nEntryBlks = (unsigned) ((oldMemoBlock.numChars + f4memo->blockSize-1)/ f4memo->blockSize ) ;
}
if ( nEntryBlks >= ((unsigned)strNumBlocks) && blockNo ) /* write to existing position */
*memoIdPtr = blockNo ;
else /* read in header record */
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
lockCond = f4memo->data->memoFile.fileLock ;
rc = memo4fileLock( &f4memo->data->memoFile ) ;
if ( rc )
return rc ;
#endif
#endif
lenRead = file4read( &f4memo->file, 0L, &mh, sizeof( mh ) ) ;
#ifdef S4BYTE_SWAP
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
mh.blockSize = x4reverseShort( (void *)&mh.blockSize ) ;
#endif
if ( error4code( f4memo->data->c4 ) < 0 )
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
return -1 ;
}
if ( lenRead != sizeof( mh ) )
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
return file4readError( &f4memo->file, 0L, sizeof( mh ), "memo4fileWritePart" ) ;
}
*memoIdPtr = x4reverseLong( (void *)&mh.nextBlock ) ;
mh.nextBlock = *memoIdPtr + strNumBlocks ;
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
#ifdef S4BYTE_SWAP
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
mh.blockSize = x4reverseShort( (void *)&mh.blockSize ) ;
#endif
file4write( &f4memo->file, 0L, &mh, sizeof( mh ) ) ;
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
}
if ( memo4fileDump( f4memo, *memoIdPtr, ptr, lenWrite, memoLen, type ) < 0 )
return -1 ;
}
else
return file4write( &f4memo->file, *memoIdPtr * f4memo->blockSize + offset + sizeof( oldMemoBlock ), ptr, lenWrite ) ;
return 0 ;
}
#endif /* S4MFOX */
int memo4fileWrite( MEMO4FILE *f4memo, long *memoIdPtr, const char *ptr, const unsigned ptrLen )
{
#ifdef S4MFOX
return memo4fileWritePart( f4memo, memoIdPtr, ptr, (long)ptrLen, 0L, ptrLen, 1L ) ;
#else
int strNumBlocks ;
long pos ;
#ifndef S4MDX
#ifndef S4OFF_MULTI
#ifndef N4OTHER
int rc, lockCond ;
#endif
#endif
#endif
#ifdef S4MNDX
MEMO4HEADER mh ;
long lenRead ;
char buf[MEMO4SIZE] ;
int readSize, i ;
#else
MEMO4BLOCK oldMemoBlock ;
MEMO4CHAIN_ENTRY newEntry, cur, prev ;
int strWritten ;
long prevPrevEntry, prevPrevNum ;
long fileLen, extraLen ;
#endif
#ifdef E4PARM_LOW
if ( memoIdPtr == 0 )
return error4( 0, e4parm_null, E95209 ) ;
#endif
#ifdef S4MNDX
if ( ptrLen == 0 )
{
*memoIdPtr = 0L ;
return 0 ;
}
strNumBlocks = (int)(((long)ptrLen + f4memo->blockSize-1) / f4memo->blockSize) ;
if ( *memoIdPtr <= 0L )
*memoIdPtr = 0L ;
else /* read in old record to see if new entry can fit */
{
readSize = 0 ;
pos = *memoIdPtr * f4memo->blockSize ;
do
{
readSize += MEMO4SIZE ;
lenRead = file4read( &f4memo->file, pos, buf, MEMO4SIZE ) ;
if ( lenRead <= 0 )
return file4readError( &f4memo->file, pos, MEMO4SIZE, "memo4fileWrite()" ) ;
for ( i=0 ; ((long) i) < lenRead ; i++ )
if ( buf[i] == (char)0x1A ) break ;
#ifdef E4MISC
if ( buf[i] != (char)0x1A && lenRead != MEMO4SIZE )
return error4( f4memo->file.codeBase, e4info, E85203 ) ;
#endif
pos += MEMO4SIZE ;
} while ( i >= MEMO4SIZE && buf[i] != (char) 0x1A ) ; /* Continue if Esc is not located */
if ( ((unsigned)readSize) <= ptrLen ) /* there is not room */
*memoIdPtr = 0 ;
}
if ( *memoIdPtr == 0 ) /* add entry at eof */
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
lockCond = f4memo->data->memoFile.fileLock ;
rc = memo4fileLock( &f4memo->data->memoFile ) ;
if ( rc )
return rc ;
#endif
#endif
lenRead = file4read( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
#ifdef S4BYTE_SWAP
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
#endif
if ( error4code( f4memo->data->c4 ) < 0 )
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
return -1 ;
}
if ( lenRead != sizeof( mh ) )
{
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
return file4readError( &f4memo->file, 0L, sizeof( mh ), "memo4fileWrite()" ) ;
}
*memoIdPtr = mh.nextBlock ;
mh.nextBlock = *memoIdPtr + strNumBlocks ;
#ifdef S4BYTE_SWAP
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
#endif
file4write( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
#ifndef S4OFF_MULTI
#ifndef N4OTHER
if ( !lockCond )
memo4fileUnlock( &f4memo->data->memoFile ) ;
#endif
#endif
#ifdef S4BYTE_SWAP
mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
#endif
}
if ( memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) < 0 )
return -1 ;
return 0 ;
#else
/* S4MMDX */
memset( (void *)&newEntry, 0, sizeof(newEntry) ) ;
newEntry.blockNo = *memoIdPtr ;
strWritten = 0 ;
if ( ptrLen == 0 )
{
strWritten = 1 ;
*memoIdPtr = 0 ;
}
/* Initialize information about the old memo entry */
if ( newEntry.blockNo <= 0L )
{
if ( strWritten )
{
*memoIdPtr = 0L ;
return 0 ;
}
newEntry.num = 0 ;
}
else
{
pos = newEntry.blockNo * f4memo->blockSize ;
file4readAll( &f4memo->file, pos, (char *)&oldMemoBlock, sizeof(oldMemoBlock) ) ;
#ifdef S4BYTE_SWAP
oldMemoBlock.startPos = x4reverseShort( (void *)&oldMemoBlock.startPos ) ;
oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
#endif
newEntry.num = (unsigned)(((long)oldMemoBlock.numChars + (long)f4memo->blockSize-1)/ f4memo->blockSize ) ;
}
strNumBlocks = (int)(((long)ptrLen+2*(sizeof(short))+(sizeof(S4LONG))+ f4memo->blockSize-1) / f4memo->blockSize ) ;
if ( newEntry.num >= strNumBlocks && !strWritten )
{
*memoIdPtr = newEntry.blockNo + newEntry.num - strNumBlocks ;
if ( memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) < 0 )
return -1 ;
strWritten = 1 ;
if ( newEntry.num == strNumBlocks )
return 0 ;
newEntry.num -= strNumBlocks ;
}
/* Initialize 'chain' */
memset( (void *)&cur, 0, sizeof(cur) ) ;
memset( (void *)&prev, 0, sizeof(prev) ) ;
for(;;)
{
if ( error4code( f4memo->data->c4 ) < 0 )
return -1 ;
memo4fileChainFlush( f4memo, &prev ) ;
prevPrevEntry = prev.blockNo ;
prevPrevNum = prev.num ;
memcpy( (void *)&prev, (void *)&cur, sizeof(prev) ) ;
if ( newEntry.blockNo > 0 && prev.next > newEntry.blockNo )
{
/* See if the new entry fits in here */
memcpy( (void *)&cur, (void *)&newEntry, sizeof(cur) ) ;
newEntry.blockNo = 0 ;
cur.next = prev.next ;
prev.next = cur.blockNo ;
cur.toDisk = prev.toDisk = 1 ;
}
else
memo4fileChainSkip( f4memo, &cur ) ;
/* See if the entries can be combined. */
if ( prev.blockNo + prev.num == cur.blockNo && prev.num )
{
/* 'cur' becomes the combined groups. */
prev.toDisk = 0 ;
cur.toDisk = 1 ;
cur.blockNo = prev.blockNo ;
if ( cur.num >= 0 )
cur.num += prev.num ;
prev.blockNo = prevPrevEntry ;
prev.num = prevPrevNum ;
}
if ( strWritten )
{
if ( newEntry.blockNo == 0 )
{
memo4fileChainFlush( f4memo, &prev ) ;
memo4fileChainFlush( f4memo, &cur ) ;
return 0 ;
}
}
else /* 'str' is not yet written, try the current entry */
{
if ( cur.next == -1 ) /* End of file */
cur.num = strNumBlocks ;
if ( cur.num >= strNumBlocks )
{
cur.num -= strNumBlocks ;
*memoIdPtr = cur.blockNo + cur.num ;
memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) ;
if ( cur.next == -1 ) /* if end of file */
{
/* For dBASE IV compatibility */
fileLen = file4len( &f4memo->file ) ;
extraLen = f4memo->blockSize - fileLen % f4memo->blockSize ;
if ( extraLen != f4memo->blockSize )
file4lenSet( &f4memo->file, fileLen+extraLen ) ;
}
strWritten = 1 ;
if ( cur.num == 0 )
{
if ( cur.next == -1 ) /* End of file */
prev.next = cur.blockNo + strNumBlocks ;
else
prev.next = cur.next ;
prev.toDisk = 1 ;
cur.toDisk = 0 ;
}
else
cur.toDisk = 1 ;
}
}
}
#endif
#endif
}
#endif /* S4OFF_WRITE */
#endif /* S4MEMO_OFF */
#endif /* S4CLIENT */