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 */
 |