1974 lines
54 KiB
C
Executable File
1974 lines
54 KiB
C
Executable File
/* i4ntag.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
|
|
|
|
#include "d4all.h"
|
|
#ifdef __TURBOC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifdef S4CLIENT
|
|
TAG4 *S4FUNCTION t4openLow( DATA4 *d4, INDEX4 *i4ndx, const char *fileName, const char *indexName )
|
|
{
|
|
CODE4 *c4 ;
|
|
CONNECTION4OPEN_TAG_INFO_IN dataIn ;
|
|
CONNECTION4OPEN_TAG_INFO_OUT *out ;
|
|
CONNECTION4 *connection ;
|
|
int rc ;
|
|
TAG4 *returnTag ;
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( d4, 2, E94903 ) )
|
|
return 0 ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 || fileName == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E94903 ) ;
|
|
return 0 ; ;
|
|
}
|
|
#endif
|
|
|
|
c4 = d4->codeBase ;
|
|
if ( error4code( c4 ) < 0 )
|
|
return 0 ;
|
|
|
|
switch( code4indexFormat( c4 ) )
|
|
{
|
|
case r4ndx:
|
|
case r4ntx:
|
|
break ;
|
|
default:
|
|
{
|
|
error4( c4, e4notSupported, E81719 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
if ( strlen( fileName ) > LEN4PATH )
|
|
{
|
|
error4( c4, e4name, E94903 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
memset( &dataIn, 0, sizeof( CONNECTION4OPEN_TAG_INFO_IN ) ) ;
|
|
connection = d4->dataFile->connection ;
|
|
if ( connection == 0 )
|
|
{
|
|
error4( c4, e4connection, E81704 ) ;
|
|
return 0 ;
|
|
}
|
|
connection4assign( connection, CON4TAG_OPEN, data4clientId( d4 ), data4serverId( d4 ) ) ;
|
|
dataIn.openForCreate = c4->openForCreate ;
|
|
|
|
#ifdef S4SINGLE
|
|
dataIn.exclusiveClient = 1 ;
|
|
#else
|
|
if ( c4->singleOpen == OPEN4DENY_RW )
|
|
dataIn.accessMode = OPEN4DENY_RW ;
|
|
else
|
|
dataIn.accessMode = c4->accessMode ;
|
|
#endif
|
|
|
|
dataIn.readOnly = c4->readOnly ;
|
|
dataIn.safety = c4->safety ; /* for catalog */
|
|
dataIn.errDefaultUnique = c4->errDefaultUnique ;
|
|
u4ncpy( dataIn.tagName, fileName, sizeof( dataIn.tagName ) ) ;
|
|
if ( i4ndx != 0 )
|
|
dataIn.hasIndex = 1 ;
|
|
|
|
if ( indexName != 0 )
|
|
u4ncpy( dataIn.indexName, indexName, sizeof( dataIn.indexName ) ) ;
|
|
|
|
if ( i4ndx != 0 )
|
|
dataIn.nameLen = strlen( i4ndx->indexFile->accessName ) + 1 ;
|
|
connection4addData( connection, &dataIn, sizeof( CONNECTION4OPEN_TAG_INFO_IN ), 0 ) ;
|
|
if ( i4ndx != 0 )
|
|
connection4addData( connection, i4ndx->indexFile->accessName, dataIn.nameLen, 0 ) ;
|
|
connection4send( connection ) ;
|
|
rc = connection4receive( connection ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
error4( c4, rc, E81701 ) ;
|
|
return 0 ;
|
|
}
|
|
rc = connection4status( connection ) ;
|
|
if ( rc != 0 )
|
|
{
|
|
if ( rc < 0 )
|
|
{
|
|
if ( c4->errOpen == 0 )
|
|
{
|
|
if ( error4code( c4 ) >= 0 )
|
|
error4set( c4, r4noOpen ) ;
|
|
}
|
|
else
|
|
connection4error( connection, c4, rc, E94903 ) ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
out = (CONNECTION4OPEN_TAG_INFO_OUT *)connection4data( connection ) ;
|
|
|
|
if ( client4indexSetup( c4, d4, d4->dataFile, 1, connection4data( connection ) + sizeof(CONNECTION4OPEN_TAG_INFO_OUT),
|
|
(unsigned int)connection4len( connection ), (char*)fileName, i4ndx ) < 0 )
|
|
{
|
|
error4( c4, e4connection, E94903 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
i4setup( c4, d4, (char *)fileName, out->autoOpened, i4ndx ) ;
|
|
|
|
returnTag = d4tag( d4, fileName ) ;
|
|
#ifndef S4OFF_TRAN
|
|
returnTag->isValid = 1 ;
|
|
#endif
|
|
return returnTag ;
|
|
}
|
|
|
|
int S4FUNCTION t4close( TAG4 *t4 )
|
|
{
|
|
INDEX4 *i4 ;
|
|
CODE4 *c4 ;
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( t4, 4, E91637 ) )
|
|
return -1 ;
|
|
#endif
|
|
|
|
i4 = t4->index ;
|
|
c4 = i4->codeBase ;
|
|
|
|
if ( code4indexFormat( c4 ) != r4ntx ) /* function not supported */
|
|
return error4( c4, e4notSupported, E81719 ) ;
|
|
|
|
if ( l4numNodes( &i4->tags ) == 1 ) /* only the one tag, so remove index */
|
|
return i4close( i4 ) ;
|
|
else /* just free up the one tag so it is no longer available */
|
|
{
|
|
l4remove( &i4->tags, t4 ) ;
|
|
mem4free( c4->tagMemory, t4 ) ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
#else
|
|
#ifndef S4INDEX_OFF
|
|
|
|
int tfile4type( TAG4FILE *t4 )
|
|
{
|
|
#ifdef S4FOX
|
|
return t4->expr->type ;
|
|
#endif
|
|
#ifdef S4CLIPPER
|
|
return t4->expr->type ;
|
|
#endif
|
|
#ifdef S4NDX
|
|
return t4->header.type ;
|
|
#endif
|
|
#ifdef S4MDX
|
|
return t4->header.type ;
|
|
#endif
|
|
}
|
|
|
|
#ifdef N4OTHER
|
|
|
|
B4BLOCK *tfile4block( TAG4FILE *t4 )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E91642 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
#ifdef E4ANALYZE
|
|
if ( t4->blocks.lastNode == 0 )
|
|
{
|
|
error4( 0, e4struct, E91642 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
return (B4BLOCK *)t4->blocks.lastNode ;
|
|
}
|
|
|
|
#ifdef S4CLIPPER
|
|
int tfile4rlBottom( TAG4FILE *t4 )
|
|
#else
|
|
int tfile4bottom( TAG4FILE *t4 )
|
|
#endif
|
|
{
|
|
int rc ;
|
|
B4BLOCK *blockOn ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return -1 ;
|
|
|
|
do
|
|
{
|
|
rc = tfile4upToRoot( t4 ) ;
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
|
|
if ( rc != 2 )
|
|
{
|
|
b4goEof( tfile4block( t4 ) ) ;
|
|
do
|
|
{
|
|
rc = tfile4down( t4 ) ;
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
b4goEof( tfile4block( t4 ) ) ;
|
|
} while ( rc == 0 ) ;
|
|
}
|
|
|
|
if ( rc == 2 ) /* failed due to read while locked */
|
|
tfile4outOfDate( t4 ) ;
|
|
} while ( rc == 2 ) ;
|
|
|
|
blockOn = tfile4block(t4) ;
|
|
if ( blockOn->keyOn > 0 )
|
|
blockOn->keyOn = blockOn->nKeys-1 ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( blockOn->keyOn < 0 )
|
|
return error4( t4->codeBase, e4info, E91642 ) ;
|
|
#endif
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4CLIPPER
|
|
int tfile4bottom( TAG4FILE *t4 )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( t4->header.descending ) /* if descending, go bottom means go top */
|
|
return tfile4rlTop( t4 ) ;
|
|
else
|
|
return tfile4rlBottom( t4 ) ;
|
|
}
|
|
#endif
|
|
|
|
#ifdef S4CLIPPER
|
|
#ifdef S4HAS_DESCENDING
|
|
void tfile4descending( TAG4FILE *tag, const unsigned short int setting )
|
|
{
|
|
tag->header.descending = setting ;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/* Returns 1 - Cannot move down; 0 - Success; -1 Error */
|
|
int tfile4down( TAG4FILE *t4 )
|
|
{
|
|
long blockDown ;
|
|
B4BLOCK *blockOn, *popBlock, *newBlock, *parent ;
|
|
int rc ;
|
|
#ifdef S4BYTE_SWAP
|
|
char *swapPtr ;
|
|
int i ;
|
|
short shortVal ;
|
|
long longVal ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
|
|
if ( blockOn == 0 ) /* Read the root block */
|
|
{
|
|
if ( t4->header.root <= 0L )
|
|
{
|
|
#ifdef S4NDX
|
|
if ( file4readAll( &t4->file, t4->header.headerOffset, &t4->header.root, 2*sizeof(long)) < 0 )
|
|
return -1 ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
if ( file4readAll( &t4->file, t4->header.headerOffset + 2*sizeof(short), &t4->header.root, 2*sizeof(long)) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.root = x4reverseLong( (void *)&t4->header.root ) ;
|
|
t4->header.eof = x4reverseLong( (void *)&t4->header.eof ) ;
|
|
#endif
|
|
}
|
|
blockDown = t4->header.root ;
|
|
}
|
|
else
|
|
{
|
|
if ( b4leaf( blockOn ) )
|
|
return 1 ;
|
|
blockDown = b4key( blockOn, blockOn->keyOn )->pointer ;
|
|
#ifdef E4ANALYZE
|
|
if ( blockDown <= 0L )
|
|
error4( t4->codeBase, e4info, E81602 ) ;
|
|
#endif
|
|
}
|
|
|
|
/* Get memory for the new block */
|
|
popBlock = (B4BLOCK *)l4pop( &t4->saved ) ;
|
|
newBlock = popBlock ;
|
|
if ( newBlock == 0 )
|
|
newBlock = b4alloc( t4, blockDown ) ;
|
|
if ( newBlock == 0 )
|
|
return -1 ;
|
|
parent = (B4BLOCK *)l4last( &t4->blocks ) ;
|
|
l4add( &t4->blocks, newBlock ) ;
|
|
|
|
#ifdef S4NDX
|
|
if ( popBlock == 0 || newBlock->fileBlock != blockDown )
|
|
#else
|
|
if ( popBlock == 0 || newBlock->fileBlock*I4MULTIPLY != blockDown )
|
|
#endif
|
|
{
|
|
#ifndef S4OFF_WRITE
|
|
if ( newBlock->changed == 1 )
|
|
if ( b4flush(newBlock) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
|
|
rc = i4readBlock( &t4->file, blockDown, parent, newBlock ) ;
|
|
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
|
|
if ( rc == 1 )
|
|
{
|
|
l4remove( &t4->blocks, newBlock ) ;
|
|
l4add( &t4->saved, newBlock ) ;
|
|
return 2 ;
|
|
}
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
#ifdef S4NDX
|
|
swapPtr = (void *)&newBlock->nKeys ;
|
|
|
|
shortVal = x4reverseShort( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
|
|
|
|
swapPtr += 2 + sizeof(short) ;
|
|
|
|
for ( i = 0 ; i < (*(short *)swap) ; i++ )
|
|
{
|
|
longVal = x4reverseLong( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &longVal, sizeof(long) ) ;
|
|
longVal = x4reverseLong( (void *)(swapPtr+sizeof(long)) ) ;
|
|
memcpy( swapPtr+sizeof(long), (void *) &longVal, sizeof(long) ) ;
|
|
swapPtr += r4->groupLen ;
|
|
}
|
|
|
|
longVal = x4reverseLong( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &longVal, sizeof(long) ) ;
|
|
#endif
|
|
|
|
#ifdef S4CLIPPER
|
|
swapPtr = (void *)&newBlock->nKeys ;
|
|
|
|
shortVal = x4reverseShort( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
|
|
|
|
swapPtr += 2 ;
|
|
/* swap the short pointers to B4KEY_DATA */
|
|
for ( i = 0 ; i <= t4->header.keysMax ; i++ )
|
|
{
|
|
shortVal = x4reverseShort( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
|
|
swapPtr += sizeof(short) ;
|
|
}
|
|
/* swap the B4KEY_DATA's */
|
|
for ( i = 0 ; i < t4->header.keysMax ; i++ )
|
|
{
|
|
longVal = x4reverseLong( (void *)swapPtr ) ;
|
|
memcpy( swapPtr, (void *) &longVal, sizeof(long) ) ;
|
|
longVal = x4reverseLong( (void *)(swapPtr+sizeof(long)) ) ;
|
|
memcpy( swapPtr+sizeof(long), (void *) &longVal, sizeof(long) ) ;
|
|
swapPtr += t4->header.groupLen ;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
for ( ;; )
|
|
{
|
|
blockOn = (B4BLOCK *)l4pop( &t4->saved ) ;
|
|
if ( blockOn == 0 )
|
|
break ;
|
|
#ifndef S4OFF_WRITE
|
|
if ( b4flush(blockOn) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
b4free( blockOn ) ;
|
|
}
|
|
}
|
|
|
|
newBlock->keyOn = 0 ;
|
|
return 0 ;
|
|
}
|
|
|
|
int tfile4eof( TAG4FILE *t4 )
|
|
{
|
|
B4BLOCK *b4 ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
b4 = tfile4block( t4 ) ;
|
|
return ( b4->keyOn >= b4->nKeys ) ;
|
|
}
|
|
|
|
#ifndef S4OFF_WRITE
|
|
int tfile4flush( TAG4FILE *t4 )
|
|
{
|
|
int rc ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E94901 ) ;
|
|
#endif
|
|
|
|
rc = tfile4update( t4 ) ;
|
|
#ifndef S4OPTIMIZE_OFF
|
|
if ( rc )
|
|
rc = file4flush( &t4->file ) ;
|
|
#endif
|
|
return rc ;
|
|
}
|
|
#endif
|
|
|
|
int tfile4freeAll( TAG4FILE *t4 )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
while ( tfile4up( t4 ) == 0 ) ;
|
|
return tfile4freeSaved( t4 ) ;
|
|
}
|
|
|
|
int tfile4freeSaved( TAG4FILE *t4 )
|
|
{
|
|
B4BLOCK *blockOn ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
#ifndef S4OFF_WRITE
|
|
if ( tfile4update( t4 ) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
|
|
for ( ;; )
|
|
{
|
|
blockOn = (B4BLOCK *)l4pop( &t4->saved ) ;
|
|
if ( blockOn == 0 )
|
|
return 0 ;
|
|
#ifndef S4OFF_WRITE
|
|
if ( b4flush( blockOn ) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
b4free( blockOn ) ;
|
|
}
|
|
}
|
|
|
|
B4KEY_DATA *tfile4keyData( TAG4FILE *t4 )
|
|
{
|
|
B4BLOCK *b4 ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E91642 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
b4 = (B4BLOCK *)t4->blocks.lastNode ;
|
|
return b4key( b4, b4->keyOn ) ;
|
|
}
|
|
|
|
long tfile4recNo( TAG4FILE *t4 )
|
|
{
|
|
B4BLOCK *blockOn ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return (long)error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
if ( blockOn == 0 )
|
|
return -2L ;
|
|
#ifdef S4NDX
|
|
if ( !b4leaf( blockOn ) )
|
|
return -2L ;
|
|
#else
|
|
if ( blockOn->keyOn >= blockOn->nKeys )
|
|
return -1 ;
|
|
#endif
|
|
|
|
return b4recNo( blockOn, blockOn->keyOn ) ;
|
|
}
|
|
|
|
int tfile4seek( TAG4FILE *t4, const void *ptr, const int lenPtrIn )
|
|
{
|
|
int rc, lenPtr ;
|
|
B4BLOCK *blockOn ;
|
|
#ifdef S4CLIPPER
|
|
int upperFnd, upperAft, incPos, dSet ;
|
|
unsigned char *cPtr ;
|
|
dSet = 0 ;
|
|
cPtr = (unsigned char *)ptr ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 || ptr == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
#ifdef E4ANALYZE
|
|
#ifndef S4CLIPPER
|
|
/* clipper stores all keys as strings, so length-mismatches are
|
|
ok */
|
|
if ( lenPtrIn != t4->header.keyLen && tfile4type( t4 ) != r4str )
|
|
return error4( t4->codeBase, e4struct, E91642 ) ;
|
|
#endif
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
lenPtr = lenPtrIn ;
|
|
|
|
if ( lenPtr > t4->header.keyLen )
|
|
lenPtr = t4->header.keyLen ;
|
|
|
|
#ifdef S4CLIPPER
|
|
if ( t4->header.descending ) /* look for current item less one: */
|
|
{
|
|
for( incPos = lenPtr-1 ; dSet == 0 && incPos >=0 ; incPos-- )
|
|
if ( cPtr[incPos] != 0xFF )
|
|
{
|
|
cPtr[incPos]++ ;
|
|
dSet = 1 ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
rc = 3 ;
|
|
for(;;) /* Repeat until found */
|
|
{
|
|
while ( rc >= 2 )
|
|
{
|
|
if ( rc == 2 )
|
|
tfile4outOfDate( t4 ) ;
|
|
rc = tfile4upToRoot( t4 ) ;
|
|
#ifdef S4CLIPPER
|
|
upperFnd = 0 ;
|
|
upperAft = 0 ;
|
|
#endif
|
|
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
}
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
#ifdef E4ANALYZE
|
|
if ( blockOn == 0 )
|
|
return error4( t4->codeBase, e4info, E91642 ) ;
|
|
#endif
|
|
|
|
rc = b4seek( blockOn, (char *)ptr, lenPtr ) ;
|
|
#ifdef S4NDX
|
|
if ( b4leaf( blockOn ) )
|
|
break ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
if ( b4leaf( blockOn ) )
|
|
{
|
|
if ( rc == r4after && upperAft && blockOn->keyOn >= blockOn->nKeys )
|
|
while( upperAft-- > 1 )
|
|
tfile4up( t4 ) ;
|
|
if ( rc == 0 || !upperFnd )
|
|
break ;
|
|
|
|
while( upperFnd-- > 1 )
|
|
tfile4up( t4 ) ;
|
|
rc = 0 ;
|
|
break ;
|
|
}
|
|
if ( rc == 0 )
|
|
{
|
|
upperFnd = 1 ;
|
|
upperAft = 0 ;
|
|
}
|
|
else
|
|
if ( rc == r4after && !upperFnd && !( blockOn->keyOn >= blockOn->nKeys ) )
|
|
upperAft = 1 ;
|
|
#endif
|
|
#endif
|
|
|
|
rc = tfile4down( t4 ) ;
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
|
|
#ifdef S4CLIPPER
|
|
if ( upperFnd )
|
|
upperFnd++ ;
|
|
if ( upperAft )
|
|
upperAft++ ;
|
|
#endif
|
|
}
|
|
#ifdef S4CLIPPER
|
|
if ( t4->header.descending ) /* must go back one! */
|
|
{
|
|
cPtr[incPos+1]-- ; /* reset the search_ptr ; */
|
|
if ( dSet )
|
|
{
|
|
rc = (int)tfile4skip( t4, -1L ) ;
|
|
if ( rc == 0L ) /* bof = eof condition */
|
|
{
|
|
b4goEof( blockOn ) ;
|
|
rc = r4eof ;
|
|
}
|
|
else
|
|
{
|
|
if ( (u4memcmp)( b4keyKey( tfile4block( t4 ), tfile4block( t4 )->keyOn ), ptr, lenPtr ) )
|
|
rc = r4after ;
|
|
else
|
|
rc = 0 ; /* successful find */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( rc == 0 ) /* the item was found, so go top, */
|
|
tfile4top( t4 ) ;
|
|
else /* otherwise want an eof type condition */
|
|
{
|
|
b4goEof( blockOn ) ;
|
|
rc = r4eof ;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return rc ;
|
|
}
|
|
|
|
long tfile4skip( TAG4FILE *t4, long numSkip )
|
|
{
|
|
int rc, sign, seekSpecial ;
|
|
B4BLOCK *blockOn ;
|
|
|
|
#ifdef S4NDX
|
|
long numLeft = numSkip ;
|
|
#endif
|
|
#ifdef S4CLIPPER
|
|
long j ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return (long)error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( numSkip < 0)
|
|
sign = -1 ;
|
|
else
|
|
sign = 1 ;
|
|
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
if ( blockOn == 0 )
|
|
{
|
|
rc = tfile4top( t4 ) ;
|
|
if ( rc < 0 )
|
|
return -numSkip ;
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
}
|
|
|
|
#ifdef S4NDX
|
|
#ifdef E4ANALYZE
|
|
if ( !b4leaf( blockOn ) )
|
|
return (long)error4( t4->codeBase, e4info, E91642 ) ;
|
|
#endif
|
|
|
|
for(;;)
|
|
{
|
|
/* save the current key in case skip fails */
|
|
memcpy( t4->codeBase->savedKey, b4keyKey( blockOn, blockOn->keyOn ), t4->header.keyLen ) ;
|
|
|
|
while ( (rc = tfile4down(t4)) == 0 )
|
|
if ( sign < 0 )
|
|
{
|
|
blockOn = tfile4block(t4) ;
|
|
b4goEof( blockOn ) ;
|
|
if ( b4leaf(blockOn) )
|
|
{
|
|
blockOn->keyOn-- ;
|
|
#ifdef E4ANALYZE
|
|
if ( blockOn->keyOn < 0 )
|
|
return (long)error4( t4->codeBase, e4info, E91642 ) ;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( rc < 0 )
|
|
return -numSkip ;
|
|
|
|
if ( rc == 2 ) /* failed on i/o, seek current spot to make valid */
|
|
{
|
|
tfile4outOfDate( t4 ) ;
|
|
rc = tfile4seek( t4, t4->codeBase->savedKey, t4->header.keyLen ) ;
|
|
if ( rc < 0 )
|
|
return -numSkip ;
|
|
if ( rc == r4after ) /* means skipped 1 ahead */
|
|
numLeft-- ;
|
|
continue ;
|
|
}
|
|
|
|
blockOn = tfile4block( t4 ) ;
|
|
|
|
if ( rc < 0 ) /* Error */
|
|
return( -numSkip ) ;
|
|
|
|
numLeft -= b4skip( blockOn, numLeft ) ;
|
|
if ( numLeft == 0 ) /* Success */
|
|
return( numSkip ) ;
|
|
|
|
do /* Skip 1 to the next leaf block */
|
|
{
|
|
#ifdef E4ANALYZE
|
|
if ( t4->blocks.lastNode == 0 )
|
|
return (long)error4( t4->codeBase, e4result, E91642 ) ;
|
|
#endif
|
|
if ( l4prev( &t4->blocks, t4->blocks.lastNode ) == 0 ) /* root block */
|
|
{
|
|
if ( numSkip > 0 )
|
|
{
|
|
if ( tfile4bottom( t4 ) < 0 )
|
|
return -numSkip ;
|
|
}
|
|
else
|
|
if ( tfile4top( t4 ) < 0 )
|
|
return -numSkip ;
|
|
|
|
return( numSkip - numLeft ) ;
|
|
}
|
|
tfile4up( t4 ) ;
|
|
blockOn = (B4BLOCK *)t4->blocks.lastNode ;
|
|
} while ( b4skip( blockOn, (long) sign) != sign) ;
|
|
numLeft -= sign ;
|
|
}
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
for( j = numSkip; j != 0; j -= sign ) /* skip 1 * numSkip */
|
|
{
|
|
if ( b4leaf(blockOn) )
|
|
{
|
|
if ( b4skip( blockOn, (long) sign) != sign ) /* go up */
|
|
{
|
|
int go_on = 1 ;
|
|
while ( go_on )
|
|
{
|
|
if ( l4prev( &t4->blocks, t4->blocks.lastNode ) == 0 ) /* root block */
|
|
{
|
|
if ( numSkip > 0 && t4->header.descending == 0 ||
|
|
numSkip <= 0 && t4->header.descending == 1 )
|
|
/* if ( numSkip > 0 )*/
|
|
{
|
|
if ( tfile4bottom( t4 ) < 0 )
|
|
return -numSkip ;
|
|
}
|
|
else
|
|
if ( tfile4top( t4 ) < 0 )
|
|
return -numSkip ;
|
|
|
|
return ( numSkip - j ) ;
|
|
}
|
|
|
|
rc = tfile4up( t4 ) ;
|
|
blockOn = tfile4block( t4 ) ;
|
|
if ( rc != 0 ) return -1 ;
|
|
|
|
if ( sign > 0 ) /* forward skipping */
|
|
{
|
|
if ( !( blockOn->keyOn >= blockOn->nKeys ) )
|
|
go_on = 0 ;
|
|
}
|
|
else /* backward skipping */
|
|
{
|
|
if ( ! (blockOn->keyOn == 0) )
|
|
{
|
|
b4skip( blockOn, -1L ) ;
|
|
go_on = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( sign > 0 )
|
|
b4skip( blockOn, 1L ) ;
|
|
|
|
/* save the current key in case skip fails */
|
|
if ( blockOn->keyOn >= blockOn->nKeys ) /* case where no proper key to copy exists */
|
|
{
|
|
if ( blockOn->nKeys == 0 ) /* invalid, so must discard this block */
|
|
{
|
|
/* codeBase can't recover from this gracefully, so just go back up saying
|
|
that couldn't skip */
|
|
return 0 ;
|
|
}
|
|
|
|
/* not on a true key, so instead just go to the old position, and then try the skip again (unless r4after)*/
|
|
memcpy( t4->codeBase->savedKey, b4keyKey( blockOn, blockOn->keyOn - 1 ), t4->header.keyLen ) ;
|
|
seekSpecial = 1 ;
|
|
}
|
|
else
|
|
{
|
|
memcpy( t4->codeBase->savedKey, b4keyKey( blockOn, blockOn->keyOn ), t4->header.keyLen ) ;
|
|
seekSpecial = 0 ;
|
|
}
|
|
|
|
while ( (rc = tfile4down( t4 ) ) == 0 )
|
|
{
|
|
if ( sign < 0 )
|
|
{
|
|
blockOn = tfile4block( t4 ) ;
|
|
b4goEof( blockOn ) ;
|
|
if ( b4leaf( blockOn ) )
|
|
blockOn->keyOn-- ;
|
|
}
|
|
}
|
|
if ( rc < 0 )
|
|
return -numSkip ;
|
|
|
|
if ( rc == 2 ) /* failed on i/o, seek current spot to make valid */
|
|
{
|
|
#ifndef S4OPTIMIZE_OFF
|
|
#ifndef S4SINGLE
|
|
file4refresh( &t4->file ) ;
|
|
#endif
|
|
#endif
|
|
rc = tfile4seek( t4, t4->codeBase->savedKey, t4->header.keyLen ) ;
|
|
if ( rc < 0 )
|
|
return -numSkip ;
|
|
if ( rc == r4after ) /* means skipped 1 ahead */
|
|
if ( j != 1 )
|
|
j-- ;
|
|
if ( seekSpecial == 1 ) /* means we are actually on wrong pos, need to skip one */
|
|
j += sign ; /* pre-increment # of skip times */
|
|
}
|
|
|
|
blockOn = tfile4block( t4 ) ;
|
|
}
|
|
}
|
|
return numSkip ;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#ifndef S4OFF_WRITE
|
|
#ifdef S4NDX
|
|
B4BLOCK *tfile4split( TAG4FILE *t4, B4BLOCK *oldBlock )
|
|
{
|
|
long newFileBlock ;
|
|
B4BLOCK *newBlock ;
|
|
int newLen ;
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return 0 ;
|
|
|
|
#ifdef E4INDEX_VERIFY
|
|
if ( b4verify( oldBlock ) == -1 )
|
|
error4describe( oldBlock->tag->codeBase, e4index, E91622, oldBlock->tag->alias, 0, 0 ) ;
|
|
#endif
|
|
|
|
newFileBlock = tfile4extend( t4 ) ;
|
|
newBlock = b4alloc( t4, newFileBlock ) ;
|
|
if ( newBlock == 0 )
|
|
return 0 ;
|
|
|
|
newBlock->changed = 1 ;
|
|
oldBlock->changed = 1 ;
|
|
|
|
/* NNNNOOOO N - New, O - Old */
|
|
newBlock->nKeys = ( oldBlock->nKeys )/2 ;
|
|
oldBlock->nKeys -= newBlock->nKeys ;
|
|
|
|
newLen = newBlock->nKeys * t4->header.groupLen ;
|
|
|
|
c4memmove( b4key(newBlock,0), b4key(oldBlock, oldBlock->nKeys ), newLen+ (sizeof(long)*(!(b4leaf( oldBlock )) ) ) ) ;
|
|
newBlock->keyOn = oldBlock->keyOn - oldBlock->nKeys ;
|
|
|
|
oldBlock->nKeys -= !( b4leaf( oldBlock ) ) ;
|
|
|
|
return newBlock ;
|
|
}
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
/* NTX only needs to do a copy and adjust the index pointers */
|
|
/* if extraOld is true then the extra key is placed in old, otherwise in new */
|
|
B4BLOCK *tfile4split( TAG4FILE *t4, B4BLOCK *oldBlock, const int extraOld )
|
|
{
|
|
long newFileBlock ;
|
|
B4BLOCK *newBlock ;
|
|
int isBranch ;
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return 0 ;
|
|
|
|
#ifdef E4INDEX_VERIFY
|
|
if ( b4verify( oldBlock ) == -1 )
|
|
error4describe( oldBlock->tag->codeBase, e4index, E91642, oldBlock->tag->alias, 0, 0 ) ;
|
|
#endif
|
|
|
|
newFileBlock = tfile4extend( t4 ) ;
|
|
newBlock = b4alloc( t4, newFileBlock ) ;
|
|
if ( newBlock == 0 )
|
|
return 0 ;
|
|
|
|
newBlock->changed = 1 ;
|
|
oldBlock->changed = 1 ;
|
|
|
|
memcpy( newBlock->data, oldBlock->data, B4BLOCK_SIZE - ( t4->header.keysMax + 2 ) * sizeof(short) ) ;
|
|
|
|
if ( extraOld )
|
|
{
|
|
newBlock->nKeys = oldBlock->nKeys / 2 ;
|
|
oldBlock->nKeys -= newBlock->nKeys ;
|
|
}
|
|
else
|
|
{
|
|
newBlock->nKeys = oldBlock->nKeys ;
|
|
oldBlock->nKeys = oldBlock->nKeys / 2 ;
|
|
newBlock->nKeys -= oldBlock->nKeys ;
|
|
if ( oldBlock->nKeys == newBlock->nKeys )
|
|
{
|
|
newBlock->nKeys++ ;
|
|
oldBlock->nKeys-- ;
|
|
}
|
|
}
|
|
|
|
isBranch = !b4leaf( oldBlock ) ;
|
|
|
|
memcpy( newBlock->pointers, &oldBlock->pointers[oldBlock->nKeys + isBranch], newBlock->nKeys * sizeof(short) ) ;
|
|
memcpy( &newBlock->pointers[newBlock->nKeys], oldBlock->pointers, (oldBlock->nKeys + isBranch) * sizeof(short) ) ;
|
|
|
|
if ( isBranch == 0 ) /* leaf blocks need one more copy */
|
|
newBlock->pointers[t4->header.keysMax] = oldBlock->pointers[t4->header.keysMax] ;
|
|
|
|
newBlock->keyOn = oldBlock->keyOn - oldBlock->nKeys - isBranch ;
|
|
newBlock->nKeys -= isBranch ;
|
|
|
|
return newBlock ;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif /* S4OFF_WRITE */
|
|
|
|
#ifdef S4CLIPPER
|
|
int tfile4rlTop( TAG4FILE *t4 )
|
|
#else
|
|
int tfile4top( TAG4FILE *t4 )
|
|
#endif
|
|
{
|
|
int rc ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
do
|
|
{
|
|
rc = tfile4upToRoot( t4 ) ;
|
|
if ( rc < 0 )
|
|
return -1 ;
|
|
|
|
if ( rc != 2 )
|
|
{
|
|
((B4BLOCK *)t4->blocks.lastNode)->keyOn = 0 ;
|
|
do
|
|
{
|
|
if ( (rc = tfile4down(t4)) < 0 )
|
|
return -1 ;
|
|
((B4BLOCK *)t4->blocks.lastNode)->keyOn = 0 ;
|
|
} while ( rc == 0 ) ;
|
|
}
|
|
|
|
if ( rc == 2 ) /* failed due to read while locked */
|
|
tfile4outOfDate( t4 ) ;
|
|
} while ( rc == 2 ) ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4CLIPPER
|
|
int tfile4top( TAG4FILE *t4 )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( t4->header.descending ) /* if descending, go top means go bottom */
|
|
return tfile4rlBottom( t4 ) ;
|
|
else
|
|
return tfile4rlTop( t4 ) ;
|
|
}
|
|
#endif
|
|
|
|
int tfile4up( TAG4FILE *t4 )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( t4->blocks.lastNode == 0 )
|
|
return 1 ;
|
|
l4add( &t4->saved, l4pop(&t4->blocks) ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifndef S4OFF_WRITE
|
|
int tfile4update( TAG4FILE *t4 )
|
|
{
|
|
B4BLOCK *blockOn ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( tfile4updateHeader( t4 ) < 0 )
|
|
return -1 ;
|
|
|
|
for( blockOn = 0 ;; )
|
|
{
|
|
blockOn = (B4BLOCK *)l4next( &t4->saved ,blockOn ) ;
|
|
if ( blockOn == 0 )
|
|
break ;
|
|
if ( b4flush(blockOn) < 0 )
|
|
return -1 ;
|
|
}
|
|
|
|
for( blockOn = 0 ;; )
|
|
{
|
|
blockOn = (B4BLOCK *)l4next( &t4->blocks, blockOn ) ;
|
|
if ( blockOn == 0 )
|
|
break ;
|
|
if ( b4flush( blockOn ) < 0 )
|
|
return -1 ;
|
|
}
|
|
|
|
if ( t4->rootWrite )
|
|
{
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.root = x4reverseLong( (void *)&t4->header.root ) ;
|
|
t4->header.eof = x4reverseLong( (void *)&t4->header.eof ) ;
|
|
#endif
|
|
#ifdef S4NDX
|
|
if ( file4write( &t4->file, t4->headerOffset, &t4->header.root, 2 * sizeof(long) ) < 0 )
|
|
return -1 ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
if ( file4write( &t4->file, t4->headerOffset + 2*sizeof( short ),
|
|
&t4->header.root, 2*sizeof(long) ) < 0 ) return -1 ;
|
|
#endif
|
|
#endif
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.root = x4reverseLong( (void *)&t4->header.root ) ;
|
|
t4->header.eof = x4reverseLong( (void *)&t4->header.eof ) ;
|
|
#endif
|
|
t4->rootWrite = 0 ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
#endif /* S4OFF_WRITE */
|
|
|
|
int tfile4upToRoot( TAG4FILE *t4 )
|
|
{
|
|
LINK4 *linkOn ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
for ( ;; )
|
|
{
|
|
linkOn = (LINK4 *)l4pop( &t4->blocks ) ;
|
|
if ( linkOn == 0 )
|
|
return tfile4down(t4) ;
|
|
l4add( &t4->saved, linkOn ) ;
|
|
}
|
|
}
|
|
|
|
int tfile4close( TAG4FILE *t4, DATA4FILE *d4 )
|
|
{
|
|
CODE4 *c4 ;
|
|
int finalRc ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91638 ) ;
|
|
#endif
|
|
|
|
c4 = t4->codeBase ;
|
|
finalRc = 0 ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( t4->userCount <= 0 )
|
|
return error4( c4, e4struct, E91638 ) ;
|
|
#endif
|
|
|
|
t4->userCount-- ;
|
|
#ifdef S4SERVER
|
|
if ( c4->server->keepOpen != 2 || t4->file.isTemp != 1 )
|
|
#endif
|
|
if ( t4->userCount == 0 )
|
|
{
|
|
if ( tfile4freeAll( t4 ) < 0 )
|
|
finalRc = error4set( c4, 0) ;
|
|
expr4free( t4->expr ) ;
|
|
expr4free( t4->filter ) ;
|
|
mem4release( t4->blockMemory ) ;
|
|
t4->blockMemory = 0 ;
|
|
if ( file4openTest( &t4->file ) )
|
|
{
|
|
if ( c4->doRemove == 1 )
|
|
t4->file.isTemp = 1 ;
|
|
if ( file4close( &t4->file ) < 0 )
|
|
finalRc = error4set( c4, 0 ) ;
|
|
}
|
|
if ( t4->link.n != (LINK4 *)0 )
|
|
l4remove( &d4->tagfiles, t4 ) ;
|
|
mem4free( c4->tagFileMemory, t4 ) ;
|
|
error4set( c4, finalRc ) ;
|
|
}
|
|
|
|
return finalRc ;
|
|
}
|
|
|
|
int S4FUNCTION t4close( TAG4 *t4 )
|
|
{
|
|
int finalRc ;
|
|
DATA4 *d4 ;
|
|
CODE4 *c4 ;
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( t4, 4, E91637 ) )
|
|
return -1 ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91637 ) ;
|
|
#endif
|
|
|
|
if ( l4seek( &t4->index->tags, t4 ) == 1 ) /* i4close removes the tag, so if still there, was not called from i4close() */
|
|
{
|
|
if ( l4numNodes( &t4->index->tags ) == 1 ) /* only the one tag, so remove index */
|
|
return i4close( t4->index ) ;
|
|
else /* must remove from the list manually */
|
|
l4remove( &t4->index->tags, t4 ) ;
|
|
}
|
|
|
|
c4 = t4->tagFile->codeBase ;
|
|
d4 = t4->index->data ;
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( t4->isValid == 1 ) /* if invalid (failed create/open) then allow close */
|
|
if ( code4transEnabled( c4 ) )
|
|
if ( code4trans( c4 )->currentTranStatus == r4active ) /* disallow on current active only */
|
|
return error4( c4, e4transViolation, E81522 ) ;
|
|
#endif
|
|
|
|
finalRc = error4set( c4, 0 ) ;
|
|
|
|
#ifndef S4OFF_WRITE
|
|
#ifndef S4OFF_TRAN
|
|
if ( t4->isValid == 1 ) /* if invalid (failed create/open) then allow close */
|
|
#endif
|
|
if ( d4 )
|
|
if ( d4update( d4 ) < 0 )
|
|
finalRc = error4set( c4, 0 ) ;
|
|
#endif
|
|
|
|
#ifndef S4SINGLE
|
|
if ( tfile4unlock( t4->tagFile, data4serverId( t4->index->data ) ) < 0 )
|
|
finalRc = error4set( c4, 0 ) ;
|
|
#endif
|
|
|
|
if ( tfile4close( t4->tagFile, d4->dataFile ) < 0 )
|
|
finalRc = error4set( c4, 0 ) ;
|
|
mem4free( c4->tagMemory, t4 ) ;
|
|
|
|
error4set( c4, finalRc ) ;
|
|
|
|
return finalRc ;
|
|
}
|
|
|
|
#ifndef S4OFF_WRITE
|
|
long tfile4extend( TAG4FILE *t4 )
|
|
{
|
|
long oldEof ;
|
|
CODE4 *c4 = t4->codeBase ;
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( t4->header.version == t4->header.oldVersion )
|
|
return (long)error4( c4, e4info, E91636 ) ;
|
|
#endif
|
|
|
|
oldEof = t4->header.eof ;
|
|
|
|
#ifdef S4NDX
|
|
#ifdef E4ANALYZE
|
|
if ( oldEof <= 0L )
|
|
return (long)error4( c4, e4info, E91636 ) ;
|
|
#endif
|
|
|
|
t4->header.eof += B4BLOCK_SIZE / I4MULTIPLY ;
|
|
t4->rootWrite = 1 ;
|
|
return oldEof ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
#ifdef S4SINGLE
|
|
if ( oldEof != 0 ) /* case where free-list exists */
|
|
t4->header.eof = 0L ;
|
|
else
|
|
{
|
|
#endif
|
|
oldEof = file4len( &t4->file ) ;
|
|
#ifdef E4ANALYZE
|
|
if ( oldEof <= t4->checkEof )
|
|
return (long)error4( c4, e4info, E91636 ) ;
|
|
t4->checkEof = oldEof ;
|
|
#endif
|
|
file4lenSet( &t4->file, file4len( &t4->file ) + 1024 ) ; /* and extend the file */
|
|
#ifdef S4SINGLE
|
|
}
|
|
#endif
|
|
return oldEof/512 ;
|
|
#endif
|
|
#endif
|
|
}
|
|
#endif /* S4OFF_WRITE */
|
|
|
|
#ifdef P4ARGS_USED
|
|
#pragma argsused
|
|
#endif
|
|
int tfile4go2( TAG4FILE *t4, const unsigned char *ptr, const long recNum, const int goAdd )
|
|
{
|
|
int rc ;
|
|
long rec ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 || ptr == 0 || recNum < 1 )
|
|
return error4( 0, e4parm, E91642 ) ;
|
|
#endif
|
|
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
rc = tfile4seek( t4, ptr, t4->header.keyLen ) ;
|
|
if ( rc )
|
|
return rc ;
|
|
|
|
for(;;)
|
|
{
|
|
rec = tfile4recNo( t4 ) ;
|
|
if (rec == recNum )
|
|
return 0 ;
|
|
|
|
rc = (int)tfile4skip( t4, 1L ) ;
|
|
if ( rc == -1 )
|
|
return -1 ;
|
|
if ( rc == 0 )
|
|
{
|
|
b4goEof( tfile4block( t4 ) ) ;
|
|
return r4found ;
|
|
}
|
|
|
|
if ( (*t4->cmp)( tfile4keyData( t4 )->value, ptr, t4->header.keyLen ) )
|
|
return r4found ;
|
|
}
|
|
}
|
|
|
|
static TAG4FILE *tfile4open( DATA4 *d4, const char *fileName )
|
|
{
|
|
TAG4FILE *tfile ;
|
|
CODE4 *c4 ;
|
|
char buf[258], buffer[1024] ;
|
|
char exprBuf[I4MAX_EXPR_SIZE + 1] ;
|
|
#ifdef S4CLIPPER
|
|
char *ptr, garbage ;
|
|
#endif
|
|
FILE4SEQ_READ seqRead ;
|
|
int rc, len, oldTagNameError ;
|
|
|
|
c4 = d4->codeBase ;
|
|
|
|
u4ncpy( buf, fileName, sizeof( buf ) ) ;
|
|
c4upper(buf) ;
|
|
|
|
#ifdef S4NDX
|
|
#ifdef S4CASE_SEN
|
|
u4nameExt( buf, sizeof(buf), "ndx", 0 ) ;
|
|
#else
|
|
u4nameExt( buf, sizeof(buf), "NDX", 0 ) ;
|
|
#endif
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
#ifdef S4CASE_SEN
|
|
u4nameExt( buf, sizeof(buf), "ntx", 0 ) ;
|
|
#else
|
|
u4nameExt( buf, sizeof(buf), "NTX", 0 ) ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
oldTagNameError = c4->errTagName ;
|
|
c4->errTagName = 0 ;
|
|
tfile = dfile4tag( d4->dataFile, buf ) ;
|
|
c4->errTagName = oldTagNameError ;
|
|
if ( tfile != 0 ) /* because t4open() verifies no duplicates, this must be a duplicate data4 instance */
|
|
{
|
|
/* changed 09/19/95 - test program t4skip.c */
|
|
tfile->userCount++ ;
|
|
return tfile ;
|
|
/* only one instance ever allowed */
|
|
/* error4( c4, e4instance, E94906 ) ;*/
|
|
/* return 0 ; */
|
|
|
|
/*
|
|
#ifndef S4SERVER
|
|
if ( c4->singleOpen != OPEN4SPECIAL ) only one instance allowed...
|
|
{
|
|
error4( c4, e4instance, E94906 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
tfile->userCount++ ;
|
|
return tfile ;
|
|
*/
|
|
}
|
|
|
|
if ( c4->tagFileMemory == 0 )
|
|
{
|
|
c4->tagFileMemory = mem4create( c4, c4->memStartTagFile, sizeof(TAG4FILE), c4->memExpandTagFile, 0 ) ;
|
|
if ( c4->tagFileMemory == 0 )
|
|
return 0 ;
|
|
}
|
|
|
|
tfile = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ;
|
|
if ( tfile == 0 )
|
|
return 0 ;
|
|
|
|
tfile->file.hand = -1 ;
|
|
tfile->codeBase = c4 ;
|
|
tfile->userCount = 1 ;
|
|
if ( tfile->blockMemory == 0 )
|
|
tfile->blockMemory = mem4create( c4, c4->memStartBlock, (sizeof(B4BLOCK)) + B4BLOCK_SIZE -
|
|
(sizeof(B4KEY_DATA)) - (sizeof(short)) - (sizeof(char[2])),
|
|
c4->memExpandBlock, 0 ) ;
|
|
|
|
if ( tfile->blockMemory == 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
rc = file4open( &tfile->file, c4, buf, 1 ) ;
|
|
if ( rc != 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifndef S4OPTIMIZE_OFF
|
|
file4optimizeLow( &tfile->file, c4->optimize, OPT4INDEX, 0, tfile ) ;
|
|
#endif
|
|
|
|
file4seqReadInit( &seqRead, &tfile->file, 0, buffer, 1024 ) ;
|
|
#ifdef S4NDX
|
|
if ( file4seqReadAll( &seqRead, &tfile->header.root, sizeof(I4IND_HEAD_WRITE) ) < 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
tfile->header.root = x4reverseLong( (void *)&tfile->header.root ) ;
|
|
tfile->header.eof = x4reverseLong( (void *)&tfile->header.eof ) ;
|
|
tfile->header.keyLen = x4reverseShort( (void *)&tfile->header.keyLen ) ;
|
|
tfile->header.keysMax = x4reverseShort( (void *)&tfile->header.keysMax ) ;
|
|
tfile->header.int_or_date = x4reverseShort( (void *)&tfile->header.int_or_date ) ;
|
|
tfile->header.groupLen = x4reverseShort( (void *)&tfile->header.groupLen ) ;
|
|
tfile->header.dummy = x4reverseShort( (void *)&tfile->header.dummy ) ;
|
|
tfile->header.unique = x4reverseShort( (void *)&tfile->header.unique ) ;
|
|
#endif
|
|
t4->header.type = 0 ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
if ( file4seqReadAll( &seqRead, &tfile->header.sign, sizeof(I4IND_HEAD_WRITE) ) < 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
#ifdef S4BYTE_SWAP
|
|
tfile->header.sign = x4reverseShort( (void *)&tfile->header.sign ) ;
|
|
tfile->header.version = x4reverseShort( (void *)&tfile->header.version ) ;
|
|
tfile->header.root = x4reverseLong( (void *)&tfile->header.root ) ;
|
|
tfile->header.eof = x4reverseLong( (void *)&tfile->header.eof ) ;
|
|
tfile->header.groupLen = x4reverseShort( (void *)&tfile->header.groupLen ) ;
|
|
tfile->header.keyLen = x4reverseShort( (void *)&tfile->header.keyLen ) ;
|
|
tfile->header.keyDec = x4reverseShort( (void *)&tfile->header.keyDec ) ;
|
|
tfile->header.keysMax = x4reverseShort( (void *)&tfile->header.keysMax ) ;
|
|
tfile->header.keysHalf = x4reverseShort( (void *)&tfile->header.keysHalf ) ;
|
|
#endif
|
|
#endif
|
|
tfile->header.headerOffset = 0 ;
|
|
|
|
/* Perform some checks */
|
|
if ( tfile->header.keyLen > I4MAX_KEY_SIZE || tfile->header.keyLen <= 0 ||
|
|
#ifdef S4CLIPPER
|
|
tfile->header.keysMax != 2* tfile->header.keysHalf || tfile->header.keysHalf <= 0 ||
|
|
tfile->header.groupLen != tfile->header.keyLen+ 8 ||
|
|
(tfile->header.sign != 0x6 && tfile->header.sign != 0x106 ) )
|
|
#else
|
|
tfile->header.keyLen+8 > tfile->header.groupLen ||
|
|
tfile->header.keysMax < 4 || tfile->header.keysMax > 50 ||
|
|
tfile->header.eof <= 0L )
|
|
#endif
|
|
{
|
|
error4describe( c4, e4index, E84904, buf, 0, 0 ) ;
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
tfile->cmp = (S4CMP_FUNCTION *)u4memcmp ;
|
|
tfile->header.root = -1 ;
|
|
tfile->header.oldVersion = tfile->header.version ;
|
|
|
|
u4namePiece( tfile->alias, sizeof( tfile->alias ), fileName, 0, 0 ) ;
|
|
#ifndef S4CASE_SEN
|
|
c4upper( tfile->alias ) ;
|
|
#endif
|
|
|
|
file4seqReadAll( &seqRead, exprBuf, sizeof( exprBuf ) - 1 ) ;
|
|
c4trimN( exprBuf, sizeof( exprBuf ) ) ;
|
|
tfile->expr = expr4parseLow( d4, exprBuf, tfile ) ;
|
|
if ( tfile->expr == 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
#ifdef S4CLIPPER
|
|
tfile->expr->keyLen = tfile->header.keyLen ;
|
|
tfile->expr->keyDec = tfile->header.keyDec ;
|
|
#endif
|
|
|
|
if ( expr4context( tfile->expr, d4 ) < 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
len = expr4keyLen( tfile->expr ) ;
|
|
if ( len < 0 )
|
|
{
|
|
error4describe( c4, e4info, 84906, exprBuf, 0, 0 ) ;
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4NDX
|
|
tfile->header.type = (char) expr4type(tfile->expr) ;
|
|
if ( t4->header.keyLen != (short) len )
|
|
{
|
|
error4describe( c4, e4index, E84905, i4->file.name, 0 ) ;
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
file4seqReadAll( &seqRead, &tfile->header.unique, sizeof( tfile->header.unique ) ) ;
|
|
file4seqReadAll( &seqRead, &garbage, sizeof( garbage ) ) ;
|
|
file4seqReadAll( &seqRead, &tfile->header.descending, sizeof( tfile->header.descending ) ) ;
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.unique = x4reverseShort( (void *)&tfile->header.unique ) ;
|
|
t4->header.descending = x4reverseShort( (void *)&tfile->header.descending ) ;
|
|
#endif
|
|
file4seqReadAll( &seqRead, exprBuf, sizeof( exprBuf ) - 1 ) ;
|
|
c4trimN( exprBuf, sizeof( exprBuf ) ) ;
|
|
if ( exprBuf[0] != 0 )
|
|
{
|
|
tfile->filter = expr4parseLow( d4, exprBuf, tfile ) ;
|
|
if ( tfile->filter != 0 )
|
|
{
|
|
if ( expr4context( tfile->filter, d4 ) < 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
len = expr4key( tfile->filter, &ptr ) ;
|
|
if ( len < 0 )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
if ( expr4type( tfile->filter ) != 'L' )
|
|
{
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
/* if( tfile->header.unique )
|
|
tfile->uniqueError = c4->errDefaultUnique ;
|
|
*/
|
|
l4add( &d4->dataFile->tagfiles, tfile ) ; /* add the tag to its index list */
|
|
|
|
#ifdef S4NDX
|
|
tfile4initSeekConv( tfile, tfile->header.type) ;
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
tfile4initSeekConv( tfile, (char)expr4type( tfile->expr ) ) ;
|
|
#endif
|
|
#endif
|
|
|
|
if ( tfile->blockMemory == 0 )
|
|
tfile->blockMemory = mem4create( c4, c4->memStartBlock, (sizeof(B4BLOCK)) + B4BLOCK_SIZE -
|
|
(sizeof(B4KEY_DATA)) - (sizeof(short)) - (sizeof(char[2])), c4->memExpandBlock, 0 ) ;
|
|
|
|
if ( tfile->blockMemory == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94906 ) ;
|
|
#endif
|
|
tfile4close( tfile, d4->dataFile ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
if ( d4->dataFile->indexLocked == 1 ) /* index locked, so lock this tag as well */
|
|
tfile4lock( tfile, data4serverId( d4 ) ) ;
|
|
return tfile ;
|
|
}
|
|
|
|
#ifdef P4ARGS_USED
|
|
#pragma argsused
|
|
#endif
|
|
TAG4 *S4FUNCTION t4openLow( DATA4 *d4, INDEX4 *i4ndx, const char *fileName, const char *dummy )
|
|
{
|
|
CODE4 *c4 ;
|
|
INDEX4 *i4 ;
|
|
TAG4 *t4 ;
|
|
int oldTagErr ;
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( d4, 2, E94903 ) )
|
|
return 0 ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 || fileName == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E94903 ) ;
|
|
return 0 ; ;
|
|
}
|
|
#endif
|
|
|
|
c4 = d4->codeBase ;
|
|
if ( error4code( c4 ) < 0 )
|
|
return 0 ;
|
|
|
|
oldTagErr = c4->errTagName ;
|
|
c4->errTagName = 0 ;
|
|
if ( d4tag( d4, fileName ) )
|
|
{
|
|
error4describe( c4, e4instance, E85308, fileName, 0, 0 ) ;
|
|
c4->errTagName = oldTagErr ;
|
|
return 0 ;
|
|
}
|
|
c4->errTagName = oldTagErr ;
|
|
error4set( c4, 0 ) ;
|
|
|
|
if ( i4ndx == 0 ) /* must create an index for the tag */
|
|
{
|
|
if ( c4->indexMemory == 0 )
|
|
{
|
|
c4->indexMemory = mem4create( c4, c4->memStartIndex, sizeof( INDEX4 ), c4->memExpandIndex, 0 ) ;
|
|
if ( c4->indexMemory == 0 )
|
|
return 0 ;
|
|
}
|
|
|
|
i4 = (INDEX4 *)mem4alloc( c4->indexMemory ) ;
|
|
if ( i4 == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94903 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
i4->codeBase = c4 = d4->codeBase ;
|
|
/* 09/22/95 AS - changed last parm to 0 for t4group (c/s access name needs extension if provided) */
|
|
u4namePiece( i4->accessName, sizeof( i4->accessName ), fileName, 0, 1 ) ;
|
|
}
|
|
else
|
|
i4 = i4ndx ;
|
|
|
|
if ( c4->tagMemory == 0 )
|
|
{
|
|
c4->tagMemory = mem4create( c4, c4->memStartTag, sizeof(TAG4), c4->memExpandTag, 0 ) ;
|
|
if ( c4->tagMemory == 0 )
|
|
{
|
|
if ( i4ndx == 0 )
|
|
mem4free( c4->indexMemory, i4 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
t4 = (TAG4 *)mem4alloc( c4->tagMemory ) ;
|
|
if ( t4 == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94903 ) ;
|
|
#endif
|
|
if ( i4ndx == 0 )
|
|
mem4free( c4->indexMemory, i4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
t4->tagFile = tfile4open( d4, fileName ) ;
|
|
if ( t4->tagFile == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94903 ) ;
|
|
#endif
|
|
mem4free( c4->tagMemory, t4 ) ;
|
|
if ( i4ndx == 0 )
|
|
mem4free( c4->indexMemory, i4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
if ( t4->tagFile->header.unique )
|
|
t4->errUnique = c4->errDefaultUnique ;
|
|
t4->index = i4 ;
|
|
if ( i4ndx == 0 )
|
|
{
|
|
i4->data = d4 ;
|
|
l4add( &d4->indexes, i4 ) ;
|
|
}
|
|
|
|
l4add( &t4->index->tags, t4 ) ;
|
|
#ifndef S4OFF_TRAN
|
|
t4->isValid = 1 ;
|
|
#endif
|
|
return t4 ;
|
|
}
|
|
|
|
#ifndef S4OFF_WRITE
|
|
#ifdef S4CLIPPER
|
|
#ifdef P4ARGS_USED
|
|
#pragma argsused
|
|
#endif
|
|
int tfile4shrink( TAG4FILE *t4, long blockNo )
|
|
{
|
|
#ifdef S4SINGLE
|
|
t4->header.eof = blockNo * 512 ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
#endif /* S4CLIPPER */
|
|
|
|
int tfile4updateHeader( TAG4FILE *t4 )
|
|
{
|
|
T4HEADER *header ;
|
|
FILE4 *file ;
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
I4IND_HEAD_WRITE swap ;
|
|
#endif
|
|
if ( error4code( t4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
header = &t4->header ;
|
|
file = &t4->file ;
|
|
/* header->version = header->oldVersion + 2 ; */
|
|
|
|
if ( header->oldVersion != header->version )
|
|
{
|
|
#ifdef S4NDX
|
|
#ifdef S4BYTE_SWAP
|
|
swap.root = x4reverseLong( (void *)&header->root ) ;
|
|
swap.eof = x4reverseLong( (void *)&header->eof ) ;
|
|
swap.keyLen = x4reverseShort( (void *)&header->keyLen ) ;
|
|
swap.keysMax = x4reverseShort( (void *)&header->keysMax ) ;
|
|
swap.int_or_date = x4reverseShort( (void *)&header->int_or_date ) ;
|
|
swap.groupLen = x4reverseShort( (void *)&header->groupLen ) ;
|
|
swap.dummy = x4reverseShort( (void *)&header->dummy ) ;
|
|
swap.unique = x4reverseShort( (void *)&header->unique ) ;
|
|
|
|
if ( file4write( file, 0L, &swap, sizeof(I4IND_HEAD_WRITE)) < 0 )
|
|
return -1 ;
|
|
|
|
header->version = x4reverseLong( (void *)&header->version ) ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE, &header->version, sizeof(header->version)) < 0 )
|
|
return -1 ;
|
|
header->version = x4reverseLong( (void *)&header->version ) ;
|
|
#else
|
|
if ( file4write( file, 0L, &header->root, sizeof(I4IND_HEAD_WRITE) ) < 0 )
|
|
return -1 ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE, &header->version, sizeof(header->version)) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
#ifdef S4BYTE_SWAP
|
|
swap.sign = x4reverseShort( (void *)&header->sign ) ;
|
|
swap.version = x4reverseShort( (void *)&header->version ) ;
|
|
swap.root = x4reverseLong( (void *)&header->root ) ;
|
|
swap.eof = x4reverseLong( (void *)&header->eof ) ;
|
|
swap.groupLen = x4reverseShort( (void *)&header->groupLen ) ;
|
|
swap.keyLen = x4reverseShort( (void *)&header->keyLen ) ;
|
|
swap.keyDec = x4reverseShort( (void *)&header->keyDec ) ;
|
|
swap.keysMax = x4reverseShort( (void *)&header->keysMax ) ;
|
|
swap.keysHalf = x4reverseShort( (void *)&header->keysHalf ) ;
|
|
|
|
if ( file4write( file, 0L, &swap, 2 * sizeof( long ) + 2 * sizeof( short ) ) < 0)
|
|
return -1 ;
|
|
|
|
header->unique = x4reverseShort( (void *)&header->unique ) ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE, &header->unique, sizeof(header->unique)) < 0 )
|
|
return -1 ;
|
|
header->unique = x4reverseShort( (void *)&header->unique ) ;
|
|
|
|
header->descending = x4reverseShort( (void *)&header->descending ) ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE + sizeof(header->unique) + 1, &header->descending, sizeof(header->descending)) < 0 )
|
|
return -1 ;
|
|
header->descending = x4reverseShort( (void *)&header->descending ) ;
|
|
#else
|
|
if ( file4write( file, 0L, &header->sign, 2 * sizeof( long ) + 2 * sizeof( short ) ) < 0 )
|
|
return -1 ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE, &header->unique, sizeof(header->unique)) < 0 )
|
|
return -1 ;
|
|
if ( file4write( file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE + sizeof(header->unique) + 1, &header->descending, sizeof(header->descending)) < 0 )
|
|
return -1 ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
header->oldVersion = header->version ;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* S4OFF_WRITE */
|
|
|
|
int tfile4goEof( TAG4FILE *t4 )
|
|
{
|
|
int rc ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91642 ) ;
|
|
#endif
|
|
|
|
rc = tfile4bottom( t4 ) ;
|
|
if ( rc != 0 )
|
|
return rc ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( tfile4block( t4 ) == 0 )
|
|
return error4( 0, e4info, E91642 ) ;
|
|
#endif
|
|
|
|
tfile4block(t4)->keyOn++ ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
int tfile4doVersionCheck( TAG4FILE *t4, int doSeek, int updateVersion )
|
|
{
|
|
#ifndef S4SINGLE
|
|
int rc, needSeek ;
|
|
B4BLOCK *b4 ;
|
|
CODE4 *c4 ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( t4 == 0 )
|
|
return error4( 0, e4parm_null, E91635 ) ;
|
|
#endif
|
|
|
|
c4 = t4->codeBase ;
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( tfile4lockTest( t4 ) )
|
|
return 0 ;
|
|
|
|
#ifndef S4OPTIMIZE_OFF
|
|
/* make sure read from disk */
|
|
if ( t4->file.doBuffer )
|
|
c4->opt.forceCurrent = 1 ;
|
|
#endif
|
|
|
|
#ifdef S4NDX
|
|
rc = file4readAll( &t4->file, sizeof(I4IND_HEAD_WRITE) + I4MAX_EXPR_SIZE,
|
|
&t4->header.version, sizeof(t4->header.version ) ) ;
|
|
#ifndef S4OPTIMIZE_OFF
|
|
if ( t4->file.doBuffer )
|
|
c4->opt.forceCurrent = 0 ;
|
|
#endif
|
|
if ( rc < 0 )
|
|
return rc ;
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.version = x4reverseLong( (void *)&t4->header.version ) ;
|
|
#endif
|
|
#else
|
|
rc = file4readAll( &t4->file, 0L, &t4->header.sign , 2 * sizeof( short ) + 2 * sizeof( long ) ) ;
|
|
#ifndef S4OPTIMIZE_OFF
|
|
if ( t4->file.doBuffer )
|
|
c4->opt.forceCurrent = 0 ;
|
|
#endif
|
|
if ( rc < 0 )
|
|
return rc ;
|
|
#ifdef S4BYTE_SWAP
|
|
t4->header.sign = x4reverseShort( (void *)&t4->header.sign ) ;
|
|
t4->header.version = x4reverseShort( (void *)&t4->header.version ) ;
|
|
t4->header.root = x4reverseLong( (void *)&t4->header.root ) ;
|
|
t4->header.eof = x4reverseLong( (void *)&t4->header.eof ) ;
|
|
t4->header.groupLen = x4reverseShort( (void *)&t4->header.groupLen ) ;
|
|
t4->header.keyLen = x4reverseShort( (void *)&t4->header.keyLen ) ;
|
|
t4->header.keyDec = x4reverseShort( (void *)&t4->header.keyDec ) ;
|
|
t4->header.keysMax = x4reverseShort( (void *)&t4->header.keysMax ) ;
|
|
t4->header.keysHalf = x4reverseShort( (void *)&t4->header.keysHalf ) ;
|
|
#endif
|
|
#endif
|
|
|
|
if ( t4->header.version == t4->header.oldVersion )
|
|
return 0 ;
|
|
|
|
if ( updateVersion == 1 )
|
|
t4->header.oldVersion = t4->header.version ;
|
|
else
|
|
t4->header.version = t4->header.oldVersion ;
|
|
|
|
/* remember the old position */
|
|
needSeek = 0 ;
|
|
if ( doSeek )
|
|
{
|
|
b4 = (B4BLOCK *)t4->blocks.lastNode ; /* can't use tfile4block( t4 ) since might be null */
|
|
if ( b4 != 0 )
|
|
{
|
|
if ( tfile4eof( t4 ) )
|
|
needSeek = 2 ;
|
|
else
|
|
/* if ( b4leaf( b4 ) && b4->nKeys != 0 )
|
|
changed line 04/09/96 AS --> if on a branch, and no seek is performed, a gpf or general
|
|
error can later occur (in d4seek) --> this should be ok for S4CLIPPER */
|
|
if ( b4->nKeys != 0 )
|
|
{
|
|
memcpy( c4->savedKey, b4key( b4, b4->keyOn ), t4->header.keyLen + 2 * sizeof( long ) ) ;
|
|
needSeek = 1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( tfile4freeAll( t4 ) < 0 ) /* Should be a memory operation only */
|
|
#ifdef E4ANALYZE
|
|
return error4( c4, e4result, E91635 ) ;
|
|
#else
|
|
return e4result ;
|
|
#endif
|
|
|
|
switch( needSeek )
|
|
{
|
|
case 1:
|
|
#ifdef E4ANALYZE_ALL
|
|
if ( tfile4go( t4, ((B4KEY_DATA *)c4->savedKey)->value, ((B4KEY_DATA *)c4->savedKey)->num, 0 ) != 0 )
|
|
return error4( c4, e4index, E91635 ) ;
|
|
#else
|
|
tfile4go( t4, ((B4KEY_DATA *)c4->savedKey)->value, ((B4KEY_DATA *)c4->savedKey)->num, 0 ) ;
|
|
#endif
|
|
break ;
|
|
case 2:
|
|
tfile4goEof( t4 ) ;
|
|
break ;
|
|
}
|
|
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int tfile4versionCheck( TAG4FILE *t4, const int doSeek, const int updateVersion )
|
|
{
|
|
#ifndef S4OPTIMIZE_OFF
|
|
if ( t4->file.doBuffer == 0 )
|
|
#endif
|
|
#ifndef S4SINGLE
|
|
if ( tfile4lockTest( t4 ) == 0 )
|
|
#endif
|
|
return tfile4doVersionCheck( t4, doSeek, updateVersion ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#endif /* N4OTHER */
|
|
#endif /* S4INDEX_OFF */
|
|
|
|
#ifdef S4VB_DOS
|
|
#ifdef N4OTHER
|
|
|
|
TAG4 *S4FUNCTION tfile4open_v(DATA4 *d4, char *name)
|
|
{
|
|
return tfile4open( d4, 0, c4str(name) ) ;
|
|
}
|
|
|
|
#endif /* N4OTHER */
|
|
#endif /* S4VB_DOS */
|
|
#endif /* S4CLIENT */
|