which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@976 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1091 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1091 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* i4remove.c   (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */
 | |
| 
 | |
| #include "d4all.h"
 | |
| #ifndef S4UNIX
 | |
| #ifdef __TURBOC__
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #ifndef S4OFF_WRITE
 | |
| #ifndef S4INDEX_OFF
 | |
| 
 | |
| int S4FUNCTION t4remove( TAG4 *t4, char *ptr, long rec )
 | |
| {
 | |
|   int rc ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( t4 == 0 )
 | |
|     e4severe( e4parm, E4_T4REMOVE ) ;
 | |
| #endif
 | |
| 
 | |
|   rc = t4go( t4, ptr, rec ) ;   /* returns -1 if code_base->error_code < 0 */
 | |
|   if ( rc < 0 )
 | |
|     return rc ;
 | |
|   if ( rc )
 | |
|     return r4entry ;
 | |
| 
 | |
|   return t4remove_current( t4 ) ;
 | |
| }
 | |
| 
 | |
| int S4FUNCTION t4remove_calc( TAG4 *t4, long rec )
 | |
| {
 | |
|   char *ptr ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( t4 == 0 )
 | |
|     e4severe( e4parm, E4_T4REM_CALC ) ;
 | |
| #endif
 | |
| 
 | |
|   if ( t4->code_base->error_code < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   t4expr_key( t4, &ptr ) ;
 | |
|   return t4remove( t4, ptr, rec ) ;
 | |
| }
 | |
| 
 | |
| #ifndef N4OTHER
 | |
| 
 | |
| #ifdef S4FOX
 | |
| /* remove the (current) branch block */
 | |
| void S4FUNCTION t4remove_branch( TAG4 *t4, B4BLOCK *block_on )
 | |
| {
 | |
|   long l_node, r_node ;
 | |
|   INDEX4 *i4 ;
 | |
| #ifdef S4BYTE_SWAP
 | |
|   char *swap_ptr ;
 | |
|   S4LONG long_val ;
 | |
|   short short_val ;
 | |
|   int i ;
 | |
| #endif
 | |
| 
 | |
|   i4 = t4->index ;
 | |
| 
 | |
|   if ( block_on == (B4BLOCK *)l4first( &t4->blocks ) )
 | |
|   {
 | |
|     /* Root Block, do not delete */
 | |
| #ifdef S4DEBUG
 | |
|     if ( block_on->header.left_node != -1 || block_on->header.right_node != -1 || block_on->header.n_keys != 1 )
 | |
|       e4severe( e4info, E4_INFO_CIB ) ;
 | |
| #endif
 | |
|     memset( block_on->data, 0, B4BLOCK_SIZE - sizeof(B4STD_HEADER) - sizeof(B4NODE_HEADER) ) ;
 | |
|     if ( !b4leaf( block_on ) )   /* if not a leaf, then reset node_hdr too */
 | |
|     {
 | |
|       memset( (void *)&block_on->node_hdr, 0, sizeof(B4NODE_HEADER) ) ;
 | |
|       b4leaf_init( block_on ) ;
 | |
|     }
 | |
|     else
 | |
|       block_on->node_hdr.free_space = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - sizeof( B4NODE_HEADER ) ;
 | |
|     block_on->header.n_keys = 0 ;
 | |
|     block_on->header.left_node = -1 ;
 | |
|     block_on->header.right_node = -1 ;
 | |
|     block_on->key_on = -1 ;
 | |
|     block_on->built_on = -1 ;
 | |
|     block_on->header.node_attribute = 3 ;  /* root and leaf */
 | |
|     block_on->changed = 1 ;
 | |
|   }
 | |
|   else /* This block is to be deleted */
 | |
|   {
 | |
|     l_node = block_on->header.left_node ;
 | |
|     r_node = block_on->header.right_node ;
 | |
|     l4remove( &t4->blocks, block_on ) ;
 | |
|     if ( i4shrink( i4, block_on->file_block ) < 0 )
 | |
|       return ;
 | |
|     block_on->changed = 0 ;
 | |
| 
 | |
|     if ( l_node != -1L )
 | |
|     {
 | |
|       if ( file4read_all( &i4->file, I4MULTIPLY*l_node, &block_on->header, B4BLOCK_SIZE) < 0 )
 | |
|         return ;
 | |
| 
 | |
| #ifdef S4BYTE_SWAP
 | |
|       block_on->header.node_attribute = x4reverse_short( (void *)&block_on->header.node_attribute ) ;
 | |
|       block_on->header.n_keys = x4reverse_short( (void *)&block_on->header.n_keys ) ;
 | |
|       block_on->header.left_node = x4reverse_long( (void *)&block_on->header.left_node ) ;
 | |
|       block_on->header.right_node = x4reverse_long( (void *)&block_on->header.right_node ) ;
 | |
| 
 | |
|       /* if block is a leaf */
 | |
|       if (block_on->header.node_attribute >= 2 )
 | |
|       {
 | |
|         block_on->node_hdr.free_space = x4reverse_short( (void *)&block_on->node_hdr.free_space ) ;
 | |
|         long_val = x4reverse_long( (void *)&block_on->node_hdr.rec_num_mask[0] ) ;
 | |
|         memcpy( (void *)&block_on->node_hdr.rec_num_mask[0], (void *)&long_val, sizeof(S4LONG) ) ;
 | |
|       }
 | |
|       else                /* if block is a branch */
 | |
|       {
 | |
|         short_val = block_on->tag->header.key_len + sizeof(S4LONG) ;
 | |
|         /* position swap_ptr to end of first key expression */
 | |
|         swap_ptr = (char *) &block_on->node_hdr.free_space + block_on->tag->header.key_len ;
 | |
| 
 | |
|         /* move through all B4KEY's to swap 'long's */
 | |
|         for ( i = 0 ; i < (int) block_on->header.n_keys ; i++ )
 | |
|         {
 | |
|           long_val = x4reverse_long( (void *)swap_ptr ) ;
 | |
|           memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
 | |
|           swap_ptr += sizeof(S4LONG) ;
 | |
|           long_val = x4reverse_long( (void *)swap_ptr ) ;
 | |
|           memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
 | |
|           swap_ptr += short_val ;
 | |
|         }
 | |
|       }
 | |
| #endif
 | |
| 
 | |
|       block_on->file_block = l_node ;
 | |
|       block_on->header.right_node = r_node ;
 | |
|       block_on->changed = 1 ;
 | |
|       b4flush( block_on ) ;
 | |
|     }
 | |
| 
 | |
|     if ( r_node != -1L )
 | |
|     {
 | |
|       if ( file4read_all( &i4->file, I4MULTIPLY*r_node, &block_on->header, B4BLOCK_SIZE) < 0 )
 | |
|         return ;
 | |
| 
 | |
| #ifdef S4BYTE_SWAP
 | |
|       block_on->header.node_attribute = x4reverse_short( (void *)&block_on->header.node_attribute ) ;
 | |
|       block_on->header.n_keys = x4reverse_short( (void *)&block_on->header.n_keys ) ;
 | |
|       block_on->header.left_node = x4reverse_long( (void *)&block_on->header.left_node ) ;
 | |
|       block_on->header.right_node = x4reverse_long( (void *)&block_on->header.right_node ) ;
 | |
| 
 | |
|       /* if block is a leaf */
 | |
|       if (block_on->header.node_attribute >= 2 )
 | |
|       {
 | |
|         block_on->node_hdr.free_space = x4reverse_short( (void *)&block_on->node_hdr.free_space ) ;
 | |
|         long_val = x4reverse_long( (void *)block_on->node_hdr.rec_num_mask ) ;
 | |
|         memcpy( (void *)block_on->node_hdr.rec_num_mask, (void *)&long_val, sizeof(S4LONG) ) ;
 | |
|       }
 | |
|       else                /* if block is a branch */
 | |
|       {
 | |
|         short_val = block_on->tag->header.key_len + sizeof(S4LONG) ;
 | |
|         /* position swap_ptr to end of first key expression */
 | |
|         swap_ptr = (char *) &block_on->node_hdr.free_space + block_on->tag->header.key_len ;
 | |
| 
 | |
|         /* move through all B4KEY's to swap 'long's */
 | |
|         for ( i = 0 ; i < (int) block_on->header.n_keys ; i++ )
 | |
|         {
 | |
|           long_val = x4reverse_long( (void *)swap_ptr ) ;
 | |
|           memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
 | |
|           swap_ptr += sizeof(S4LONG) ;
 | |
|           long_val = x4reverse_long( (void *)swap_ptr ) ;
 | |
|           memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
 | |
|           swap_ptr += short_val ;
 | |
|         }
 | |
|       }
 | |
| #endif
 | |
| 
 | |
|       block_on->file_block = r_node ;
 | |
|       block_on->header.left_node = l_node ;
 | |
|       block_on->changed = 1 ;
 | |
|       b4flush( block_on ) ;
 | |
|     }
 | |
| 
 | |
|     b4free( block_on ) ;
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* Remove the current key */
 | |
| int S4FUNCTION t4remove_current( TAG4 *t4 )
 | |
| {
 | |
|   B4BLOCK *block_on ;
 | |
|   INDEX4 *i4 ;
 | |
| #ifdef S4FOX
 | |
|   void *new_key_info ;
 | |
|   long rec ;
 | |
|   int bl_removed, less_than_last ;
 | |
| #else
 | |
|   int remove_done, update_reqd ;
 | |
|   B4BLOCK *block_iterate ;
 | |
| #endif
 | |
| 
 | |
|   i4 = t4->index ;
 | |
| 
 | |
| #ifdef S4FOX
 | |
|   i4->tag_index->header.version = i4->version_old+1 ;
 | |
|   new_key_info = 0 ;
 | |
| 
 | |
|   for ( block_on = (B4BLOCK *)t4->blocks.last_node ; block_on ; )
 | |
|   {
 | |
|     bl_removed = 0 ;
 | |
|     if ( new_key_info == 0 )  /* then delete entry */
 | |
|     {
 | |
|       if ( b4lastpos( block_on ) == 0 )
 | |
|       {
 | |
|         if ( block_on != (B4BLOCK *)l4first( &t4->blocks ) )
 | |
|           bl_removed = 1 ;
 | |
|         t4remove_branch( t4, block_on ) ;
 | |
|         block_on = (B4BLOCK *)t4->blocks.last_node ;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         less_than_last = 0 ;
 | |
|         if ( block_on->key_on < b4lastpos( block_on ) )
 | |
|           less_than_last = 1 ;
 | |
|         b4remove( block_on ) ;
 | |
|         if ( less_than_last )
 | |
|           return 0 ;
 | |
| 
 | |
|         /* On last entry */
 | |
|         b4go_eof( block_on ) ;
 | |
|         block_on->key_on-- ;  /* update key_on for goint to last spot */
 | |
|         new_key_info = b4key_key( block_on, block_on->key_on ) ;
 | |
|         rec = b4recno( block_on, block_on->key_on ) ;
 | |
|       }
 | |
|     }
 | |
|     else  /* Adjust entry */
 | |
|     {
 | |
|       b4br_replace( block_on, (char *)new_key_info, rec ) ;
 | |
|       if ( block_on->key_on != b4lastpos( block_on ) )  /* not on end key, so exit, else continue */
 | |
|         return 0 ;
 | |
|     }
 | |
| 
 | |
|     if ( !bl_removed )
 | |
|     {
 | |
|       block_on = (B4BLOCK *)block_on->link.p ;
 | |
|       if ( block_on == (B4BLOCK *)t4->blocks.last_node )
 | |
|         break ;
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef S4MDX
 | |
|   remove_done = 0 ;
 | |
|   update_reqd = 0 ;
 | |
|   i4->changed = 1 ;
 | |
|   t4->changed = 1 ;
 | |
|   t4->header.version++ ;
 | |
| 
 | |
|   block_iterate = (B4BLOCK *)l4last( &t4->blocks ) ;
 | |
|   for ( ;; )
 | |
|   {
 | |
|     block_on = block_iterate ;
 | |
|     if ( block_on == 0 )
 | |
|       break ;
 | |
|     block_iterate = (B4BLOCK *)l4prev( &t4->blocks, block_iterate ) ;  /* Calculate the previous block while the current block exists. */
 | |
| 
 | |
|     if ( !remove_done )  /* either removing or else updating */
 | |
|     {
 | |
|       if ( b4lastpos( block_on ) == 0 )  /* delete block */
 | |
|       {
 | |
|         if ( block_on == (B4BLOCK *)l4first( &t4->blocks ) )  /* root block, don't delete */
 | |
|         {
 | |
|           block_on->changed = 1 ;
 | |
|           block_on->key_on = 0 ;
 | |
|           memset( (void *)&block_on->n_keys, 0, i4->header.block_rw ) ;
 | |
|           if (t4->filter )  /* must modify the filter setting for dBASE IV compatibility */
 | |
|           {
 | |
|             file4write(&t4->index->file, t4->header_offset+sizeof(t4->header)+222, (char *)"\0", (int)1 ) ;
 | |
|             t4->has_keys = 0 ;
 | |
| #ifdef S4MDX
 | |
|             t4->had_keys = 1 ;
 | |
| #endif
 | |
|           }
 | |
|           return 0 ;
 | |
|         }
 | |
| else
 | |
| {
 | |
|   l4remove( &t4->blocks, block_on ) ;
 | |
|   if ( i4shrink( i4, block_on->file_block) < 0 )
 | |
|     return -1 ;
 | |
|   b4free( block_on ) ;
 | |
| }
 | |
| }
 | |
| else  /* just remove entry */
 | |
| {
 | |
|   if ( block_iterate && block_on->key_on == b4lastpos( block_on ) && b4lastpos( block_on ) > 0 )  /* save to become last key of the block for parent update */
 | |
|   {
 | |
|     memcpy( t4->code_base->saved_key, b4key_key( block_on, block_on->n_keys - 1 - b4leaf(block_on) ), t4->header.key_len ) ;
 | |
|     update_reqd = 1 ;
 | |
|   }
 | |
|   else
 | |
|     update_reqd = 0 ;
 | |
| 
 | |
|   b4remove( block_on ) ;
 | |
|   if ( !b4leaf( block_on ) && b4lastpos( block_on ) == 0 )  /* branch with only one entry, so have the entry take place of this block */
 | |
|   {
 | |
|     if (block_on == (B4BLOCK *)l4first( &t4->blocks ) )   /* the entry becomes the new root */
 | |
|     {
 | |
|       /* first update the tags root */
 | |
|       t4->header.root = b4key( block_on, 0 )->num ;
 | |
| #ifdef S4BYTE_SWAP
 | |
|       t4->header.root = x4reverse_long( (void *)&t4->header.root ) ;
 | |
| #endif
 | |
|       file4write( &t4->index->file, t4->header_offset, (void *)&t4->header.root, sizeof(t4->header.root) ) ;
 | |
| #ifdef S4BYTE_SWAP
 | |
|       t4->header.root = x4reverse_long( (void *)&t4->header.root ) ;
 | |
| #endif
 | |
|       update_reqd = 0 ;
 | |
|     }
 | |
|     else  /* remove this branch block */
 | |
|     {
 | |
|       block_iterate->changed = 1 ;
 | |
|       b4key( block_iterate, block_iterate->key_on )->num = b4key( block_on, 0 )->num ;
 | |
|     }
 | |
|     l4remove( &t4->blocks, block_on ) ;
 | |
|     if ( i4shrink( t4->index, block_on->file_block) < 0 )
 | |
|       return -1 ;
 | |
|     block_on->changed = 0 ;
 | |
|     b4free( block_on ) ;
 | |
|   }
 | |
|   else
 | |
|     block_on->key_on = b4lastpos( block_on ) ;
 | |
| 
 | |
|   if ( !update_reqd )
 | |
|     return 0 ;
 | |
|   remove_done = 1 ;
 | |
| }
 | |
| }
 | |
| else  /* Adjust entry - at most one update will be required in MDX */
 | |
| {
 | |
|   if ( block_on->key_on < b4lastpos( block_on ) )
 | |
|   {
 | |
|     block_on->changed = 1 ;
 | |
|     memcpy( b4key_key( block_on, block_on->key_on), t4->code_base->saved_key, t4->header.key_len ) ;
 | |
|     return 0 ;
 | |
|   }
 | |
| }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| return 0 ;
 | |
| }
 | |
| 
 | |
| #endif   /* ifndef N4OTHER  */
 | |
| 
 | |
| #ifdef N4OTHER
 | |
| 
 | |
| #ifdef S4NDX
 | |
| int S4FUNCTION t4remove_current( TAG4 *t4 )
 | |
| {
 | |
|   B4BLOCK *block_on, *block_iterate ;
 | |
|   int remove_done, update_reqd ;
 | |
| #ifdef S4USE_OLD
 | |
|   void *new_key_info ;
 | |
|   long shrink_br = 0 ;
 | |
|   B4BLOCK *shrink_block = 0 ;
 | |
|   new_key_info = 0 ;
 | |
| #endif
 | |
| 
 | |
|   t4->header.version = t4->header.old_version+1 ;
 | |
| 
 | |
|   remove_done = 0 ;
 | |
|   update_reqd = 0 ;
 | |
|   t4->header.version++ ;
 | |
| 
 | |
|   block_iterate = (B4BLOCK *)l4last( &t4->blocks ) ;
 | |
|   for ( ;; )
 | |
|   {
 | |
|     block_on = block_iterate ;
 | |
|     if ( block_on == 0 )
 | |
|       break ;
 | |
|     block_iterate = (B4BLOCK *)l4prev( &t4->blocks, block_iterate ) ;  /* Calculate the previous block while the current block exists. */
 | |
| 
 | |
|     if ( !remove_done )  /* either removing or else updating */
 | |
|     {
 | |
|       if ( b4lastpos( block_on ) == 0 )  /* delete block */
 | |
|       {
 | |
|         block_on->changed = 1 ;
 | |
|         block_on->key_on = 0 ;
 | |
|         memset( (void *)&block_on->n_keys, 0, B4BLOCK_SIZE ) ;
 | |
|         if ( block_on == (B4BLOCK *)l4first( &t4->blocks ) )  /* root block, don't delete */
 | |
|           return 0 ;
 | |
| else
 | |
| {
 | |
|   l4remove( &t4->blocks, block_on ) ;
 | |
|   if ( b4flush( block_on ) < 0 )
 | |
|     return -1 ;
 | |
|   b4free( block_on ) ;
 | |
| }
 | |
| }
 | |
| else  /* just remove entry */
 | |
| {
 | |
|   if ( block_iterate && block_on->key_on == b4lastpos( block_on ) && b4lastpos( block_on ) > 0 )  /* save to become last key of the block for parent update */
 | |
|   {
 | |
|     memcpy( t4->code_base->saved_key, b4key_key( block_on, block_on->n_keys - 1 - b4leaf(block_on) ), t4->header.key_len ) ;
 | |
|     update_reqd = 1 ;
 | |
|   }
 | |
|   else
 | |
|     update_reqd = 0 ;
 | |
| 
 | |
|   b4remove( block_on ) ;
 | |
|   if ( !b4leaf( block_on ) && b4lastpos( block_on ) == 0 )  /* branch with only one entry, so have the entry take place of this block */
 | |
|   {
 | |
|     if (block_on == (B4BLOCK *)l4first( &t4->blocks ) )   /* the entry becomes the new root */
 | |
|     {
 | |
|       /* first update the tags root */
 | |
|       t4->header.root = b4key( block_on, 0 )->num ;
 | |
| #ifdef S4BYTE_SWAP
 | |
|       t4->header.root = x4reverse_long( (void *)&t4->header.root ) ;
 | |
| #endif
 | |
|       file4write( &t4->file, t4->header_offset, (void *)&t4->header.root, sizeof(t4->header.root) ) ;
 | |
| #ifdef S4BYTE_SWAP
 | |
|       t4->header.root = x4reverse_long( (void *)&t4->header.root ) ;
 | |
| #endif
 | |
|       update_reqd = 0 ;
 | |
|     }
 | |
|     else  /* remove this branch block */
 | |
|     {
 | |
|       block_iterate->changed = 1 ;
 | |
|       b4key( block_iterate, block_iterate->key_on )->pointer = b4key( block_on, 0 )->pointer ;
 | |
|     }
 | |
|     l4remove( &t4->blocks, block_on ) ;
 | |
|     block_on->changed = 1 ;
 | |
|     memset( &block_on->n_keys, 0, B4BLOCK_SIZE ) ;
 | |
|     if ( b4flush( block_on ) < 0 )
 | |
|       return -1 ;
 | |
|     b4free( block_on ) ;
 | |
|   }
 | |
|   else
 | |
|     block_on->key_on = b4lastpos( block_on ) ;
 | |
| 
 | |
|   if ( !update_reqd )
 | |
|     return 0 ;
 | |
|   remove_done = 1 ;
 | |
| }
 | |
| }
 | |
| else  /* Adjust entry - at most one update will be required in MDX */
 | |
| {
 | |
|   if ( block_on->key_on < b4lastpos( block_on ) )
 | |
|   {
 | |
|     block_on->changed = 1 ;
 | |
|     memcpy( b4key_key( block_on, block_on->key_on), t4->code_base->saved_key, t4->header.key_len ) ;
 | |
|     return 0 ;
 | |
|   }
 | |
| }
 | |
| }
 | |
| 
 | |
| return 0 ;
 | |
| }
 | |
| #else
 | |
| #ifdef S4CLIPPER
 | |
| int S4FUNCTION t4balance_branch( TAG4 *, B4BLOCK * ) ;
 | |
| 
 | |
| int S4FUNCTION t4remove_ref( TAG4 *t4 )
 | |
| {
 | |
|   B4KEY_DATA *my_key_data ;
 | |
|   B4BLOCK *block_on, *block_up ;
 | |
|   long reference ;
 | |
|   int i ;
 | |
|   int rc ;
 | |
| 
 | |
|   my_key_data = (B4KEY_DATA *)u4alloc_er( t4->code_base, t4->header.group_len ) ;
 | |
|   if ( my_key_data == 0 )
 | |
|     return -1 ;
 | |
|   block_on = (B4BLOCK *)t4->blocks.last_node ;
 | |
| 
 | |
|   /*  no longer required...
 | |
|       #ifdef S4DEBUG
 | |
|       if ( block_on->n_keys )
 | |
|       e4severe( e4info, E4_INFO_DEL ) ;
 | |
|       #endif
 | |
|       */
 | |
| 
 | |
|   t4up( t4 ) ;
 | |
|   block_up = (B4BLOCK *)t4->blocks.last_node ;
 | |
| 
 | |
|   if ( block_up == 0 )  /* root block only, so reference doesn't exist */
 | |
|   {
 | |
|     /* reset the block */
 | |
|     short offset = ( t4->header.keys_max + 2 + ( (t4->header.keys_max/2)*2 != t4->header.keys_max ) ) * sizeof(short) ;
 | |
|     for ( i = 0 ; i <= t4->header.keys_max ; i++ )
 | |
|       block_on->pointers[i] = (short)( t4->header.group_len * i ) + offset ;
 | |
|     return 0 ;
 | |
|   }
 | |
| else  /* delete the block */
 | |
| {
 | |
|   t4shrink( t4, block_on->file_block ) ;
 | |
|   l4pop( &t4->saved ) ;
 | |
|   block_on->changed = 0 ;
 | |
|   b4free( block_on ) ;
 | |
| }
 | |
| block_on = block_up ;
 | |
| 
 | |
| if ( block_on->key_on >= block_on->n_keys )
 | |
|   memcpy( &(my_key_data->num), &( b4key( block_on, block_on->key_on - 1 )->num), sizeof(long) + t4->header.key_len ) ;
 | |
| else
 | |
| memcpy( &(my_key_data->num), &( b4key( block_on, block_on->key_on )->num), sizeof(long) + t4->header.key_len ) ;
 | |
| 
 | |
| if ( block_on->n_keys == 1 )
 | |
| {
 | |
|   /* take the branch, and put in place of me, then delete and add me */
 | |
|   if ( block_on->key_on >= block_on->n_keys )
 | |
|     reference = (long) b4key( block_on, 0 )->pointer ;
 | |
|   else
 | |
|     reference = (long) b4key( block_on, 1 )->pointer ;
 | |
|   t4shrink( t4, block_on->file_block ) ;
 | |
|   t4up( t4 ) ;
 | |
|   l4pop(&t4->saved ) ;
 | |
|   block_on->changed = 0 ;
 | |
|   b4free( block_on ) ;
 | |
|   block_on = (B4BLOCK *)t4->blocks.last_node ;
 | |
|   if ( block_on == 0 )  /* just removed root, so make reference root! */
 | |
|     t4->header.root = reference ;
 | |
|   else
 | |
|   {
 | |
|     memcpy( &(b4key( block_on, block_on->key_on )->pointer), &reference, sizeof( reference ) )  ;
 | |
|     block_on->changed = 1 ;
 | |
|   }
 | |
| }
 | |
| else    /* just remove myself, add later */
 | |
| {
 | |
|   b4remove( block_on ) ;
 | |
|   if ( block_on->n_keys < t4->header.keys_half && block_on->file_block != t4->header.root )  /* if not root may have to balance the tree */
 | |
|   {
 | |
|     if ( t4balance_branch( t4, block_on ) < 0 )
 | |
|       return -1 ;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* now add the removed reference back into the index */
 | |
| rc = t4add( t4, (unsigned char *)my_key_data->value, my_key_data->num ) ;
 | |
| u4free( my_key_data ) ;
 | |
| 
 | |
| return rc ;
 | |
| }
 | |
| 
 | |
| static int t4balance_block( TAG4 *t4, B4BLOCK *parent, B4BLOCK *b4, B4BLOCK *b4temp, char is_right, char balance_mode )
 | |
| {
 | |
|   B4KEY_DATA *bdata, *bdata2 ;
 | |
|   int avg, i ;
 | |
|   long temp_fb ;
 | |
| 
 | |
|   if ( balance_mode == 2 && b4leaf( b4temp ) )
 | |
|   {
 | |
| #ifdef S4DEBUG
 | |
|     e4severe( e4info, E4_INFO_CIF ) ;
 | |
| #endif
 | |
|     return -1 ;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     if ( b4temp->n_keys + b4->n_keys < t4->header.keys_max )  /* join the two */
 | |
|     {
 | |
|       if ( is_right )
 | |
|       {
 | |
|         if ( balance_mode == 2 )
 | |
|         {
 | |
|           b4->key_on = 0 ;
 | |
|           parent->key_on-- ;
 | |
|           bdata = b4key( parent, parent->key_on ) ;
 | |
|           b4insert( b4, bdata->value, bdata->num, b4key( b4temp, b4temp->n_keys )->pointer / 512 ) ;
 | |
|           for ( i = b4temp->n_keys - 1 ; i >= 0 ; i-- )
 | |
|           {
 | |
|             b4->key_on = 0 ;
 | |
|             bdata = b4key( b4temp, i ) ;
 | |
|             b4insert( b4, bdata->value, bdata->num, bdata->pointer / 512 ) ;
 | |
|           }
 | |
|           b4temp->changed = 0 ;
 | |
|           t4shrink( t4, b4temp->file_block ) ;
 | |
|           b4remove( parent ) ;
 | |
|           if ( parent->n_keys < t4->header.keys_half )
 | |
|             t4balance_branch( t4, parent ) ;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           for ( i = 0 ; i < b4->n_keys ; i++ )
 | |
|           {
 | |
|             b4go_eof( b4temp ) ;
 | |
|             bdata = b4key( b4, i ) ;
 | |
|             b4insert( b4temp, bdata->value, bdata->num, 0L ) ;
 | |
|           }
 | |
| 
 | |
|           t4->index->code_base->do_index_verify = 0 ;  /* avoid verify errors due to our partial removal */
 | |
|           do
 | |
|           {
 | |
|             t4down( t4 ) ;
 | |
|           } while( !b4leaf( t4block( t4 ) ) ) ;
 | |
|           t4->index->code_base->do_index_verify = 1 ;
 | |
| 
 | |
|           b4flush( b4temp ) ;
 | |
|           if ( t4remove_ref( t4 ) != 0 )  /* will delete b4 and will remove and re-add the reference if required */
 | |
|             return -1 ;
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         /* put parent entry, then all but one child, then last child to parent */
 | |
|         b4go_eof( b4 ) ;
 | |
|         if ( balance_mode == 2 )
 | |
|         {
 | |
|           b4temp->key_on = 0 ;
 | |
|           bdata = b4key( parent, parent->key_on ) ;
 | |
|           b4insert( b4temp, bdata->value, bdata->num, b4key( b4, b4->n_keys )->pointer / 512 ) ;
 | |
|           for ( i = b4->n_keys - 1 ; i >= 0 ; i-- )
 | |
|           {
 | |
|             b4temp->key_on = 0 ;
 | |
|             bdata = b4key( b4, i ) ;
 | |
|             b4insert( b4temp, bdata->value, bdata->num, bdata->pointer / 512 ) ;
 | |
|           }
 | |
|           t4shrink( t4, b4->file_block ) ;
 | |
|           l4pop( &t4->saved ) ;
 | |
|           b4->changed = 0 ;
 | |
|           b4free( b4 ) ;
 | |
|           b4flush( b4temp ) ;
 | |
|           b4remove( parent ) ;
 | |
|           if ( parent->n_keys < t4->header.keys_half )
 | |
|             t4balance_branch( t4, parent ) ;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           bdata = b4key( parent, parent->key_on ) ;
 | |
|           b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
|           for ( i = 0 ; i < b4temp->n_keys - 1 ; i++ )
 | |
|           {
 | |
|             b4go_eof( b4 ) ;
 | |
|             bdata = b4key( b4temp, i ) ;
 | |
|             b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
|           }
 | |
|           bdata = b4key( parent, parent->key_on ) ;
 | |
|           bdata2 = b4key( b4temp, b4temp->n_keys - 1 ) ;
 | |
|           memcpy( bdata->value, bdata2->value, t4->header.key_len )  ;
 | |
|           memcpy( &( bdata->num ), &bdata2->num, sizeof( long ) )  ;
 | |
| 
 | |
|           parent->key_on++ ;
 | |
|           parent->changed = 1 ;
 | |
| 
 | |
|           t4->index->code_base->do_index_verify = 0 ;  /* avoid verify errors due to our partial removal */
 | |
|           b4flush( b4 ) ;
 | |
|           do
 | |
|           {
 | |
|             if ( t4down( t4 ) == 1 )
 | |
|               break ;
 | |
|           } while( ((B4BLOCK *)t4->blocks.last_node)->file_block != b4temp->file_block ) ;
 | |
|           t4->index->code_base->do_index_verify = 1 ;
 | |
|           if ( t4remove_ref( t4 ) != 0 )  /* will delete b4temp and will remove and re-add the reference if required */
 | |
|             return -1 ;
 | |
|           b4temp->changed = 0 ;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     else  /* will have to redistribute keys */
 | |
|     {
 | |
|       avg = ( b4->n_keys + b4temp->n_keys + 1 ) / 2 ;
 | |
|       if ( avg < t4->header.keys_half )
 | |
|         avg = t4->header.keys_half ;
 | |
|       if ( is_right )
 | |
|       {
 | |
|         b4->key_on = 0 ;
 | |
|         parent->key_on-- ;
 | |
|         bdata = b4key( parent, parent->key_on ) ;
 | |
| 
 | |
|         if ( balance_mode == 2 )
 | |
|         {
 | |
|           if ( b4->n_keys == 0 )
 | |
|           {
 | |
|             temp_fb = b4key( b4, 0 )->pointer ;
 | |
|             b4insert( b4, bdata->value, bdata->num, b4key( b4temp, b4temp->n_keys )->pointer / 512 ) ;
 | |
|             b4append( b4, temp_fb / 512 ) ;
 | |
|           }
 | |
|           else
 | |
|             b4insert( b4, bdata->value, bdata->num, b4key( b4temp, b4temp->n_keys )->pointer / 512 ) ;
 | |
|         }
 | |
|         else
 | |
|           b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
| 
 | |
|         while ( b4temp->n_keys > avg && b4->n_keys < avg )
 | |
|         {
 | |
|           b4->key_on = 0 ;
 | |
|           b4temp->key_on = b4temp->n_keys - 1 ;
 | |
|           bdata = b4key( b4temp, b4temp->key_on ) ;
 | |
|           if ( balance_mode == 2 )
 | |
|             b4insert( b4, bdata->value, bdata->num, bdata->pointer / 512 ) ;
 | |
|           else
 | |
|             b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
|           b4remove( b4temp ) ;
 | |
|         }
 | |
|         b4temp->key_on = b4temp->n_keys - 1 ;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         b4go_eof( b4 ) ;
 | |
|         if ( balance_mode == 2 )
 | |
|         {
 | |
|           bdata = b4key( b4, b4->n_keys ) ;
 | |
|           bdata2 = b4key( parent, parent->key_on ) ;
 | |
|           memcpy( bdata->value, bdata2->value, t4->header.key_len )  ;
 | |
|           memcpy( &(bdata->num), &bdata2->num, sizeof( long ) )  ;
 | |
|           b4->n_keys++ ;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           bdata = b4key( parent, parent->key_on ) ;
 | |
|           b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
|         }
 | |
| 
 | |
|         while ( b4->n_keys - (balance_mode == 2) < avg )
 | |
|         {
 | |
|           b4go_eof( b4 ) ;
 | |
|           b4temp->key_on = 0 ;
 | |
|           bdata = b4key( b4temp, b4temp->key_on ) ;
 | |
|           if ( balance_mode == 2 )
 | |
|             b4insert( b4, bdata->value, bdata->num, bdata->pointer / 512 ) ;
 | |
|           else
 | |
|             b4insert( b4, bdata->value, bdata->num, 0L ) ;
 | |
|           b4remove( b4temp ) ;
 | |
|         }
 | |
| 
 | |
|         if ( balance_mode == 2 )
 | |
|         {
 | |
|           b4->n_keys-- ;
 | |
|           b4->key_on-- ;
 | |
|         }
 | |
|         b4temp->key_on = 0 ;
 | |
|       }
 | |
|       /* and add a key back to the parent */
 | |
|       bdata = b4key( parent, parent->key_on ) ;
 | |
|       if ( balance_mode == 2 )
 | |
|       {
 | |
|         if ( is_right )
 | |
|           bdata2 = b4key( b4temp, b4temp->n_keys - 1 ) ;
 | |
|         else
 | |
|           bdata2 = b4key( b4, b4->n_keys ) ;
 | |
|         memcpy( bdata->value, bdata2->value, t4->header.key_len )  ;
 | |
|         memcpy( &(bdata->num), &bdata2->num, sizeof( long ) )  ;
 | |
|         if ( is_right )
 | |
|         {
 | |
|           b4temp->key_on = b4temp->n_keys ;
 | |
|           b4remove( b4temp ) ;
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         bdata2 = b4key( b4temp, b4temp->key_on ) ;
 | |
|         memcpy( bdata->value, bdata2->value, t4->header.key_len )  ;
 | |
|         memcpy( &(bdata->num), &bdata2->num, sizeof( long ) )  ;
 | |
|         b4remove( b4temp ) ;
 | |
|       }
 | |
|       parent->changed = 1 ;
 | |
|       b4flush( b4temp ) ;
 | |
|     }
 | |
|   }
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| static int t4balance_branch_leaf( TAG4 *t4, B4BLOCK *parent, B4BLOCK *branch, B4BLOCK *leaf )
 | |
| {
 | |
|   B4BLOCK *b4temp ;
 | |
|   long new_file_block ;
 | |
|   B4KEY_DATA *key ;
 | |
| 
 | |
|   t4->header.version++ ;
 | |
|   new_file_block = t4extend( t4 ) ;
 | |
|   b4temp = b4alloc( t4, new_file_block ) ;
 | |
|   if ( b4temp == 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   key = b4key( b4temp, 0 ) ;
 | |
|   key->pointer =  leaf->file_block * I4MULTIPLY ;
 | |
|   b4temp->changed = 1 ;
 | |
|   key = b4key( parent, parent->key_on ) ;
 | |
| #ifdef S4DEBUG_DEV
 | |
|   if ( key->pointer != leaf->file_block * I4MULTIPLY )
 | |
|     e4severe( e4info, "t4balance_branch_leaf - corruption" ) ;
 | |
| #endif
 | |
|   key->pointer = new_file_block * I4MULTIPLY ;
 | |
|   parent->changed = 1 ;
 | |
|   l4add( &t4->blocks, b4temp ) ;
 | |
| 
 | |
|   return t4balance_block( t4, parent, b4temp, branch, 1, 2 ) ;
 | |
| }
 | |
| 
 | |
| /* if do_full is true, the whole branch set will be balanced, not just the current leaf block and reqd.  Also, this will balance top down instead of the other way. */
 | |
| int S4FUNCTION t4balance( TAG4 *t4, B4BLOCK *b4, int do_full )
 | |
| {
 | |
|   B4BLOCK *b4temp, *parent ;
 | |
|   long temp_fb ;
 | |
|   int rc, i ;
 | |
|   char is_right, balance_mode ;  /* balance_mode = 0 for done, 1 for leaf, and 2 for branch */
 | |
| 
 | |
|   if ( !b4leaf( b4 ) )
 | |
|     return 0 ;
 | |
| 
 | |
|   b4temp = b4alloc( t4, 0L ) ;
 | |
|   if ( b4temp == 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   if ( do_full )
 | |
|   {
 | |
|     t4up_to_root( t4 ) ;
 | |
|     balance_mode = 2 ;  /* branch */
 | |
|   }
 | |
|   else
 | |
|     balance_mode = 1 ;  /* leaf */
 | |
| 
 | |
|   while ( balance_mode != 0 || do_full )
 | |
|   {
 | |
|     if ( do_full )
 | |
|     {
 | |
|       parent = (B4BLOCK *)t4->blocks.last_node ;
 | |
|       parent->key_on = parent->n_keys ;
 | |
|       rc = t4down( t4 ) ;
 | |
|       if ( rc == 1 )  /* make sure siblings are also leafs */
 | |
|       {
 | |
|         t4up( t4 ) ;
 | |
|         parent = (B4BLOCK *)t4->blocks.last_node ;
 | |
|         if ( parent != 0 )
 | |
|         {
 | |
|           if ( parent->key_on > 0 )
 | |
|           {
 | |
|             temp_fb = (long)b4key( parent, parent->key_on - 1 )->pointer ;
 | |
|             if ( i4read_block( &t4->file, temp_fb, 0, b4temp ) < 0 )
 | |
|             {
 | |
|               b4free( b4temp ) ;
 | |
|               return -1 ;
 | |
|             }
 | |
|             if ( b4leaf( b4temp ) == 0 &&  b4leaf( b4 ) == 1 )
 | |
|             {
 | |
|               rc = t4balance_branch_leaf( t4, parent, b4temp, b4 ) ;
 | |
|               b4free( b4temp ) ;
 | |
|               return rc ;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         break ;
 | |
|       }
 | |
|       if ( rc < 0 )
 | |
|         return -1 ;
 | |
| 
 | |
|       b4 = (B4BLOCK *)t4->blocks.last_node ;
 | |
|       b4->key_on = b4->n_keys ;
 | |
| 
 | |
|       if ( b4->n_keys >= t4->header.keys_half )
 | |
|         continue ;
 | |
| 
 | |
|       if ( b4leaf( b4 ) )
 | |
|         balance_mode = 1 ;
 | |
|       temp_fb = b4key( parent, parent->key_on - 1 )->pointer ;
 | |
|       is_right = 1 ;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if ( balance_mode == 2 )  /* branch */
 | |
|       {
 | |
|         b4 = parent ;
 | |
|         while( t4->blocks.last_node != (LINK4 *)b4 )  /* re-align ourselves */
 | |
|           t4up( t4 ) ;
 | |
|       }
 | |
|       t4up( t4 ) ;
 | |
|       parent = (B4BLOCK *)t4->blocks.last_node ;
 | |
| 
 | |
|       if ( parent == 0 )  /* root block */
 | |
|       {
 | |
|         t4down( t4 ) ;
 | |
|         parent = (B4BLOCK *)t4->blocks.last_node ;
 | |
|         if ( !b4leaf( parent ) && parent->n_keys == 0 )  /* remove */
 | |
|         {
 | |
|           temp_fb = (long)b4key( parent, 0 )->pointer ;
 | |
|           t4shrink( t4, parent->file_block ) ;
 | |
|           t4up( t4 ) ;
 | |
|           l4pop( &t4->saved ) ;
 | |
|           parent->changed = 0 ;
 | |
|           b4free( parent ) ;
 | |
|           t4->header.root = temp_fb ;
 | |
|           t4down( t4 ) ;
 | |
|         }
 | |
|         break ;
 | |
|       }
 | |
| 
 | |
|       if ( parent->n_keys == 0 )  /* try to replace parent with ourself */
 | |
|       {
 | |
| #ifdef S4DEBUG
 | |
|         e4severe( e4info, E4_INFO_CIF ) ;
 | |
| #endif
 | |
|         return -1 ;
 | |
|       }
 | |
| 
 | |
|       if ( b4->n_keys >= t4->header.keys_half )
 | |
|       {
 | |
|         balance_mode = 0 ;
 | |
|         continue ;
 | |
|       }
 | |
|       is_right = (parent->key_on == parent->n_keys ) ;
 | |
|       if ( is_right )
 | |
|         temp_fb = b4key( parent, parent->key_on - 1 )->pointer ;
 | |
|       else
 | |
|         temp_fb = b4key( parent, parent->key_on + 1 )->pointer ;
 | |
|     }
 | |
| 
 | |
|     b4temp->file_block = temp_fb ;
 | |
|     for ( ;; )
 | |
|     {
 | |
|       if ( i4read_block( &t4->file, temp_fb, 0, b4temp ) < 0 )
 | |
|       {
 | |
|         b4free( b4temp ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| 
 | |
|       if ( balance_mode == 2 || b4leaf( b4temp ) )  /* if branch mode or leaf mode and leaf block found */
 | |
|         break ;
 | |
| 
 | |
|       if ( is_right )
 | |
|         temp_fb = b4key( b4temp, b4temp->n_keys )->pointer ;
 | |
|       else
 | |
|         temp_fb = b4key( b4temp, 0 )->pointer ;
 | |
|     }
 | |
| 
 | |
|     if ( t4balance_block( t4, parent, b4, b4temp, is_right, balance_mode ) < 0 )
 | |
|       return -1 ;
 | |
| 
 | |
|     if ( do_full )
 | |
|     {
 | |
|       if ( b4leaf( b4 ) )
 | |
|         balance_mode = 0 ;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if ( parent->n_keys < t4->header.keys_half )  /* do parent as well */
 | |
|         balance_mode = 2 ;
 | |
|       else
 | |
|         balance_mode = 0 ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   b4free( b4temp ) ;
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| int S4FUNCTION t4get_replace_entry( TAG4 *t4, B4KEY_DATA *insert_spot, B4BLOCK *save_block )
 | |
| {
 | |
|   int rc ;
 | |
|   B4BLOCK *block_on ;
 | |
| 
 | |
|   block_on = save_block ;
 | |
| 
 | |
|   if ( b4leaf( block_on ) )
 | |
|     return 0 ;
 | |
| 
 | |
|   block_on->key_on = block_on->key_on + 1 ;
 | |
|   while ( !b4leaf( block_on ) )
 | |
|   {
 | |
|     rc = t4down( t4 ) ;
 | |
|     if ( rc < 0 || rc == 2 )
 | |
|       return -1 ;
 | |
|     block_on = (B4BLOCK *)t4->blocks.last_node ;
 | |
|   }
 | |
|   memcpy( &insert_spot->num, &(b4key( block_on, block_on->key_on )->num), sizeof(long) + t4->header.key_len ) ;
 | |
|   save_block->changed = 1 ;
 | |
|   b4remove( block_on ) ;
 | |
|   if ( block_on->n_keys < t4->header.keys_half && block_on->file_block != t4->header.root )  /* if not root may have to balance the tree */
 | |
|     if ( t4balance( t4, block_on, 0 ) < 0 )
 | |
|       return -1 ;
 | |
|   return 1 ;
 | |
| }
 | |
| 
 | |
| int S4FUNCTION t4balance_branch( TAG4 *t4, B4BLOCK *b4 )
 | |
| {
 | |
|   B4BLOCK *parent, *b4temp ;
 | |
|   int is_right ;
 | |
|   long temp_fb, reference ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( b4leaf( b4 ) )
 | |
|     e4severe( e4info, E4_T4BALANCE_BR ) ;
 | |
| #endif
 | |
| 
 | |
|   if ( b4 == (B4BLOCK *)l4first( &t4->blocks ) )
 | |
|   {
 | |
|     if ( b4->n_keys == 0 )   /* empty, so just remove */
 | |
|     {
 | |
|       reference = (long)b4key( b4, 0 )->pointer ;
 | |
|       b4->changed = 0 ;
 | |
|       t4shrink( t4, b4->file_block ) ;
 | |
|       t4up( t4 ) ;
 | |
|       l4pop(&t4->saved ) ;
 | |
|       t4->header.root = reference ;
 | |
|     }
 | |
|     return 0 ;
 | |
|   }
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if (  b4->n_keys < 2 )
 | |
|     e4severe( e4info, E4_T4BALANCE_BR ) ;
 | |
| #endif
 | |
| 
 | |
|   t4up( t4 ) ;
 | |
|   parent = (B4BLOCK *)t4->blocks.last_node ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( b4key( parent, parent->key_on )->pointer != I4MULTIPLY * b4->file_block )
 | |
|     e4severe( e4info, E4_T4BALANCE_BR ) ;
 | |
| #endif
 | |
| 
 | |
|   if ( parent->key_on == parent->n_keys )
 | |
|   {
 | |
|     temp_fb = b4key( parent, parent->key_on - 1 )->pointer ;
 | |
|     is_right = 1 ;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     temp_fb = b4key( parent, parent->key_on + 1 )->pointer ;
 | |
|     is_right = 0 ;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   b4temp = b4alloc( t4, 0L ) ;
 | |
|   if ( b4temp == 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   if ( i4read_block( &t4->file, temp_fb, 0, b4temp ) < 0 )
 | |
|   {
 | |
|     b4free( b4temp ) ;
 | |
|     return -1 ;
 | |
|   }
 | |
| 
 | |
|   if ( t4balance_block( t4, parent, b4, b4temp, is_right, 2 ) < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   b4free( b4temp ) ;
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| int S4FUNCTION t4remove_current( TAG4 *t4 )
 | |
| {
 | |
|   B4BLOCK *block_on ;
 | |
| 
 | |
|   t4->header.version = (short)( t4->header.old_version + 1L ) ;
 | |
| 
 | |
|   block_on = (B4BLOCK *)t4->blocks.last_node ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( b4lastpos( block_on ) == -b4leaf( block_on ) )
 | |
|     e4severe( e4info, E4_INFO_UNE ) ;
 | |
| #endif
 | |
| 
 | |
|   switch( t4get_replace_entry( t4, b4key( block_on, block_on->key_on ), block_on ) )
 | |
|   {
 | |
|   case 0 :   /* leaf delete */
 | |
|     b4remove( block_on ) ;
 | |
|     if ( block_on->n_keys == 0 )  /* last entry deleted! -- remove upward reference */
 | |
|     {
 | |
|       if ( t4remove_ref( t4 ) != 0 )
 | |
|         return -1 ;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if ( block_on->n_keys < t4->header.keys_half && block_on->file_block != t4->header.root )  /* if not root may have to balance the tree */
 | |
|         return t4balance( t4, block_on, 0 ) ;
 | |
|     }
 | |
|     break ;
 | |
| 
 | |
|   case 1 :   /* branch delete */
 | |
|     /*         block_on->changed = 1 ;*/  /* mark as changed for all entries */
 | |
|     if( t4block( t4 )->n_keys == 0 )    /* removed the last key of */
 | |
|       if ( t4remove_ref( t4 ) != 0 )
 | |
|         return -1 ;
 | |
|     break ;
 | |
| 
 | |
|   default:
 | |
|     e4severe( e4info, E4_INFO_INT ) ;
 | |
|     break ;
 | |
|   }
 | |
|   return 0 ;
 | |
| }
 | |
| #endif  /* S4CLIPPER */
 | |
| #endif  /* S4NDX */
 | |
| #endif  /* N4OTHER */
 | |
| 
 | |
| #endif  /* S4INDEX_OFF */
 | |
| #endif  /* S4OFF_WRITE */
 |