1035 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1035 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* i4addtag.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */
 | |
| 
 | |
| #include "d4all.h"
 | |
| #ifndef S4UNIX
 | |
|    #ifdef __TURBOC__
 | |
|       #pragma hdrstop
 | |
|    #endif
 | |
| #endif
 | |
| 
 | |
| #ifndef S4CLIENT
 | |
| #ifndef S4INDEX_OFF
 | |
| 
 | |
| #ifndef S4OFF_WRITE
 | |
| 
 | |
| #ifdef S4NDX
 | |
| int i4getLastKey( TAG4FILE *t4, char *keyData, long forBlock )
 | |
| {
 | |
|    int rc = 0 ;
 | |
|    B4BLOCK *tempBlock ;
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( forBlock <= 0 || t4 == 0 || keyData == 0 )
 | |
|          return error4( 0, e4parm, E95401 ) ;
 | |
|    #endif
 | |
| 
 | |
|    /* must get block forBlock, then find the last key */
 | |
|    tempBlock = b4alloc( t4, forBlock ) ;
 | |
|    if ( tempBlock == 0 )
 | |
|       return -1 ;
 | |
| 
 | |
|    if ( file4readAll( &t4->file, I4MULTIPLY * forBlock, &tempBlock->nKeys, B4BLOCK_SIZE ) < 0 )
 | |
|       return -1 ;
 | |
| 
 | |
|    b4goEof( tempBlock ) ;
 | |
|    if ( b4leaf( tempBlock ) )
 | |
|       rc = 2 ;
 | |
|    else
 | |
|       rc = b4getLastKey( tempBlock, keyData ) ;
 | |
| 
 | |
|    b4free( tempBlock ) ;
 | |
| 
 | |
|    return rc ;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifndef N4OTHER
 | |
| 
 | |
| #ifdef S4FOX
 | |
| /* (temporary) fix for FoxPro multi-user compatibility
 | |
|    swaps parent and right blocks */
 | |
| #ifndef S4OFF_MULTI
 | |
| static long tfile4swap( B4BLOCK *parent, B4BLOCK *left )
 | |
| {
 | |
|    long tempFb ;
 | |
|    #ifdef S4BYTE_SWAP
 | |
|       S4LONG longVal ;
 | |
|    #endif
 | |
| 
 | |
|    tempFb = left->fileBlock ;
 | |
|    left->fileBlock = parent->fileBlock ;
 | |
|    parent->fileBlock = tempFb ;
 | |
| 
 | |
|    /* now update neighbours */
 | |
|    if ( left->header.rightNode != -1 )
 | |
|    {
 | |
|       #ifdef S4BYTE_SWAP
 | |
|          longVal = x4reverseLong( (void *)&left->fileBlock ) ;
 | |
|          file4write( &parent->tag->indexFile->file, left->header.rightNode + 2*sizeof(short),
 | |
|                      &longVal, sizeof( left->header.leftNode ) ) ;
 | |
|       #else
 | |
|          file4write( &parent->tag->indexFile->file, left->header.rightNode + 2*sizeof(short),
 | |
|                      &left->fileBlock, sizeof( left->header.leftNode ) ) ;
 | |
|       #endif
 | |
|    }
 | |
| 
 | |
|    if ( left->header.leftNode != -1 )
 | |
|    {
 | |
|       #ifdef S4BYTE_SWAP
 | |
|          longVal = x4reverseLong( (void *)&left->fileBlock ) ;
 | |
|          file4write( &parent->tag->indexFile->file, left->header.leftNode + 2*sizeof(short),
 | |
|                      &longVal, sizeof( left->header.rightNode ) ) ;
 | |
|       #else
 | |
|          file4write( &parent->tag->indexFile->file, left->header.leftNode + 2*sizeof(short),
 | |
|                      &left->fileBlock, sizeof( left->header.rightNode ) ) ;
 | |
|       #endif
 | |
|    }
 | |
| 
 | |
|    if ( parent->header.rightNode != -1 )
 | |
|    {
 | |
|       #ifdef S4BYTE_SWAP
 | |
|          longVal = x4reverseLong( (void *)&parent->fileBlock ) ;
 | |
|          file4write( &parent->tag->indexFile->file, parent->header.rightNode + 2*sizeof(short),
 | |
|                      &longVal, sizeof( parent->header.leftNode ) ) ;
 | |
|       #else
 | |
|          file4write( &parent->tag->indexFile->file, parent->header.rightNode + 2*sizeof(short),
 | |
|                      &parent->fileBlock, sizeof( parent->header.leftNode ) ) ;
 | |
|       #endif
 | |
|    }
 | |
| 
 | |
|    if ( parent->header.leftNode != -1 )
 | |
|    {
 | |
|       #ifdef S4BYTE_SWAP
 | |
|          longVal = x4reverseLong( (void *)&parent->fileBlock ) ;
 | |
|          file4write( &parent->tag->indexFile->file, parent->header.leftNode + 2*sizeof(short),
 | |
|                      &longVal, sizeof( parent->header.rightNode ) ) ;
 | |
|       #else
 | |
|          file4write( &parent->tag->indexFile->file, parent->header.leftNode + 2*sizeof(short),
 | |
|                      &parent->fileBlock, sizeof( parent->header.rightNode ) ) ;
 | |
|       #endif
 | |
|    }
 | |
| 
 | |
|    return left->fileBlock ;
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| /* errUnique must be 0 if the tag is not unique, otherwise must contain unique error */
 | |
| static int tfile4addDo( TAG4FILE *t4, const unsigned char *keyInfo, const long recIn, short int errUnique )
 | |
| {
 | |
|    CODE4 *c4 ;
 | |
|    INDEX4FILE *i4 ;
 | |
|    B4BLOCK *oldBlock, *rootBlock, *newBlock ;
 | |
|    int rc ;
 | |
|    long  oldFileBlock, extendBlock, rec ;
 | |
|    #ifdef S4FOX
 | |
|       int  keyOn, didAdd ;
 | |
|       long rec1 = 0L ;
 | |
|       long rec2 = 0L ;
 | |
|       const unsigned char *tempKey = 0 ;
 | |
|       int doInsert, updateReqd ;
 | |
|    #else
 | |
|       int isBranch ;
 | |
|    #endif
 | |
| 
 | |
|    rec = recIn ;
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( t4 == 0 )
 | |
|          return error4( 0, e4parm_null, E95402 ) ;
 | |
|       if ( keyInfo == 0 || rec < 1 )
 | |
|          return error4( t4->codeBase, e4parm_null, E95402 ) ;
 | |
|    #endif
 | |
| 
 | |
|    c4 = t4->codeBase ;
 | |
|    i4 = t4->indexFile ;
 | |
|    if ( error4code( c4 ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    #ifdef S4FOX
 | |
|       if ( t4->expr != 0 )
 | |
|          switch( errUnique )  /* ensure not a null add if r4/e4 candidate */
 | |
|          {
 | |
|             case r4candidate:
 | |
|                if ( expr4nullLow( t4->expr, 1 ) == 1 )
 | |
|                   return r4unique ;
 | |
|                break ;
 | |
|             case e4candidate:
 | |
|                if ( expr4nullLow( t4->expr, 1 ) == 1 )
 | |
|                   return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
 | |
|                break ;
 | |
|             default:
 | |
|                break ;
 | |
|          }
 | |
| 
 | |
|       rc = tfile4go( t4, keyInfo, rec, 1 ) ;
 | |
|    #else
 | |
|       rc = tfile4seek( t4, keyInfo, t4->header.keyLen ) ;
 | |
|    #endif
 | |
|    if ( rc < 0 )
 | |
|       return error4stack( c4, rc, E95402 ) ;
 | |
| 
 | |
|    #ifdef S4FOX
 | |
|       if ( rc == 0 )
 | |
|       {
 | |
|          switch( errUnique )
 | |
|          {
 | |
|             case e4unique:
 | |
|             case e4candidate:
 | |
|                return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
 | |
|             case r4candidate :
 | |
|                return r4unique ;
 | |
|             default:
 | |
|                break ;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       if ( errUnique && rc == r4found )
 | |
|    #else
 | |
|       if ( errUnique && rc == 0 )
 | |
|    #endif
 | |
|       {
 | |
|          switch ( errUnique )
 | |
|          {
 | |
|             #ifdef S4FOX
 | |
|                case e4candidate:
 | |
|             #endif
 | |
|             case e4unique:
 | |
|                return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
 | |
|             #ifdef S4FOX
 | |
|                case r4candidate:
 | |
|             #endif
 | |
|             case r4unique:
 | |
|                return r4unique ;
 | |
|             case r4uniqueContinue:
 | |
|                return r4uniqueContinue ;
 | |
|             default:
 | |
|                break ;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|    if ( t4->filter && !t4->hasKeys )
 | |
|    {
 | |
|       file4write(&t4->indexFile->file, t4->headerOffset+sizeof(t4->header)+222, (char *) "\0", (int) 1 ) ;
 | |
|       t4->hasKeys = (char)1 ;
 | |
|       #ifdef S4MDX
 | |
|          t4->hadKeys = (char)0 ;
 | |
|       #endif
 | |
|    }
 | |
| 
 | |
|    oldBlock = tfile4block( t4 ) ;
 | |
|    oldFileBlock = 0 ;
 | |
| 
 | |
|    #ifdef S4FOX
 | |
|       doInsert = 1 ;
 | |
|       updateReqd = 0 ;
 | |
|       didAdd = 1 ;
 | |
| 
 | |
|       for( ;; )
 | |
|       {
 | |
|          if ( doInsert == 1 )
 | |
|          {
 | |
|             i4->tagIndex->header.version = i4->versionOld + 1 ;
 | |
|             if ( oldBlock == 0 )
 | |
|             {
 | |
|                /* Must create a new root block */
 | |
|                extendBlock = index4extend( i4 ) ;
 | |
|                if ( extendBlock < 0 )
 | |
|                   return (int)extendBlock ;
 | |
| 
 | |
|                rootBlock = b4alloc( t4, extendBlock) ;
 | |
|                if ( rootBlock == 0 )
 | |
|                   return -1 ;
 | |
| 
 | |
|                rootBlock->header.leftNode = -1 ;
 | |
|                rootBlock->header.rightNode = -1 ;
 | |
|                rootBlock->header.nodeAttribute = 1 ;
 | |
| 
 | |
|                l4add( &t4->blocks, rootBlock ) ;
 | |
| 
 | |
|                #ifndef S4OFF_MULTI
 | |
|                   if ( t4->indexFile->file.lowAccessMode != OPEN4DENY_RW )
 | |
|                   {
 | |
|                      oldFileBlock = tfile4swap( rootBlock, (B4BLOCK *)l4last( &t4->saved ) ) ;
 | |
|                      if ( oldFileBlock < 0 )
 | |
|                         return -1 ;
 | |
|                   }
 | |
| 
 | |
|                #endif
 | |
| 
 | |
|                b4top( rootBlock ) ;
 | |
|                b4insert( rootBlock, tempKey, rec, rec2, 1 ) ;
 | |
|                b4insert( rootBlock, keyInfo, oldFileBlock, rec1, 1 ) ;
 | |
|                t4->header.root = rootBlock->fileBlock ;
 | |
|                t4->rootWrite = 1 ;
 | |
|                if ( didAdd == 0 )
 | |
|                   return 1 ;
 | |
|                return 0 ;
 | |
|             }
 | |
| 
 | |
|             if ( (rc = b4insert( oldBlock, keyInfo, rec, rec1, 0 )) != 1 )
 | |
|             {
 | |
|                if ( rc == 0 )
 | |
|                {
 | |
|                   if ( b4leaf( oldBlock ) )
 | |
|                   {
 | |
|                      tempKey = keyInfo ;
 | |
|                      rec2 = rec ;
 | |
|                   }
 | |
|                   if ( oldBlock->keyOn == oldBlock->header.nKeys - 1 )
 | |
|                      updateReqd = 1 ;
 | |
|                   doInsert = 0 ;
 | |
|                   continue ;
 | |
|                }
 | |
|                else
 | |
|                   return rc ;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                l4pop( &t4->blocks ) ;
 | |
|                keyOn = oldBlock->keyOn ;
 | |
| 
 | |
|                /* The new block's end key gets added to the block just up */
 | |
|                newBlock= tfile4split( t4, oldBlock ) ;
 | |
|                if ( newBlock == 0 )
 | |
|                   return -1 ;
 | |
| 
 | |
|                l4add( &t4->saved, oldBlock ) ;
 | |
| 
 | |
|                if ( keyOn < oldBlock->header.nKeys )
 | |
|                {
 | |
|                   b4go( oldBlock, (long)keyOn ) ;
 | |
|                   rc = b4insert( oldBlock, keyInfo, rec, rec1, 0 ) ;
 | |
|                }
 | |
|                else
 | |
|                {
 | |
|                   b4go( newBlock, (long)(keyOn - oldBlock->header.nKeys) ) ;
 | |
|                   rc = b4insert( newBlock, keyInfo, rec, rec1, 0 ) ;
 | |
|                   if ( rc == 0 )  /* if there was room to insert and on the key, need to change the upper block entry */
 | |
|                      if ( newBlock->keyOn == newBlock->header.nKeys - 1 )
 | |
|                         updateReqd = 1 ;
 | |
|                }
 | |
| 
 | |
|                if ( rc == 1 )  /* was not possible to insert the key */
 | |
|                   didAdd = 0 ;
 | |
| 
 | |
|                #ifdef E4INDEX_VERIFY
 | |
|                   rc = b4verify( oldBlock ) ;
 | |
|                   if ( rc < 0 )
 | |
|                      return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|                   rc = b4verify( newBlock ) ;
 | |
|                   if ( rc < 0 )
 | |
|                      return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|                #endif
 | |
| 
 | |
|                /* Now add to the block just up */
 | |
|                b4goEof( oldBlock ) ;
 | |
|                oldBlock->keyOn-- ;
 | |
| 
 | |
|                keyInfo = b4keyKey( oldBlock, oldBlock->keyOn ) ;
 | |
|                oldFileBlock = oldBlock->fileBlock ;
 | |
|                rec1 = b4recNo( oldBlock, oldBlock->keyOn ) ;
 | |
| 
 | |
|                rec = newBlock->fileBlock ;
 | |
|                rc = b4flush(newBlock) ;
 | |
|                if ( rc < 0 )
 | |
|                   return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
| 
 | |
|                b4goEof( newBlock ) ;
 | |
|                newBlock->keyOn-- ;
 | |
| 
 | |
|                tempKey = (unsigned char *)c4->savedKey ;
 | |
|                memcpy( (void *)tempKey, (void *)b4keyKey( newBlock, newBlock->keyOn ), (unsigned int)t4->header.keyLen ) ;
 | |
|                rec2 = b4recNo( newBlock, newBlock->keyOn ) ;
 | |
|                if( newBlock->keyOn == newBlock->header.nKeys - 1 )
 | |
|                   updateReqd = 1 ;
 | |
|                b4free( newBlock ) ;
 | |
|             }
 | |
|          }
 | |
|          else
 | |
|             l4add( &t4->saved, l4pop( &t4->blocks ) ) ;
 | |
| 
 | |
|          oldBlock = (B4BLOCK *)t4->blocks.lastNode ;
 | |
| 
 | |
|          if ( oldBlock == 0 )
 | |
|          {
 | |
|             if ( doInsert == 0 )
 | |
|             {
 | |
|                if ( didAdd == 0 )
 | |
|                   return 1 ;
 | |
|                return 0 ;
 | |
|             }
 | |
|          }
 | |
|          else
 | |
|             if ( updateReqd )  /* may have to update a parent block */
 | |
|             {
 | |
|                if ( b4brReplace( oldBlock, tempKey, rec2 ) < 0 )
 | |
|                   return -1 ;
 | |
|                if ( oldBlock->keyOn != oldBlock->header.nKeys - 1 )  /* done reqd updates */
 | |
|                   updateReqd = 0 ;
 | |
|             }
 | |
|       }
 | |
|    #else              /* if not S4FOX  */
 | |
|       i4->changed = 1 ;
 | |
|       t4->changed = 1 ;
 | |
|       t4->header.version++ ;
 | |
| 
 | |
|       for(;;)
 | |
|       {
 | |
|          if ( oldBlock == 0 )
 | |
|          {
 | |
|             /* Must create a new root block */
 | |
|             extendBlock = index4extend(i4) ;
 | |
|             if ( extendBlock < 0 )
 | |
|                return (int) extendBlock ;
 | |
| 
 | |
|             rootBlock = b4alloc( t4, extendBlock) ;
 | |
|             if ( rootBlock == 0 )
 | |
|                return -1 ;
 | |
| 
 | |
|             l4add( &t4->blocks, rootBlock ) ;
 | |
| 
 | |
|             b4insert( rootBlock, keyInfo, oldFileBlock ) ;
 | |
|             b4insert( rootBlock, keyInfo, rec ) ;
 | |
|             rootBlock->nKeys-- ;
 | |
|             t4->header.root = rootBlock->fileBlock ;
 | |
|             t4->rootWrite  = 1 ;
 | |
|             return 0 ;
 | |
|          }
 | |
| 
 | |
|          if ( oldBlock->nKeys < oldBlock->tag->header.keysMax )
 | |
|          {
 | |
|             b4insert( oldBlock, keyInfo, rec ) ;
 | |
|             return 0 ;
 | |
|          }
 | |
| 
 | |
|          l4pop( &t4->blocks ) ;
 | |
| 
 | |
|          isBranch  = b4leaf( oldBlock )  ?  0 : 1 ;
 | |
| 
 | |
|          /* NNNNOOOO  N - New, O - Old */
 | |
|          /* The new block's end key gets added to the block just up */
 | |
|          newBlock= tfile4split( t4, oldBlock ) ;
 | |
|          if ( newBlock == 0 )
 | |
|             return -1 ;
 | |
| 
 | |
|          l4add( &t4->saved, newBlock ) ;
 | |
| 
 | |
|          newBlock->nKeys -= (short)isBranch ;
 | |
|          if ( newBlock->keyOn < (newBlock->nKeys+isBranch) )
 | |
|             b4insert( newBlock, keyInfo, rec ) ;
 | |
|          else
 | |
|             b4insert( oldBlock, keyInfo, rec ) ;
 | |
| 
 | |
|          #ifdef E4INDEX_VERIFY
 | |
|             rc = b4verify( oldBlock ) ;
 | |
|             if ( rc < 0 )
 | |
|                return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|             rc = b4verify( newBlock ) ;
 | |
|             if ( rc < 0 )
 | |
|                return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|          #endif
 | |
| 
 | |
|          /* Now add to the block just up */
 | |
|          newBlock->keyOn = b4lastpos(newBlock) ;
 | |
| 
 | |
|          keyInfo = b4keyKey( newBlock, newBlock->keyOn ) ;
 | |
|          rec = newBlock->fileBlock ;
 | |
| 
 | |
|          oldFileBlock = oldBlock->fileBlock ;
 | |
|          if ( b4flush(oldBlock) < 0 )
 | |
|             return -1 ;
 | |
| 
 | |
|          b4free( oldBlock ) ;
 | |
|          oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
 | |
|       }
 | |
|    #endif
 | |
| }
 | |
| 
 | |
| int tfile4add( TAG4FILE *t4, const unsigned char *keyInfo, const long recIn, short int errUnique )
 | |
| {
 | |
|    #ifdef S4FOX
 | |
|       int rc ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef S4FOX
 | |
|       /* in fox case the tfile4add might not actually add the key */
 | |
|       for( ;; )
 | |
|       {
 | |
|          rc = tfile4addDo( t4, keyInfo, recIn, errUnique ) ;
 | |
|          if ( rc != 1 )
 | |
|             return rc ;
 | |
|       }
 | |
|    #else
 | |
|       return tfile4addDo( t4, keyInfo, recIn, errUnique ) ;
 | |
|    #endif
 | |
| }
 | |
| 
 | |
| int t4addCalc( TAG4 *t4, long rec )
 | |
| {
 | |
|    int len ;
 | |
|    unsigned char *ptr ;
 | |
|    TAG4FILE *tfile ;
 | |
|    #ifndef S4OFF_TRAN
 | |
|       TAG4KEY_REMOVED *removed ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( t4 == 0 || rec < 1 )
 | |
|          return error4( 0, e4parm, E95403 ) ;
 | |
|    #endif
 | |
| 
 | |
|    tfile = t4->tagFile ;
 | |
| 
 | |
|    if ( error4code( tfile->codeBase ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    if ( tfile->filter )
 | |
|       if ( !expr4true( tfile->filter ) )
 | |
|          return 0;
 | |
| 
 | |
|    len = tfile4exprKey( tfile, (unsigned char **)&ptr ) ;
 | |
|    if ( len < 0 )
 | |
|       return error4stack( tfile->codeBase, len, E95403 ) ;
 | |
| 
 | |
|    #ifdef E4ANALYZE
 | |
|       if ( len != tfile->header.keyLen )
 | |
|          return error4describe( tfile->codeBase, e4index, E95403, tfile4alias( tfile ), 0, 0 ) ;
 | |
|    #endif
 | |
| 
 | |
|    #ifndef S4OFF_TRAN
 | |
|       if ( code4tranStatus( tfile->codeBase ) == r4active && ( t4unique( t4 ) == r4unique ||
 | |
|            t4unique( t4 ) == e4unique
 | |
|            #ifdef S4FOX
 | |
|               || t4unique( t4 ) == r4candidate
 | |
|            #endif
 | |
|            ) )  /* just remove from the removed list */
 | |
|       {
 | |
|          removed = t4keyFind( t4, rec,(char *)ptr ) ;
 | |
|          /* if found it means it is already there, so just remove from list */
 | |
|          if ( removed != 0 )
 | |
|          {
 | |
|             l4remove( &t4->removedKeys, removed ) ;
 | |
|             u4free( removed ) ;
 | |
|             return 0 ;
 | |
|          }
 | |
|          removed = t4keyFind( t4, 0L, (char *)ptr ) ;
 | |
|          if ( removed != 0 )
 | |
|          {
 | |
|             if ( tfile4remove( tfile, removed->key, removed->recno ) < 0 )
 | |
|                return -1 ;
 | |
|             l4remove( &t4->removedKeys, removed ) ;
 | |
|             u4free( removed ) ;
 | |
|          }
 | |
|       }
 | |
|    #endif
 | |
|    return tfile4add( tfile, (unsigned char *)ptr, rec, t4unique( t4 ) ) ;
 | |
| }
 | |
| 
 | |
| #endif  /*  ifndef N4OTHER  */
 | |
| 
 | |
| 
 | |
| #ifdef N4OTHER
 | |
| 
 | |
| #ifdef S4NDX
 | |
| int tfile4add( TAG4FILE *t4, unsigned char *keyInfo, long rec, short int errUnique )
 | |
| {
 | |
|    CODE4 *c4 ;
 | |
|    INDEX4 *i4 ;
 | |
|    B4BLOCK *oldBlock, *rootBlock, *newBlock, *wchBlock ;
 | |
|    int rc, isBranch ;
 | |
|    long  oldFileBlock, extendBlock ;
 | |
|    char keyData[I4MAX_KEY_SIZE+1] ;    /* temporary storage for the key data (max size 100) */
 | |
|    char key2data[I4MAX_KEY_SIZE+1] ;
 | |
|    B4KEY_DATA *atNew ;
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( t4 == 0 )
 | |
|          return error4( 0, e4parm_null, E95402 ) ;
 | |
|       if ( keyInfo == 0 || rec < 1 )
 | |
|          return error4( t4->codeBase, e4parm_null, E95402 ) ;
 | |
|    #endif
 | |
| 
 | |
|    c4 = t4->codeBase ;
 | |
|    i4 = t4->index ;
 | |
| 
 | |
|    if ( error4code( c4 ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    rc = tfile4go( t4, (char *)keyInfo, rec, 1 ) ;
 | |
|    if ( rc < 0 )
 | |
|       return error4stack( c4, rc, E95402 ) ;
 | |
| 
 | |
|    if ( rc == 0 && t4unique( t4 ) == e4unique )
 | |
|       return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
 | |
| 
 | |
|    if ( rc == r4found || rc == 0 )
 | |
|    {
 | |
|       switch ( t4unique( t4 ) )
 | |
|       {
 | |
|          case e4unique:
 | |
|             return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
 | |
|          case r4unique:
 | |
|             return r4unique ;
 | |
|          case r4uniqueContinue:
 | |
|             return r4uniqueContinue ;
 | |
|          default:
 | |
|             break ;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    oldBlock = tfile4block( t4 ) ;
 | |
|    oldFileBlock = 0 ;
 | |
| 
 | |
|    t4->header.version = t4->header.oldVersion + 1 ;
 | |
| 
 | |
|    for(;;)
 | |
|    {
 | |
|       if ( oldBlock == 0 )
 | |
|       {
 | |
|          /* Must create a new root block */
 | |
|          extendBlock = tfile4extend( t4 ) ;
 | |
|          if ( extendBlock < 0 )
 | |
|             return (int)extendBlock ;
 | |
| 
 | |
|          rootBlock = b4alloc( t4, extendBlock ) ;
 | |
|          if ( rootBlock == 0 )
 | |
|             return -1 ;
 | |
| 
 | |
|          l4add( &t4->blocks, rootBlock ) ;
 | |
| 
 | |
|          i4getLastKey( t4, keyData, oldFileBlock ) ;
 | |
| 
 | |
|          b4insert( rootBlock, keyData, 0L, oldFileBlock ) ;
 | |
|          b4append( rootBlock, rec ) ;
 | |
|          t4->header.root = rootBlock->fileBlock ;
 | |
|          t4->rootWrite  = 1 ;
 | |
|          return 0 ;
 | |
|       }
 | |
| 
 | |
|       if ( b4room( oldBlock ) )
 | |
|       {
 | |
|          if ( b4leaf( oldBlock ) )
 | |
|             b4insert( oldBlock, keyInfo, rec, 0L ) ;
 | |
|          else
 | |
|          {
 | |
|             b4getLastKey( oldBlock, keyData ) ;
 | |
|             if ( oldBlock->keyOn >= oldBlock->nKeys  )  /*insert at end done different */
 | |
|             {
 | |
|                b4insert( oldBlock, keyData, 0L, oldFileBlock ) ;
 | |
|                b4append( oldBlock, rec ) ;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                atNew = b4key( oldBlock, oldBlock->keyOn ) ;
 | |
|                atNew->pointer = rec ;
 | |
|                b4insert( oldBlock, keyData, 0L, oldFileBlock ) ;
 | |
|             }
 | |
|          }
 | |
|          return 0 ;
 | |
|       }
 | |
| 
 | |
|       l4pop( &t4->blocks ) ;
 | |
|       isBranch  = b4leaf( oldBlock )  ?  0 : 1 ;
 | |
| 
 | |
|       /* NNNNOOOO  N - New, O - Old */
 | |
|       /* The new block's end key gets added to the block just up */
 | |
|       newBlock= tfile4split( t4, oldBlock ) ;
 | |
|       if ( newBlock == 0 )
 | |
|          return -1 ;
 | |
| 
 | |
|       l4add( &t4->saved, newBlock ) ;
 | |
| 
 | |
|       /* which block should do the insertion ? */
 | |
|       if ( oldBlock->keyOn < (oldBlock->nKeys + isBranch) )
 | |
|          wchBlock = oldBlock ;
 | |
|       else wchBlock = newBlock ;
 | |
| 
 | |
|       if ( b4leaf( wchBlock ) )
 | |
|          b4insert( wchBlock, keyInfo, rec, 0L ) ;
 | |
|       else
 | |
|       {
 | |
|          b4getLastKey( wchBlock, keyData ) ;
 | |
|          if ( wchBlock->keyOn >= wchBlock->nKeys )  /* insert at end done different */
 | |
|          {
 | |
|             b4insert( wchBlock, keyData, 0L, oldFileBlock ) ;
 | |
|             b4append( wchBlock, rec ) ;
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|                atNew = b4key( wchBlock, wchBlock->keyOn ) ;
 | |
|                atNew->pointer = rec ;
 | |
|                b4insert( wchBlock, keyData, 0L, oldFileBlock ) ;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       #ifdef E4INDEX_VERIFY
 | |
|          rc = b4verify( oldBlock ) ;
 | |
|          if ( rc < 0 )
 | |
|             return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|          rc = b4verify( newBlock ) ;
 | |
|          if ( rc < 0 )
 | |
|             return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|       #endif
 | |
| 
 | |
|       /* Now add to the block just up */
 | |
|       newBlock->keyOn = b4lastpos(newBlock) ;
 | |
| 
 | |
|       keyInfo = b4keyKey( newBlock, newBlock->keyOn ) ;
 | |
|       rec = newBlock->fileBlock ;
 | |
| 
 | |
|       if( !b4leaf( newBlock ) )
 | |
|          if ( b4getLastKey( newBlock, key2data ) != 4)
 | |
|             keyInfo = (unsigned char *)key2data ;
 | |
| 
 | |
|       oldBlock->keyOn = b4lastpos( oldBlock ) ;
 | |
|       memcpy( keyData, b4keyKey( oldBlock, oldBlock->keyOn ), t4->header.keyLen ) ;
 | |
| 
 | |
|       oldFileBlock = oldBlock->fileBlock ;
 | |
|       if ( b4flush( oldBlock ) < 0 )
 | |
|          return -1 ;
 | |
|       b4free( oldBlock ) ;
 | |
|       oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
 | |
|    }
 | |
| }
 | |
| #else
 | |
| #ifdef S4CLIPPER
 | |
| int tfile4add( TAG4FILE *t4, unsigned char *keyInfo, const long recNum, short int errUnique )
 | |
| {
 | |
|    CODE4 *c4 ;
 | |
|    B4BLOCK *oldBlock, *rootBlock, *newBlock, *wchBlock ;
 | |
|    int rc ;
 | |
|    long  oldFileBlock, extendBlock, newFileBlock, rec ;
 | |
|    B4KEY_DATA *atNew ;
 | |
|    unsigned char oldKeyPtr[ I4MAX_KEY_SIZE ] ;
 | |
|    unsigned char keyData[I4MAX_KEY_SIZE+1] ;    /* temporary storage for the key data (max size 100) */
 | |
|    unsigned short int oldDesc ;
 | |
|    #ifndef S4OFF_MULTI
 | |
|       int dSet, incPos ;
 | |
|       #ifdef E4ANALYZE_ALL
 | |
|          long findVal ;
 | |
|          int trc ;
 | |
|       #endif
 | |
|    #endif
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( t4 == 0 )
 | |
|          return error4( 0, e4parm_null, E95402 ) ;
 | |
|       if ( keyInfo == 0 || recNum < 1 )
 | |
|          return error4( t4->codeBase, e4parm_null, E95402 ) ;
 | |
|    #endif
 | |
| 
 | |
|    rec = recNum ;
 | |
|    c4 = t4->codeBase ;
 | |
|    if ( error4code( c4 ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    oldDesc = t4->header.descending ;
 | |
|    tfile4descending( t4, 0 ) ;
 | |
| 
 | |
|    rc = tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) ;
 | |
| 
 | |
|    #ifndef S4OFF_MULTI
 | |
|       /* for run-time multi-user compatibility with Clipper, must perform
 | |
|          the insertion at the end of the list of keys.  This is slower than
 | |
|          CodeBase's insertion at the beginning (i.e. S4OFF_MULTI is defined) */
 | |
|       if ( rc == 0 && errUnique == 0 )
 | |
|       {
 | |
|          for( dSet = 0, incPos = t4->header.keyLen - 1 ; dSet == 0 && incPos >=0 ; incPos-- )
 | |
|             if ( keyInfo[incPos] != 0xFF )
 | |
|             {
 | |
|                keyInfo[incPos]++ ;
 | |
|                dSet = 1 ;
 | |
|                if ( tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) < 0 )
 | |
|                   return -1 ;
 | |
|                keyInfo[incPos]-- ;
 | |
|                #ifdef E4ANALYZE_ALL
 | |
|                   findVal = tfile4recNo( t4 ) ;
 | |
|                #endif
 | |
|             }
 | |
|          #ifdef E4ANALYZE_ALL
 | |
|             rc = tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) ;
 | |
|             if ( rc != 0 || errUnique != 0 )
 | |
|                findVal = -2L ;
 | |
|             for(;;)
 | |
|             {
 | |
|                if ( (*t4->cmp)( tfile4keyData( t4 )->value, keyInfo, t4->header.keyLen ) == 0 )
 | |
|                {
 | |
|                   trc = tfile4skip( t4, 1L ) ;
 | |
|                   if ( trc == 0L )
 | |
|                   {
 | |
|                      b4goEof( tfile4block( t4 ) ) ;
 | |
|                      break ;
 | |
|                   }
 | |
|                }
 | |
|                else
 | |
|                   break ;
 | |
|             }
 | |
|             if ( tfile4recNo( t4 ) != findVal )
 | |
|                return error4( c4, e4index, E85402 ) ;
 | |
|          #endif
 | |
|       }
 | |
|    #endif
 | |
| 
 | |
|    tfile4descending( t4, oldDesc ) ;
 | |
|    if ( rc < 0 )
 | |
|       return error4stack( c4, rc, E95402 ) ;
 | |
| 
 | |
|    if ( rc == 0 )
 | |
|    {
 | |
|       switch ( errUnique )
 | |
|       {
 | |
|          case e4unique:
 | |
|             #ifdef N4OTHER
 | |
|                return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), t4->file.name, 0 ) ;
 | |
|             #else
 | |
|                return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), t4->indexFile->file.name, 0 ) ;
 | |
|             #endif
 | |
|          case r4unique:
 | |
|             return r4unique ;
 | |
|          case r4uniqueContinue:
 | |
|             return r4uniqueContinue ;
 | |
|          default:
 | |
|             break ;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    oldBlock = tfile4block(t4) ;
 | |
|    oldFileBlock = 0 ;
 | |
|    newFileBlock = 0 ;
 | |
| 
 | |
|    t4->header.version = (short)(t4->header.oldVersion + 1L) ;
 | |
| 
 | |
|    while( !b4leaf( oldBlock ) )
 | |
|    {
 | |
|       rc = tfile4down( t4 ) ;
 | |
|       if ( rc < 0 || rc == 2 )
 | |
|          return -1 ;
 | |
|       oldBlock = tfile4block( t4 ) ;
 | |
|       if ( b4leaf( oldBlock ) )
 | |
|          oldBlock->keyOn = b4lastpos( oldBlock ) + 1 ;
 | |
|       else
 | |
|          oldBlock->keyOn = b4lastpos( oldBlock ) ;
 | |
|    }
 | |
| 
 | |
|    for(;;)
 | |
|    {
 | |
|       if ( oldBlock == 0 )
 | |
|       {
 | |
|          /* Must create a new root block */
 | |
|          extendBlock = tfile4extend( t4 ) ;
 | |
|          if ( extendBlock < 0 )
 | |
|             return (int) extendBlock ;
 | |
| 
 | |
|          rootBlock = b4alloc( t4, extendBlock) ;
 | |
|          if ( rootBlock == 0 )
 | |
|             return -1 ;
 | |
| 
 | |
|          l4add( &t4->blocks, rootBlock ) ;
 | |
| 
 | |
|          /* need to set root first so that b4insert() will record that current
 | |
|             block is the root block, which is vital to its functioning */
 | |
|          t4->header.root = rootBlock->fileBlock * 512 ;
 | |
|          b4insert( rootBlock, keyInfo, rec, oldFileBlock ) ;
 | |
|          b4append( rootBlock, newFileBlock ) ;
 | |
| 
 | |
|          t4->rootWrite  = 1 ;
 | |
|          return 0 ;
 | |
|       }
 | |
| 
 | |
|       if ( b4room( oldBlock ) )
 | |
|       {
 | |
|          if ( b4leaf( oldBlock ) )
 | |
|             b4insert( oldBlock, keyInfo, rec, 0L ) ;
 | |
|          else   /* update the current pointer, add the new branch */
 | |
|          {
 | |
|             #ifdef E4ANALYZE
 | |
|                if ( oldBlock->nKeys == 0 )
 | |
|                   return error4( t4->codeBase, e4index, E95402 ) ;
 | |
|             #endif
 | |
|                atNew = b4key( oldBlock, oldBlock->keyOn ) ;
 | |
|                atNew->pointer = newFileBlock * 512 ;
 | |
|                b4insert( oldBlock, keyInfo, rec, oldFileBlock ) ;
 | |
|          }
 | |
|          return 0 ;
 | |
|       }
 | |
| 
 | |
|       l4pop( &t4->blocks ) ;
 | |
| 
 | |
|       /* NNNNOOOO  N - New, O - Old */
 | |
|       /* The new block's end key gets added to the block just up */
 | |
|       if ( oldBlock->keyOn < (t4->header.keysHalf + ( b4leaf( oldBlock ) ? 0 : 1 ) ) )
 | |
|       {
 | |
|          newBlock= tfile4split( t4, oldBlock, 0 ) ;
 | |
|          if ( newBlock == 0 )
 | |
|             return -1 ;
 | |
|          wchBlock = oldBlock ;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          newBlock= tfile4split( t4, oldBlock, 1 ) ;
 | |
|          if ( newBlock == 0 )
 | |
|             return -1 ;
 | |
|          wchBlock = newBlock ;
 | |
|       }
 | |
| 
 | |
|       if ( b4leaf( wchBlock ) )
 | |
|       {
 | |
|          b4insert( wchBlock, keyInfo, rec, 0L ) ;
 | |
|          if ( newBlock->nKeys <= t4->header.keysHalf )   /* add a key from the old block!, must have info in newBlock because oldBlock gets deleted below */
 | |
|          {
 | |
|             #ifdef E4ANALYZE
 | |
|                if ( oldBlock->nKeys <= t4->header.keysHalf )  /* impossible */
 | |
|                   #ifdef N4OTHER
 | |
|                      return error4describe( t4->codeBase, e4index, E81601, tfile4alias( t4 ), t4->file.name, 0 ) ;
 | |
|                   #else
 | |
|                      return error4describe( t4->codeBase, e4index, E81601, tfile4alias( t4 ), t4->indexFile->file.name, 0 ) ;
 | |
|                   #endif
 | |
|             #endif
 | |
|             oldBlock->keyOn = oldBlock->nKeys - 1 ;
 | |
|             memcpy( keyData, b4keyKey( oldBlock, oldBlock->keyOn ), t4->header.keyLen ) ;
 | |
|             keyInfo = keyData ;
 | |
|             rec = b4key( oldBlock, oldBlock->keyOn )->num ;
 | |
|             b4remove( oldBlock ) ;
 | |
|             newBlock->keyOn = 0 ;
 | |
|             b4insert( newBlock, keyInfo, rec, 0 ) ;
 | |
|          }
 | |
|          newBlock->keyOn = 0 ;
 | |
|          memcpy( keyData, b4keyKey( newBlock, newBlock->keyOn ), t4->header.keyLen ) ;
 | |
|          keyInfo = keyData ;
 | |
|          rec = b4key( newBlock, newBlock->keyOn )->num ;
 | |
|          b4remove( newBlock ) ;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          /* now get the key to place upwards */
 | |
|          if ( wchBlock->nKeys == 0 )   /* treat like a root block */
 | |
|          {
 | |
|             if ( wchBlock == oldBlock )  /* not a problem if number of keys very small ?? */
 | |
|             {
 | |
|                if ( wchBlock->keyOn == 1 )   /* at end, so must combine with new block alterations */
 | |
|                {
 | |
|                   wchBlock->nKeys = 1 ;  /* now reset to the proper value */
 | |
|                   /* don't actually need to do an insert, just set the file block value */
 | |
|                   /* but need to copy values in so that later copy for data gives correct results */
 | |
|                   memcpy( b4keyKey( oldBlock, 1), keyData, t4->header.keyLen ) ;
 | |
|                   b4key( oldBlock, 1 )->num = rec ;
 | |
|                   atNew = b4key( oldBlock, 1 ) ;
 | |
|                   atNew->pointer = oldFileBlock * 512 ;
 | |
|                   atNew = b4key( newBlock, 0 ) ;  /* currently set to old value, reset to new */
 | |
|                   atNew->pointer = newFileBlock * 512 ;
 | |
|                }
 | |
|                else  /* simple insert */
 | |
|                {
 | |
|                   wchBlock->nKeys = 1 ;  /* to get a proper insert */
 | |
|                   b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
 | |
|                   atNew = b4key( wchBlock, 1 ) ;
 | |
|                   atNew->pointer = newFileBlock * 512 ;
 | |
|                   memcpy( oldKeyPtr, b4keyKey( oldBlock, 1 ), t4->header.keyLen ) ;
 | |
|                   keyInfo = oldKeyPtr ;
 | |
|                   rec = b4key( oldBlock, 1 )->num ;
 | |
|                   wchBlock->nKeys = 1 ;  /* now reset to the proper value */
 | |
|                }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
 | |
|                b4append( wchBlock, newFileBlock ) ;
 | |
|             }
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|             if ( wchBlock->keyOn > wchBlock->nKeys && wchBlock == oldBlock )
 | |
|             {
 | |
|                atNew = b4key( newBlock, 0 ) ;
 | |
|                atNew->pointer = newFileBlock * 512 ;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                atNew = b4key( wchBlock, wchBlock->keyOn ) ;
 | |
|                atNew->pointer = newFileBlock * 512 ;
 | |
|             }
 | |
|             b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
 | |
|          }
 | |
|          memcpy( oldKeyPtr, b4keyKey( oldBlock, b4lastpos( oldBlock )), t4->header.keyLen ) ;
 | |
|          keyInfo = oldKeyPtr ;
 | |
|          rec = b4key( oldBlock, b4lastpos( oldBlock ) )->num ;
 | |
|       }
 | |
| 
 | |
|       #ifdef E4INDEX_VERIFY
 | |
|          rc = b4verify( oldBlock ) ;
 | |
|          if ( rc < 0 )
 | |
|             return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|          rc = b4verify( newBlock ) ;
 | |
|          if ( rc < 0 )
 | |
|             return error4stack( t4->codeBase, rc, E91642 ) ;
 | |
|       #endif
 | |
| 
 | |
|       l4add( &t4->saved, newBlock ) ;
 | |
|       newFileBlock = newBlock->fileBlock ;
 | |
|       oldFileBlock = oldBlock->fileBlock ;
 | |
|       if ( b4flush( oldBlock ) < 0 )
 | |
|          return -1 ;
 | |
|       b4free( oldBlock ) ;
 | |
|       oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
 | |
|    }
 | |
| }
 | |
| #endif  /* ifdef S4CLIPPER   */
 | |
| #endif  /* ifdef S4NDX    */
 | |
| 
 | |
| int t4addCalc( TAG4 *t4, long rec )
 | |
| {
 | |
|    int rc ;
 | |
|    char *ptr ;
 | |
|    TAG4FILE *tfile ;
 | |
|    #ifndef S4OFF_TRAN
 | |
|       TAG4KEY_REMOVED *removed ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef E4PARM_LOW
 | |
|       if ( t4 == 0 || rec < 1 )
 | |
|          return error4( 0, e4parm, E95403 ) ;
 | |
|    #endif
 | |
| 
 | |
|    tfile = t4->tagFile ;
 | |
| 
 | |
|    if ( error4code( tfile->codeBase ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    #ifdef S4CLIPPER
 | |
|       if ( tfile->filter )
 | |
|          if ( !expr4true( tfile->filter ) )
 | |
|             return 0;
 | |
|    #endif
 | |
| 
 | |
|    rc = tfile4exprKey( tfile, (unsigned char **)&ptr ) ;
 | |
|    if ( rc < 0 )
 | |
|       return error4stack( tfile->codeBase, rc, E95403 ) ;
 | |
| 
 | |
|    #ifndef S4OFF_TRAN
 | |
|       if ( code4tranStatus( tfile->codeBase ) == r4active && ( t4unique( t4 ) == r4unique ||
 | |
|            t4unique( t4 ) == e4unique
 | |
|            #ifdef S4FOX
 | |
|               || t4unique( t4 ) == r4candidate
 | |
|            #endif
 | |
|            ) )  /* just remove from the removed list */
 | |
|       {
 | |
|          removed = t4keyFind( t4, 0L, ptr ) ;
 | |
|          if ( removed != 0 )
 | |
|          {
 | |
|             if ( tfile4remove( tfile, removed->key, removed->recno ) < 0 )
 | |
|                return -1 ;
 | |
|             l4remove( &t4->removedKeys, removed ) ;
 | |
|             u4free( removed ) ;
 | |
|             return 0 ;
 | |
|          }
 | |
|       }
 | |
|    #endif
 | |
|    return tfile4add( tfile, (unsigned char *)ptr, rec, t4unique( t4 ) ) ;
 | |
| }
 | |
| 
 | |
| #endif  /* ifdef N4OTHER */
 | |
| #endif  /* S4OFF_WRITE */
 | |
| #endif  /* S4INDEX_OFF */
 | |
| #endif
 |