/* b4block.c  (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */

#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif  /* __TURBOC__ */
#endif  /* S4UNIX */

#ifndef S4INDEX_OFF

#ifdef S4FOX
#define S4REVERSE_FUNC
#endif
#ifdef S4BYTE_SWAP
#define S4REVERSE_FUNC
#endif

#ifdef S4REVERSE_FUNC
short S4FUNCTION x4reverse_short( void * val )
{
  unsigned char out[2], *at_val ;
  at_val = (unsigned char *)val ;

  out[0] = at_val[1] ;
  out[1] = at_val[0] ;

  return (*(short *)out ) ;
}

S4LONG S4FUNCTION x4reverse_long( void * val )
{
  unsigned char out[4], *at_val ;
  at_val = (unsigned char *)val ;

#ifdef S4BYTEORDER_2301
  out[0] = at_val[2] ;
  out[1] = at_val[3] ;
  out[2] = at_val[0] ;
  out[3] = at_val[1] ;
#else
  out[0] = at_val[3] ;
  out[1] = at_val[2] ;
  out[2] = at_val[1] ;
  out[3] = at_val[0] ;
#endif

  return *(S4LONG *)out ;
}
#endif

B4BLOCK * S4FUNCTION b4alloc( TAG4 *t4, long fb )
{
  B4BLOCK *b4 ;
#ifdef S4CLIPPER
  short offset ;
  int i ;
#endif  /* S4CLIPPER */

  b4 = (B4BLOCK *)mem4alloc2( t4->index->block_memory, t4->code_base ) ;
  if ( b4 == 0 )
  {
    e4( t4->code_base, e4memory, E4_B4ALLOC ) ;
    return 0 ;
  }

  b4->tag = t4 ;
  b4->file_block = fb ;

#ifdef S4CLIPPER
  offset = ( b4->tag->header.keys_max + 2 +
            (( b4->tag->header.keys_max / 2) * 2 != b4->tag->header.keys_max ) )
    * sizeof(short) ;
  for ( i = 0 ; i <= b4->tag->header.keys_max ; i++ )
    b4->pointers[i] = (short)(( b4->tag->header.group_len * i )) + offset ;
  b4->data = (B4KEY_DATA *) ((char *)&b4->n_keys + b4->pointers[0]) ;  /* first entry */
#endif  /* S4CLIPPER */

#ifdef S4FOX
  b4->built_key = (B4KEY_DATA *)u4alloc_er( t4->code_base, sizeof(long) + t4->header.key_len + 1 ) ;
  b4->built_on = -1 ;
#endif  /* S4FOX */

  return b4 ;
}

void S4FUNCTION b4free( B4BLOCK *b4 )
{
#ifdef S4FOX
#ifdef S4DEBUG
  if ( b4->changed )
    e4severe( e4info, E4_B4FREE ) ;
#endif  /* S4DEBUG */
  u4free( b4->built_key ) ;
#endif /* S4FOX */

  mem4free( b4->tag->index->block_memory, b4 ) ;
}

#ifdef S4NDX

#ifndef S4OFF_WRITE
int S4FUNCTION b4find( TAG4 *tag, long f_block, B4BLOCK *out_block )
{
  B4BLOCK *cur_block ;

  cur_block = (B4BLOCK *)l4first( &tag->blocks ) ;
  if ( cur_block != 0 )
    do
    {
      if ( cur_block->file_block == f_block )
      {
        memcpy( &(out_block->changed), &(cur_block->changed), (B4BLOCK_SIZE + 2*sizeof(int)) ) ;
        out_block->changed = 0 ;
        return( 0 ) ;
      }
      cur_block = (B4BLOCK *)l4next( &tag->blocks, cur_block ) ;
    } while ( cur_block != 0 ) ;

  cur_block = (B4BLOCK *)l4first( &tag->saved ) ;

  if ( cur_block != 0 )
    do
    {
      if ( cur_block->file_block == f_block )
      {
        memcpy( &(out_block->changed), &(cur_block->changed), (B4BLOCK_SIZE + 2*sizeof(int)) ) ;
        out_block->changed = 0 ;
        return 0 ;
      }
      cur_block = (B4BLOCK *)l4next( &tag->saved, cur_block ) ;
    } while ( cur_block != 0 ) ;

  return -1 ;
}

int S4FUNCTION b4get_last_key( B4BLOCK *b4, char *key_info )
{
  int rc ;
  long block_down ;
  B4BLOCK *temp_block ;
  char *key_data ;

#ifdef S4DEBUG
  if ( b4leaf( b4 ) )
    e4severe( e4info, E4_B4GET_LK ) ;
#endif  /* S4DEBUG */

  block_down = b4key( b4, b4->key_on )->pointer ;

  temp_block = b4alloc( b4->tag, block_down ) ;
  if ( temp_block == 0 )
    return -1 ;

  do
  {
#ifdef S4DEBUG
    if ( block_down <= 0L )
      e4severe( e4info, E4_B4GET_LK ) ;
#endif  /* S4DEBUG */

    if ( b4find( b4->tag, block_down, temp_block ) < 0 )
    {
      if ( file4len( &b4->tag->file ) <= I4MULTIPLY * block_down )
      {
        b4free(temp_block) ;
        return -1 ;
      }
      else
      {
        if ( file4read_all( &b4->tag->file, I4MULTIPLY * block_down, &temp_block->n_keys, B4BLOCK_SIZE ) < 0 )
        {
          b4free(temp_block) ;
          return -1 ;
        }
        temp_block->file_block = block_down ;
      }
    }

    temp_block->key_on = b4lastpos( temp_block ) ;
    block_down = b4key( temp_block, temp_block->key_on )->pointer ;
  } while( !( b4leaf( temp_block ) ) ) ;

  key_data = (char *)b4key_key( temp_block, temp_block->key_on ) ;

  if( strcmp( key_info, key_data ) != 0 )
  {
    strcpy( key_info, key_data ) ;
    rc = 1 ;
  }
  else
    rc = 0 ;

  b4free( temp_block ) ;

  return rc ;
}
#endif  /* S4OFF_WRITE */

#endif  /* S4NDX */

#ifdef S4MDX

/* S4MDX */
#ifndef S4OFF_WRITE
int S4FUNCTION b4flush( B4BLOCK *b4 )
{
  int rc ;
  INDEX4 *i4 ;
#ifdef S4BYTE_SWAP
  char *swap, *swap_ptr ;
  int i ;
  S4LONG long_val ;
  short short_val ;
#endif  /* S4BYTE_SWAP */

  if ( b4->changed )
  {
#ifdef S4INDEX_VERIFY
    if ( b4verify( b4 ) == -1 )
      e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4flush()", "" ) ;
#endif
    i4 = b4->tag->index ;

#ifdef S4BYTE_SWAP
    swap = (char *) u4alloc_er( b4->tag->code_base, b4->tag->index->header.block_rw ) ;
    if ( swap == 0 )
      return -1 ;

    memcpy( (void *)swap, (void *)&b4->n_keys, b4->tag->index->header.block_rw ) ;
    /* position swap_ptr at beginning of B4KEY's */
    swap_ptr = swap ;
    swap_ptr += 6 + sizeof(short) ;
    /* move through all B4KEY's to swap 'long' */
    for ( i = 0 ; i < (*(short *)swap) ; i++ )
    {
      long_val = x4reverse_long( (void *)swap_ptr ) ;
      memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
      swap_ptr += b4->tag->header.group_len ;
    }
    /* mark last_pointer */
    if ( !b4leaf( b4 ) )
    {
      long_val = x4reverse_long( (void *)swap_ptr ) ;
      memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
    }
    /* swap the num_keys value */
    short_val = x4reverse_short( (void *)swap ) ;
    memcpy( swap, (void *) &short_val, sizeof(short) ) ;

    rc = file4write( &i4->file, (long)b4->file_block*I4MULTIPLY, swap, i4->header.block_rw) ;
    u4free( swap ) ;
#else
    rc = file4write( &i4->file, (long)b4->file_block*I4MULTIPLY, &b4->n_keys, i4->header.block_rw) ;
#endif  /* S4BYTE_SWAP */

    if ( rc < 0 )
      return rc ;
    b4->changed = 0 ;
  }
  return 0 ;
}
#endif /* S4OFF_WRITE */

/* S4MDX */
void S4FUNCTION b4go_eof( B4BLOCK *b4 )
{
  b4->key_on = b4->n_keys ;
}

/* S4MDX */
#ifndef S4OFF_WRITE
void S4FUNCTION b4insert( B4BLOCK *b4, void *k, long r )
{
#ifdef S464BIT
  S4LONG temp_r ;
#endif
  int left_len ;
  B4KEY_DATA *data_ptr, *next_ptr ;

#ifdef S4DEBUG
  if ( k == 0 || r <= 0L )
    e4severe( e4parm, E4_B4INSERT ) ;
#endif  /* S4DEBUG */

  data_ptr = b4key( b4, b4->key_on ) ;
  next_ptr = b4key( b4, b4->key_on+1 ) ;
  left_len = b4->tag->index->header.block_rw - ( b4->key_on + 1 ) * b4->tag->header.group_len - sizeof(short) - sizeof(char[6]) ;

#ifdef S4DEBUG
  if ( b4->key_on < 0  ||  b4->key_on > b4->n_keys  ||  left_len < 0 )
    e4severe( e4info, E4_B4INSERT ) ;
#endif  /* S4DEBUG */

  memmove( next_ptr, data_ptr, left_len ) ;
  b4->n_keys++ ;
  memcpy( data_ptr->value, k, b4->tag->header.key_len ) ;
#ifdef S464BIT
  temp_r = (S4LONG) r ;
  memcpy( (void *)&data_ptr->num, (void *)&temp_r, sizeof(temp_r) ) ;
#else
  memcpy( (void *)&data_ptr->num, (void *)&r, sizeof(r) ) ;
#endif
  b4->changed = 1 ;
}
#endif /* S4OFF_WRITE */

/* S4MDX */
B4KEY_DATA *S4FUNCTION b4key( B4BLOCK *b4, int i_key )
{
  return  (B4KEY_DATA *) ((char *) &b4->info.num + b4->tag->header.group_len * i_key) ;
}

/* S4MDX */
unsigned char *S4FUNCTION b4key_key( B4BLOCK *b4, int i_key )
{
  return (unsigned char *)( ( (B4KEY_DATA *)( (char *)&b4->info.num + b4->tag->header.group_len * i_key ) )->value ) ;
}

/* S4MDX */
int S4FUNCTION b4lastpos( B4BLOCK *b4 )
{
  if ( b4leaf(b4) )
    return b4->n_keys - 1 ;
  else
    return b4->n_keys ;
}

/* S4MDX */
int S4FUNCTION b4leaf( B4BLOCK *b4 )
{
  return( b4key( b4, b4->n_keys )->num == 0L ) ;
}

/* S4MDX */
long S4FUNCTION b4recno( B4BLOCK *b4, int i )
{
  return b4key( b4, i )->num ;
}

/* S4MDX */
#ifndef S4OFF_WRITE
void S4FUNCTION b4remove( B4BLOCK *b4 )
{
  B4KEY_DATA *key_cur, *key_next ;
  int left_len ;

  key_cur = b4key( b4, b4->key_on ) ;
  key_next = b4key( b4, b4->key_on + 1 ) ;

  left_len = b4->tag->index->header.block_rw - sizeof(b4->n_keys) - sizeof(b4->dummy)
    - (b4->key_on+1) * b4->tag->header.group_len ;

#ifdef S4DEBUG
  if ( b4->key_on < 0  ||  b4->key_on > b4lastpos(b4) )
    e4severe( e4info, E4_B4REMOVE ) ;
#endif  /* S4DEBUG */

  if ( left_len > 0 )
    memmove( key_cur, key_next, left_len ) ;

  b4->n_keys-- ;
  b4->changed = 1 ;

  if ( b4leaf( b4 ) )
    memset( b4key_key( b4, b4->n_keys ), 0, b4->tag->header.key_len ) ;
#ifdef S4DEBUG
  else
    if ( b4->n_keys < b4->tag->header.keys_max )
      memset( b4key_key( b4, b4->n_keys ), 0, b4->tag->header.key_len ) ;
#endif
}
#endif /* S4OFF_WRITE */

/* S4MDX */
int S4FUNCTION b4seek( B4BLOCK *b4, char *search_value, int len )
{
  int rc, key_lower, key_upper, save_rc, key_cur ;
  S4CMP_FUNCTION *cmp;

  /* key_cur must be between  key_lower and  key_upper */
  key_lower = -1 ;
  key_upper = b4->n_keys ;

  cmp = b4->tag->cmp ;

  if ( key_upper == 0 )
  {
    b4->key_on = 0 ;
    return r4after ;
  }

  save_rc = 1 ;

  for(;;)  /* Repeat until the key is found */
  {
    key_cur  = (key_upper + key_lower) / 2  ;
    rc = (*cmp)( b4key_key(b4,key_cur), search_value, len ) ;

    if ( rc >= 0 )
    {
      key_upper = key_cur ;
      save_rc = rc ;
    }
    else
      key_lower = key_cur ;

    if ( key_lower >= (key_upper-1) )  /* then there is no exact match */
    {
      b4->key_on =  key_upper ;
      if ( save_rc )
        return r4after ;
      return 0 ;
    }
  }
}

/* S4MDX */
int S4FUNCTION b4skip( B4BLOCK *b4, long n )
{
  int num_left ;

  if ( n > 0 )
  {
    num_left = b4->n_keys - b4->key_on ;
    if ( b4leaf(b4) )
      if ( num_left != 0 )
        num_left -- ;
  }
  else
    num_left = -b4->key_on ;

  if ( ( n <= 0L ) ?  ((long) num_left <= n)  :  ((long) num_left >= n)  )
  {
    b4->key_on = b4->key_on+ (int)n ;
    return (int)n ;
  }
  else
  {
    b4->key_on = b4->key_on + num_left ;
    return num_left ;
  }
}
#endif  /* S4MDX */

#ifdef S4FOX

/* S4FOX */
void S4FUNCTION b4leaf_init( B4BLOCK *b4 )
{
  TAG4 *t4 ;
  int t_len ;
  unsigned c_len, key_len ;
  unsigned long ff, r_len ;

  t4 = b4->tag ;
  key_len = t4->header.key_len ;
  ff = 0xFFFFFFFF ;

  for ( c_len = 0 ; key_len ; key_len >>= 1, c_len++ ) ;

  key_len = t4->header.key_len ;
  b4->node_hdr.trail_cnt_len = b4->node_hdr.dup_cnt_len = (unsigned char)c_len ;

  b4->node_hdr.trail_byte_cnt = (unsigned char)((unsigned char)0xFF >> (8 - c_len % 8) ) ;
  b4->node_hdr.dup_byte_cnt = b4->node_hdr.trail_byte_cnt ;

  r_len = d4reccount( b4->tag->index->data ) ;

  for ( c_len = 0 ; r_len ; r_len>>=1, c_len++ ) ;

  b4->node_hdr.rec_num_len = (unsigned char) (c_len + (( 8 - ( 2 * (unsigned int)b4->node_hdr.trail_cnt_len % 8 )) % 8)) ;
  if ( b4->node_hdr.rec_num_len < 12 )
    b4->node_hdr.rec_num_len = 12 ;

  for( t_len = b4->node_hdr.rec_num_len + b4->node_hdr.trail_cnt_len + b4->node_hdr.dup_cnt_len ;
      (t_len / 8)*8 != t_len ; t_len++, b4->node_hdr.rec_num_len++ ) ;  /* make at an 8-bit offset */

  r_len = ff >> ( sizeof(long)*8 - b4->node_hdr.rec_num_len ) ;
  memcpy( (void *)&b4->node_hdr.rec_num_mask[0], (void *)&r_len, sizeof(long) ) ;

  b4->node_hdr.info_len = (unsigned char)((unsigned int)(b4->node_hdr.rec_num_len + b4->node_hdr.trail_cnt_len + b4->node_hdr.dup_cnt_len) / 8) ;
  b4->node_hdr.free_space = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - sizeof( B4NODE_HEADER ) ;
}

/* S4FOX */
int S4FUNCTION b4calc_blanks( char *key_val, int len, char p_char )
{
  int a ;

  for ( a = len ; a > 0; a-- )
    if ( key_val[a-1] != p_char )
      return ( len - a ) ;
  return len ;  /* all blanks */
}

/* S4FOX */
int S4FUNCTION b4calc_dups( char *ptr1, char *ptr2, int len )
{
  int a ;
  for ( a = 0 ; a < len; a++ )
    if ( ptr1[a] != ptr2[a] )
      return a ;
  return len ;  /* all duplicates */
}


/* S4FOX */
long S4FUNCTION x4recno( B4BLOCK *b4, int num_in_block )
{
#ifdef S4UNIX
  unsigned long long_ptr ;
  unsigned long long_val ;

  memcpy( (void *)&long_ptr , b4->data + num_in_block * b4->node_hdr.info_len , sizeof(long) ) ;
#ifdef S4DO_BYTEORDER
  long_ptr = x4reverse_long( (void *)&long_ptr ) ;
#endif

  memcpy( (void *)&long_val , (void *)&b4->node_hdr.rec_num_mask[0], sizeof(long) ) ;
  return ( long_ptr & long_val ) ;
#else
  unsigned long * l_ptr ;

  l_ptr = (unsigned long *)( b4->data + num_in_block * b4->node_hdr.info_len ) ;
  return ( *l_ptr & *(long *)&b4->node_hdr.rec_num_mask[0] ) ;
#endif
}

/* S4FOX */
int S4FUNCTION x4dup_cnt( B4BLOCK *b4, int num_in_block )
{
  int pos ;
#ifdef S4UNIX
  unsigned long long_ptr ;
#else
  unsigned long * l_ptr ;
#endif

  if ( b4->node_hdr.info_len > 4 )  /* > size of long, so must do careful shifting and copying */
  {
#ifdef S4DEBUG
    if ( b4->node_hdr.rec_num_len <= 16 )
      e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */
#ifdef S4UNIX
    memcpy( (void *)&long_ptr , b4->data + num_in_block * b4->node_hdr.info_len + 2, sizeof(long) ) ;
#else
    l_ptr = (unsigned long *)( b4->data + num_in_block * b4->node_hdr.info_len + 2 ) ;
#endif
    pos = b4->node_hdr.rec_num_len - 16 ;
  }
  else
  {
#ifdef S4UNIX
    memcpy( (void *)&long_ptr , b4->data + num_in_block * b4->node_hdr.info_len , sizeof(long) ) ;
#else
    l_ptr = (unsigned long *)( b4->data + num_in_block * b4->node_hdr.info_len ) ;
#endif
    pos = b4->node_hdr.rec_num_len ;
  }

#ifdef S4UNIX
#ifdef S4DO_BYTEORDER
  long_ptr = x4reverse_long( (void *)&long_ptr ) ;
#endif
  return (int)( ( long_ptr >> pos ) & b4->node_hdr.dup_byte_cnt ) ;
#else
  return (int)( ( *l_ptr >> pos ) & b4->node_hdr.dup_byte_cnt ) ;
#endif
}

/* S4FOX */
int S4FUNCTION x4trail_cnt( B4BLOCK *b4, int num_in_block )
{
  int pos ;
#ifdef S4UNIX
  unsigned long long_ptr ;
#else
  unsigned long * l_ptr ;
#endif

  if ( b4->node_hdr.info_len > 4 )  /* > size of long, so must do careful shifting and copying */
  {
#ifdef S4DEBUG
    if ( b4->node_hdr.rec_num_len <= 16 )
      e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */
#ifdef S4UNIX
    memcpy( (void *)&long_ptr , b4->data + num_in_block * b4->node_hdr.info_len + 2, sizeof(long) ) ;
#else
    l_ptr = (unsigned long *)( b4->data + num_in_block * b4->node_hdr.info_len + 2 ) ;
#endif
    pos = b4->node_hdr.rec_num_len - 16 + b4->node_hdr.dup_cnt_len ;
  }
  else
  {
#ifdef S4UNIX
    memcpy( (void *)&long_ptr , b4->data + num_in_block * b4->node_hdr.info_len , sizeof(long) ) ;
#else
    l_ptr = (unsigned long *)( b4->data + num_in_block * b4->node_hdr.info_len ) ;
#endif
    pos = b4->node_hdr.rec_num_len + b4->node_hdr.dup_cnt_len;
  }

#ifdef S4UNIX
#ifdef S4DO_BYTEORDER
  long_ptr = x4reverse_long( (void *)&long_ptr ) ;
#endif
  return (int)( ( long_ptr >> pos ) & b4->node_hdr.trail_byte_cnt ) ;
#else
  return (int)( ( *l_ptr >> pos ) & b4->node_hdr.trail_byte_cnt ) ;
#endif
}


/* S4FOX */
#ifndef S4OFF_WRITE

void S4FUNCTION x4put_info( B4NODE_HEADER *b4node_hdr, void *buffer, long rec, int trail, int dup_cnt )
{
  int pos ;
  unsigned char *buf ;
  unsigned long *l_ptr ;
#ifdef S4UNIX
  char unix_buf[6] ;
  char unix_buf2[4] ;
  long long_val, long_temp ;
  int do_shift = 0 ;
#endif

#ifdef S4UNIX
  memset( unix_buf, 0, 6 ) ;
  memcpy( (void *)&long_temp , (void *)&b4node_hdr->rec_num_mask[0], sizeof(long) ) ;
  long_val = rec & long_temp ;
#ifdef S4DO_BYTEORDER
  long_val = x4reverse_long( (void *)&long_val ) ;
#endif
  memcpy( unix_buf, (void *)&long_val, sizeof(long) ) ;
#else
  buf = (unsigned char *) buffer ;
  l_ptr = (unsigned long *)buf ;
  memset( buf, 0, 6 ) ;
  *l_ptr = rec & *(long *)&b4node_hdr->rec_num_mask[0] ;
#endif

  if ( b4node_hdr->info_len > 4 )  /* > size of long, so must do careful shifting and copying */
  {
#ifdef S4DEBUG
    if ( b4node_hdr->rec_num_len <= 16 )
      e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */
#ifndef S4UNIX
    l_ptr = (unsigned long *)( buf + 2 ) ;  /* start at new pos */
#endif
    pos = b4node_hdr->rec_num_len - 16 ;
#ifdef S4UNIX
    do_shift = 1 ;
#endif
  }
  else
    pos = b4node_hdr->rec_num_len ;

#ifdef S4UNIX
  long_val = ((unsigned long)dup_cnt) << pos ;
  pos += b4node_hdr->dup_cnt_len ;
  long_val |= ((unsigned long)trail) << pos ;
#ifdef S4DO_BYTEORDER
  long_val = x4reverse_long( (void *)&long_val ) ;
#endif
  memcpy( unix_buf2, (void *)&long_val, sizeof(long) ) ;
  if (do_shift)
  {
    unix_buf[2] |= unix_buf2[0] ;  /* must OR bytes 2 and 3 of 'buf' */
    unix_buf[3] |= unix_buf2[1] ;
    unix_buf[4] = unix_buf2[2] ;
    unix_buf[5] = unix_buf2[3] ;
  }
  else
  {
    unix_buf[0] |= unix_buf2[0] ;
    unix_buf[1] |= unix_buf2[1] ;
    unix_buf[2] |= unix_buf2[2] ;
    unix_buf[3] |= unix_buf2[3] ;
  }
  memcpy( (void *)buffer, unix_buf, 6 ) ;
#else
  *l_ptr |= ((unsigned long)dup_cnt) << pos ;
  pos += b4node_hdr->dup_cnt_len ;
  *l_ptr |= ((unsigned long)trail) << pos ;
#endif
}


/* S4FOX */
int S4FUNCTION b4insert_leaf( B4BLOCK *b4, void *vkey_data, long rec )
{
  int left_blanks, right_blanks, left_dups, right_dups, left_len, right_len, reqd_len, mov_len, old_rec, rc, old_right_dups, extra_dups, save_dups ;
  unsigned char buffer[6], i_len ;
  char *key_data, *info_pos, a, b ;
  int key_len ;
  unsigned int rec_len ;
  unsigned long mask ;
#ifdef S4UNIX
  long long_val ;
#endif

  i_len = b4->node_hdr.info_len ;
  key_data = (char *)vkey_data ;
  key_len = b4->tag->header.key_len ;
  b4->built_on = -1 ;

  if ( b4->header.n_keys == 0 )
  {
    if( b4->node_hdr.free_space == 0 )  /* block needs initialization */
    {
      b4leaf_init( b4 ) ;
      i_len = b4->node_hdr.info_len ;
    }
    left_blanks = b4calc_blanks( key_data, key_len, b4->tag->p_char ) ;
    left_dups = 0 ;
    reqd_len = key_len - left_blanks ;
    b4->key_on = 0 ;
    b4->cur_pos = ((char *)&b4->header) + B4BLOCK_SIZE - reqd_len ;
    memcpy( b4->cur_pos, key_data, reqd_len ) ;  /* key */
    x4put_info( &b4->node_hdr, buffer, rec, left_blanks, 0 ) ;
    memcpy( b4->data, (void *)buffer, i_len ) ;
  }
  else
  {
    /* if the record is > than the mask, must reset the block with new parameters: */
    b = sizeof( long ) * 8 ;
    mask = 0x01L << (b-1) ;    /* set leftmost bit  */

    for( rec_len = 0, a = 0 ; a < b ; a++ )
    {
      if ( rec & mask )
      {
        rec_len = b - a ;
        break ;
      }
      mask >>= 1 ;
    }

    if ( rec_len > b4->node_hdr.rec_num_len )
    {
      old_rec = b4->key_on ;
      save_dups = b4->cur_dup_cnt ;
      rc = b4reindex( b4 ) ;
      if (rc )
        return rc ;
      i_len = b4->node_hdr.info_len ;
      b4top( b4 ) ;
      b4skip( b4, old_rec ) ;
      b4->cur_dup_cnt = save_dups ;
    }

    left_blanks = b4calc_blanks( key_data, key_len, b4->tag->p_char ) ;

    if ( b4->key_on == b4->header.n_keys )  /* at end */
    {
      left_dups = b4->cur_dup_cnt ;
      reqd_len = key_len - left_blanks - b4->cur_dup_cnt ;
      if ( (int)b4->node_hdr.free_space < ( reqd_len + (int)i_len ) )  /* no room to add */
        return 1 ;
      b4->cur_pos -= reqd_len ;
      memcpy( b4->cur_pos, key_data + b4->cur_dup_cnt, reqd_len ) ;  /* key */
      x4put_info( &b4->node_hdr, buffer, rec, left_blanks, left_dups ) ;
      memcpy( b4->data + b4->key_on * i_len , (void *)buffer, i_len ) ;
    }
    else
    {
      right_blanks = x4trail_cnt( b4, b4->key_on ) ;

      if ( b4->key_on == 0 )   /* insert at top */
      {
        old_right_dups = 0 ;
        right_dups = b4calc_dups( key_data, b4->cur_pos, key_len - ( right_blanks > left_blanks ? right_blanks : left_blanks ) ) ;
        extra_dups = right_dups ;
        left_dups = 0 ;
      }
      else /* insert in middle of block */
      {
        old_right_dups = x4dup_cnt( b4, b4->key_on) ;
        extra_dups = b4calc_dups( key_data + old_right_dups, b4->cur_pos, key_len - ( right_blanks > left_blanks ? right_blanks : left_blanks ) - old_right_dups ) ;
        right_dups = old_right_dups + extra_dups ;
        left_dups = b4->cur_dup_cnt ;
      }

#ifdef S4DEBUG_DEV
      if ( b4->tag->header.type_code & 0x01 )
        if ( left_dups == b4->tag->header.key_len || right_dups == b4->tag->header.key_len )
          e4severe( e4info, "b4insert_leaf() - duplicate key being inserted in unique index" ) ;
#endif

      right_len = key_len - right_blanks - right_dups ;
      left_len = key_len - left_dups - left_blanks ;
      reqd_len = left_len - extra_dups ;

#ifdef S4DEBUG
      if ( reqd_len < 0 )
        e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */

      if ( (int)b4->node_hdr.free_space < (reqd_len + (int)i_len) )  /* no room to add */
        return 1 ;


      if ( reqd_len != 0 )  /* shift data over */
      {
        mov_len = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - i_len * b4->header.n_keys
          - sizeof( B4NODE_HEADER ) - b4->node_hdr.free_space
            - ( ( (char *)&b4->header ) + B4BLOCK_SIZE - b4->cur_pos ) ;

#ifdef S4DEBUG
        if ( mov_len < 0 )
          e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */

        /* move and put keys */
        memmove( b4->cur_pos - mov_len - reqd_len, b4->cur_pos - mov_len, mov_len ) ;
      }
      b4->cur_pos += ( key_len - right_blanks - old_right_dups ) ;
      memcpy( b4->cur_pos - left_len - right_len, b4->cur_pos - ( key_len - right_dups - right_blanks ), right_len ) ;
      b4->cur_pos -= left_len ;
      memcpy( b4->cur_pos, key_data + left_dups, left_len ) ;

      /* move and put info */
      info_pos = b4->data + ( b4->key_on ) * i_len ;
      memmove( info_pos + i_len, info_pos ,i_len * ( b4->header.n_keys - b4->key_on ) ) ;
      x4put_info( &b4->node_hdr, buffer, rec, left_blanks, left_dups ) ;
      memcpy( info_pos, (void *)buffer, i_len ) ;
      x4put_info( &b4->node_hdr, buffer, x4recno( b4, b4->key_on + 1 ), right_blanks, right_dups ) ;
      memcpy( info_pos + i_len, (void *)buffer, i_len ) ;
    }
  }

  b4->changed = 1 ;
  b4->header.n_keys++ ;
  b4->node_hdr.free_space -= (short) (reqd_len + (int)i_len ) ;
  b4->cur_dup_cnt = left_dups ;
  b4->cur_trail_cnt = left_blanks ;
  return 0 ;
}

/* S4FOX */
int S4FUNCTION b4insert_branch( B4BLOCK *b4, void *k, long r, long r2, char new_flag )
{
  int left_len, move_len, g_len ;
  char *data_ptr, *next_ptr ;

  g_len = b4->tag->header.key_len + 2 * sizeof(long) ;

#ifdef S4DEBUG
  if ( k == 0 || r <= 0L )
    e4severe( e4parm, E4_B4INSERT_BR ) ;
#endif  /* S4DEBUG */

  data_ptr = ((char *)&b4->node_hdr) + b4->key_on * g_len ;
  next_ptr = data_ptr + g_len ;

  left_len = B4BLOCK_SIZE - sizeof( b4->header ) - g_len * b4->header.n_keys ;
  if ( left_len < g_len )  /* not enough room */
    return 1 ;

#ifdef S4DEBUG
  if ( b4->key_on < 0  ||  b4->key_on > b4->header.n_keys )
    e4severe( e4info, E4_B4INSERT_BR ) ;
#endif  /* S4DEBUG */

  move_len = g_len * (b4->header.n_keys - b4->key_on) ;

  memmove( next_ptr, data_ptr, move_len ) ;
  b4->header.n_keys++ ;
  memcpy( data_ptr, k, b4->tag->header.key_len ) ;
  memset( data_ptr + g_len - 2*sizeof(long), 0, sizeof(long) ) ;

  r2 = x4reverse_long( (void *)&r2 ) ;
  memcpy( data_ptr + g_len - 2*sizeof(long), (void *)&r2, sizeof(long) ) ;

  r = x4reverse_long( (void *)&r ) ;

  if ( !new_flag &&  (b4->key_on + 1) != b4->header.n_keys )
    memcpy(  next_ptr + g_len - sizeof(long), (void *)&r, sizeof(long) ) ;
  else
    memcpy( data_ptr + g_len - sizeof(long), (void *)&r, sizeof(long) ) ;

  b4->changed = 1 ;

  return 0 ;
}

/* S4FOX */
int S4FUNCTION b4insert( B4BLOCK *b4, void *key_data, long rec, long rec2, char new_flag )
{
  if( b4->header.node_attribute >= 2 ) /* leaf */
    return b4insert_leaf( b4, key_data, rec ) ;
  else
    return b4insert_branch( b4, key_data, rec, rec2, new_flag ) ;
}

/* S4FOX */
int S4FUNCTION b4reindex( B4BLOCK *b4 )
{
  int i, dup_cnt, trail ;
  int ni_len = b4->node_hdr.info_len + 1 ;
  unsigned char buffer[6] ;
  long rec ;
  int space_reqd = b4->header.n_keys ;   /* 1 byte extra for each record */
  if ( space_reqd > b4->node_hdr.free_space )  /* not enough room */
    return 1 ;

  for ( i = b4->header.n_keys-1 ; i >= 0 ; i-- )
  {
    dup_cnt = x4dup_cnt( b4, i ) ;
    trail = x4trail_cnt( b4, i ) ;
    rec = x4recno( b4, i ) ;
    memset( b4->data + i * ni_len, 0, ni_len ) ;

    b4->node_hdr.rec_num_len += 8 ;  /* for the new info */
    b4->node_hdr.info_len++ ;
    x4put_info( &b4->node_hdr, buffer, rec, trail, dup_cnt ) ;
    b4->node_hdr.rec_num_len -= 8 ;  /* to get the old info */
    b4->node_hdr.info_len-- ;
    memcpy( b4->data + i * ni_len, (void *)buffer, ni_len ) ;
  }

  memcpy( (void *)&rec, (void *)&b4->node_hdr.rec_num_mask[0], sizeof(long) ) ;
  rec |= (0x000000FFL << b4->node_hdr.rec_num_len ) ;
  memcpy( (void *)&b4->node_hdr.rec_num_mask[0], (void *)&rec, sizeof(long) ) ;

  b4->node_hdr.info_len++ ;
  b4->node_hdr.rec_num_len += 8 ;
  b4->node_hdr.free_space -= b4->header.n_keys ;
  return 0 ;
}

/* S4FOX */
int S4FUNCTION b4flush( B4BLOCK *b4 )
{
  int rc ;
  INDEX4 *i4 ;
#ifdef S4BYTE_SWAP
  char swap[B4BLOCK_SIZE] ;
  char *swap_ptr ;
  int i ;
  S4LONG long_val ;
  short short_val ;
#endif

  if ( b4->changed )
  {
    i4 = b4->tag->index ;

#ifdef S4BYTE_SWAP
    memcpy( (void *)swap, (void *)&b4->header.node_attribute, B4BLOCK_SIZE ) ;

    /* position at either B4NODE_HEADER (leaf) or data (branch) */
    swap_ptr = swap + 2 * sizeof( short) + 2 * sizeof(S4LONG) ;

    /* if block is a leaf */
    if (b4->header.node_attribute >= 2 )
    {
      /* swap B4NODE_HEADER members */
      short_val = x4reverse_short( (void *)swap_ptr ) ; /* free_space */
      memcpy( swap_ptr, (void *) &short_val, sizeof(short) ) ;
      swap_ptr += sizeof(short) ;

      long_val = x4reverse_long( (void *)swap_ptr ) ;   /* rec_num_mask */
      memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
    }
    else                /* if block is a branch */
    {
      short_val = b4->tag->header.key_len + sizeof(S4LONG) ;

      /* position swap_ptr to end of first key expression */
      swap_ptr += b4->tag->header.key_len ;

      /* move through all B4KEY's to swap 'long's */
      for ( i = 0 ; i < (int) b4->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 ;
      }
    }

    /* reposition to B4STD_HEADER and swap members */
    swap_ptr = swap ;

    short_val = x4reverse_short( (void *)swap_ptr ) ; /* node_attribute */
    memcpy( swap_ptr, (void *) &short_val, sizeof(short) ) ;
    swap_ptr += sizeof(short) ;

    short_val = x4reverse_short( (void *)swap_ptr ) ; /* n_keys */
    memcpy( swap_ptr, (void *) &short_val, sizeof(short) ) ;
    swap_ptr += sizeof(short) ;

    long_val = x4reverse_long( (void *)swap_ptr ) ;   /* left_node */
    memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
    swap_ptr += sizeof(S4LONG) ;

    long_val = x4reverse_long( (void *)swap_ptr ) ;   /* right_node */
    memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
    swap_ptr += sizeof(S4LONG) ;

    rc = file4write( &i4->file, (long)b4->file_block * I4MULTIPLY, swap, B4BLOCK_SIZE ) ;
#else
    rc = file4write( &i4->file, (long)b4->file_block * I4MULTIPLY, &b4->header.node_attribute, B4BLOCK_SIZE ) ;
#endif

    if ( rc < 0 )
      return rc ;
    b4->changed = 0 ;
  }
  return 0 ;
}
#endif /* S4OFF_WRITE */

/* S4FOX */
void S4FUNCTION b4go( B4BLOCK *b4, int i_key )
{
  b4skip( b4, i_key - b4->key_on ) ;
}

/* S4FOX */
void S4FUNCTION b4top( B4BLOCK *b4 )
{
  b4->key_on = 0 ;
  if ( b4leaf( b4 ) )
  {
    b4->cur_dup_cnt = 0 ;
    b4->cur_pos = ((char *)&b4->header) + B4BLOCK_SIZE - b4->tag->header.key_len + x4trail_cnt( b4, 0 ) ;
  }
}

/* S4FOX */
void S4FUNCTION b4go_eof( B4BLOCK *b4 )
{
  b4->key_on = b4->header.n_keys ;
  b4->cur_pos = ((char *)&b4->header) + sizeof( B4STD_HEADER ) + sizeof( B4NODE_HEADER )
    + b4->header.n_keys * b4->node_hdr.info_len + b4->node_hdr.free_space ;
}

/* S4FOX */
B4KEY_DATA *S4FUNCTION b4key( B4BLOCK *b4, int i_key )
{
  int len ;

#ifdef S4DEBUG
  if ( i_key > b4->header.n_keys || i_key < 0 )
    e4severe( e4info, E4_INFO_CIF ) ;
#endif  /* S4DEBUG */

  if ( i_key == b4->built_on )   /* already there! */
    return b4->built_key ;

  if ( b4->header.node_attribute >= 2 ) /* leaf */
  {
    if ( b4->built_on > i_key || b4->built_on == -1 )
    {
      b4->built_on = -1 ;
      b4->built_pos = ((char *)&b4->header) + B4BLOCK_SIZE ;
    }

    for ( ; b4->built_on != i_key ; )
    {
      b4->built_on++ ;
      b4->cur_dup_cnt = x4dup_cnt( b4, b4->built_on ) ;
      b4->cur_trail_cnt = x4trail_cnt( b4, b4->built_on ) ;
      len = b4->tag->header.key_len - b4->cur_dup_cnt - b4->cur_trail_cnt ;
#ifdef S4DEBUG
      if (len < 0 || len > b4->tag->header.key_len || ( b4->built_pos - len ) < b4->data )
        e4severe( e4info, E4_INFO_CIF ) ;
#endif  /* S4DEBUG */
      b4->built_pos -= len ;
      memcpy( b4->built_key->value + b4->cur_dup_cnt, b4->built_pos, len ) ;
      memset( b4->built_key->value + b4->tag->header.key_len - b4->cur_trail_cnt, b4->tag->p_char, b4->cur_trail_cnt ) ;
    }
    b4->built_key->num = x4recno( b4, b4->key_on ) ;
  }
  else /* branch */
  {
    memcpy( b4->built_key->value, (((char *)&b4->node_hdr) + i_key*(2*sizeof( long ) + b4->tag->header.key_len ) ), b4->tag->header.key_len ) ;
    b4->built_key->num = x4reverse_long( (void *)( ((unsigned char *)&b4->node_hdr)
                                                  + (i_key+1)*(2*sizeof(long) + b4->tag->header.key_len)
                                                  - sizeof(long) ) ) ;
  }
  return b4->built_key ;
}

/* S4FOX */
unsigned char *S4FUNCTION b4key_key( B4BLOCK *b4, int i_key )
{
  return (unsigned char *)b4key( b4, i_key )->value ;
}

/* S4FOX */
int S4FUNCTION b4lastpos( B4BLOCK *b4 )
{
  return b4->header.n_keys - 1 ;
}

/* S4FOX */
int S4FUNCTION b4leaf( B4BLOCK *b4 )
{
  return( b4->header.node_attribute >= 2 ) ;
}

/* S4FOX */
long S4FUNCTION b4recno( B4BLOCK *b4, int i )
{
  if ( b4->header.node_attribute >= 2 ) /* leaf */
    return x4recno( b4, i ) ;
  else /* branch */
    return x4reverse_long( (void *)(((unsigned char *)&b4->node_hdr) +
                                    i * (2*sizeof(long) + b4->tag->header.key_len) + b4->tag->header.key_len ) ) ;
}

/* S4FOX */
#ifndef S4OFF_WRITE
void S4FUNCTION b4br_replace( B4BLOCK *b4, char *str, long rec )
{
  int key_len ;
  char *put_pl ;

  key_len = b4->tag->header.key_len ;
  put_pl = ( (char *)&b4->node_hdr ) + b4->key_on * ( 2 * sizeof( long ) + key_len ) ;
  memcpy( put_pl, str, key_len ) ;
  memcpy( b4->built_key->value, str, key_len ) ;
  memset( put_pl + key_len, 0, sizeof(long) ) ;
  rec = x4reverse_long( (void *)&rec ) ;
  memcpy( put_pl + key_len, (void *)&rec, sizeof(long) ) ;

  b4->changed = 1 ;
}
#endif /* S4OFF_WRITE */

/* S4FOX */
int S4FUNCTION b4r_brseek( B4BLOCK *b4, char *search_value, int len, long recno )
{
  int rc, key_len ;
#ifdef S4DO_BYTEORDER
  long long_val, lrecno ;
#endif

  rc = b4seek( b4, search_value, len ) ;
  key_len = b4->tag->header.key_len ;

  if ( rc == 0 )   /* string matches, so search on recno */
    for(;;)
    {
#ifdef S4DO_BYTEORDER
      lrecno = x4reverse_long( (void *)&recno ) ;
      long_val = x4reverse_long( (void *)(((char *)&b4->node_hdr) + b4->key_on * ( 2 * sizeof(long) + key_len) + key_len ) ) ;
      if ( u4memcmp( (void *)&lrecno, (void *)&long_val, sizeof(long) ) <= 0
#else
          if ( u4memcmp( (void *)&recno, ((char *)&b4->node_hdr) + b4->key_on * ( 2 * sizeof(long) + key_len) + key_len, sizeof(long) ) <= 0
#endif
              || b4->key_on >= ( b4->header.n_keys - 1 ) )  /* best match, so done */
          break ;
          else
          if( b4->key_on < b4->header.n_keys )
          b4skip( b4, 1L ) ;

          if ( u4memcmp( (void *)b4key_key(b4,b4->key_on), search_value, len ) )  /* the key has changed, so stop here */
          break ;
        }

      return rc ;
    }

  /* S4FOX */
  int S4FUNCTION b4seek( B4BLOCK *b4, char *search_value, int len )
  {
    int rc, key_lower, key_upper, save_rc, key_cur, group_val ;
    if ( b4->header.n_keys == 0 )
    {
      b4->key_on = 0 ;
      return r4after ;
    }

    if ( b4leaf( b4 ) )
      return b4leaf_seek( b4, search_value, len ) ;

    /* key_cur must be between  key_lower and  key_upper */
    key_lower = -1 ;
    key_upper = b4->header.n_keys - 1 ;

    save_rc = 1 ;
    group_val = 2 * sizeof( long ) + b4->tag->header.key_len ;

    for(;;)  /* Repeat until the key is found */
    {
      key_cur = (key_upper + key_lower) / 2 ;
      /* only memcmp for branch blocks */
      rc = u4memcmp( (((char *)&b4->node_hdr) + key_cur * group_val ), search_value, len ) ;

      if ( rc >= 0 )
      {
        key_upper = key_cur ;
        save_rc = rc ;
      }
      else
        key_lower = key_cur ;

      if ( key_lower >= (key_upper-1) )  /* then there is no exact match */
      {
        b4->key_on = key_upper ;   /* branch block, just change key_on */
        if ( save_rc )
          return r4after ;
        return 0 ;
      }
    }
  }

  /* S4FOX */
  int S4FUNCTION b4leaf_seek( B4BLOCK *b4, char *search_value, int len )
  {
    int duplicates, bytes_same, compare_len, key_len, original_len, significant_bytes, trail_cnt, done ;
    char all_blank ;

    original_len = len ;
    key_len = b4->tag->header.key_len ;
    len -= b4calc_blanks( search_value, len, b4->tag->p_char ) ;  /* don't compare blank bytes */
    if ( len == 0 )   /* if all blanks, watch for records < blank */
    {
      len = original_len ;
      all_blank = 1 ;
    }
    else
      all_blank = 0 ;
    duplicates = 0 ;
    b4top( b4 ) ;

    for(;;)
    {
      if ( b4->cur_dup_cnt == duplicates )
      {
        significant_bytes = key_len - x4trail_cnt( b4, b4->key_on ) ;
        if ( all_blank && significant_bytes == 0 )   /* found a blank record */
          len = 0 ;
        compare_len = ( len < significant_bytes ? len : significant_bytes ) - b4->cur_dup_cnt ;
        bytes_same = (*b4->tag->cmp)( b4->cur_pos, search_value + b4->cur_dup_cnt, compare_len ) ;

        if ( bytes_same == -1 )
          return r4after ;
        if ( bytes_same == compare_len )
        {
          if ( b4->cur_dup_cnt + bytes_same == len )  /* unless binary, for sure done */
          {
            if ( len == original_len )
              done = 1 ;
            else  /* in case of binary, we may not be done if values < blank */
            {
              trail_cnt = x4trail_cnt( b4, b4->key_on ) ;
              if ( significant_bytes > trail_cnt + len )  /* significant bytes beyond the trail, so check binary */
              {
                if ( memcmp( b4->cur_pos + compare_len, search_value + len, key_len - trail_cnt ) < 0 )  /* binaries */
                  done = 0 ;
                else
                  done = 1 ;

              }
              else
                done = 1 ;
            }   

            if ( done == 1 )
            {
              if ( len != original_len && significant_bytes > len )
              {
                if ( significant_bytes < original_len )
                  return r4after ;
#ifdef S4DEBUG
                if ( len > original_len )
                  e4severe( e4info, E4_B4LEAF_SEEK ) ;
#endif
                if ( (*b4->tag->cmp)( b4->cur_pos + compare_len, search_value + len, (original_len - len) ) != (original_len - len) )
                  return r4after ;
              }
              if ( all_blank != 1 )   /* not all blanks, so significants matter */
                b4->cur_dup_cnt += bytes_same ;
              else
                b4->cur_dup_cnt = 0 ;
              return 0 ;
            }
          }
        }

        b4->cur_dup_cnt += bytes_same ;
      }

      b4->key_on++ ;
      if ( b4->key_on >= b4->header.n_keys )
        return r4after ;
      duplicates = x4dup_cnt( b4, b4->key_on ) ;
      b4->cur_pos -= key_len - duplicates - x4trail_cnt( b4, b4->key_on ) ;
      if ( b4->cur_dup_cnt > duplicates )
        return r4after ;
    }
  }

  /* S4FOX */
#ifndef S4OFF_WRITE
  void S4FUNCTION b4remove_leaf( B4BLOCK *b4 )
  {
    int old_dup, left_dup, left_trail, key_len, remove_len, new_dup, old_bytes, new_bytes, mov_len, left_bytes ;
    unsigned char buffer[6], i_len ;
    char *old_pos, *info_pos ;

    b4->built_on = -1 ;

    if ( b4->header.n_keys == 1 )  /* removing last key */
    {
      b4->node_hdr.free_space = B4BLOCK_SIZE - sizeof( B4NODE_HEADER ) - sizeof( B4STD_HEADER ) ;
      memset( b4->data, 0, b4->node_hdr.free_space ) ;
      b4->header.n_keys = 0 ;
      b4->key_on = 0 ;
      b4->cur_pos = ((char *)&b4->header) + B4BLOCK_SIZE ;
      b4->changed = 1 ;
      return ;
    }

    key_len = b4->tag->header.key_len ;
    i_len = b4->node_hdr.info_len ;
    old_dup = x4dup_cnt( b4, b4->key_on) ;

    if ( b4->key_on == b4->header.n_keys - 1 )  /* at end */
    {
      remove_len = key_len - old_dup - x4trail_cnt( b4, b4->key_on ) ;

#ifdef S4DEBUG
      if ( remove_len < 0 )
        e4severe( e4info, E4_INFO_CIF ) ;
#endif  /* S4DEBUG */

      memset( b4->cur_pos, 0, remove_len ) ;
      memset( b4->data + b4->key_on * i_len, 0, i_len ) ;
      b4->key_on-- ;
    }
    else
    {
      old_bytes = key_len - old_dup - x4trail_cnt( b4, b4->key_on ) ;
      old_pos = b4->cur_pos ;
      b4skip( b4, 1 ) ;
      left_dup = x4dup_cnt( b4, b4->key_on) ;
      left_trail = x4trail_cnt( b4, b4->key_on ) ;
      new_dup = old_dup < left_dup ? old_dup : left_dup ;
      left_bytes = key_len - left_trail - left_dup ;
      new_bytes = key_len - left_trail - new_dup ;

      memcpy( b4->built_key->value, old_pos, left_dup - new_dup ) ;  /* copy prev dup bytes between the 2 keys only */
      memcpy( b4->built_key->value + ( left_dup - new_dup ), b4->cur_pos, left_bytes ) ;
      memcpy( old_pos + old_bytes - new_bytes, b4->built_key->value, new_bytes ) ;

      remove_len = old_bytes + left_bytes - new_bytes ;
#ifdef S4DEBUG
      if ( remove_len < 0 )
        e4severe( e4info, E4_INFO_CIF ) ;
#endif  /* S4DEBUG */

      mov_len = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - i_len * b4->header.n_keys
        - sizeof( B4NODE_HEADER ) - b4->node_hdr.free_space
          - ( ( (char *)&b4->header ) + B4BLOCK_SIZE - b4->cur_pos ) ;
#ifdef S4DEBUG
      if ( mov_len < 0 )
        e4severe( e4info, E4_INFO_CIB ) ;
#endif  /* S4DEBUG */

      memmove( b4->cur_pos - mov_len + remove_len, b4->cur_pos - mov_len, mov_len ) ;

      memset( b4->cur_pos - mov_len, 0, remove_len ) ;
      b4->key_on-- ;

      /* move and put info */
      info_pos = b4->data + ( b4->key_on ) * i_len ;
      memmove( info_pos, info_pos + i_len ,i_len * ( b4->header.n_keys - b4->key_on ) ) ;
      x4put_info( &b4->node_hdr, buffer, x4recno( b4, b4->key_on ), left_trail, new_dup ) ;
      memcpy( info_pos, (void *)buffer, i_len ) ;
      memset( b4->data + (b4->header.n_keys - 1 ) * i_len, 0, i_len ) ;
    }
    b4->changed = 1 ;
    b4->cur_pos += remove_len ;
    b4->header.n_keys-- ;
    b4->node_hdr.free_space += (short) ((int)i_len + remove_len) ;
  }

  /* S4FOX */
  void S4FUNCTION b4remove( B4BLOCK *b4 )
  {
    char *key_cur ;
    int len, i_len ;

    if( b4->header.node_attribute >= 2 ) /* leaf */
      b4remove_leaf( b4 ) ;
    else
    {
      i_len = b4->tag->header.key_len + 2 * sizeof( long ) ;
      key_cur = ((char *)&b4->node_hdr) + i_len * b4->key_on ;
      len = (b4->header.n_keys - b4->key_on - 1) * i_len ;

#ifdef S4DEBUG
      if ( b4->key_on < 0  || b4->key_on > b4lastpos( b4 ) ||
          len < 0 || (unsigned)len > (B4BLOCK_SIZE - sizeof(B4STD_HEADER) - (unsigned)i_len ))
        e4severe( e4info, E4_B4REMOVE ) ;
#endif  /* S4DEBUG */

      if ( len > 0 )
        memmove( key_cur, key_cur + i_len, len ) ;

      b4->header.n_keys-- ;
      memset( ((char *)&b4->node_hdr) + b4->header.n_keys * i_len, 0, i_len ) ;
      b4->changed = 1 ;
    }
  }
#endif /* S4OFF_WRITE */

  /* S4FOX */
  int S4FUNCTION b4skip( B4BLOCK *b4, long n )
  {
    int num_skipped ;

    if ( b4->header.node_attribute < 2 )  /* branch */
    {
      if ( n > 0 )
        num_skipped = b4->header.n_keys - b4->key_on ;
      else
        num_skipped = -b4->key_on ;

      if ( ( n <= 0L ) ?  (num_skipped <= (int)n)  :  (num_skipped >= (int)n)  )
      {
        b4->key_on += (int) n ;
        return (int) n ;
      }
      else
      {
        b4->key_on += num_skipped ;
        return num_skipped ;
      }
    }
    else  /* leaf */
    {
      if ( b4->header.n_keys == 0 )
        return 0 ;
      if (n > 0 )
      {
        if ( b4->key_on + n >= b4->header.n_keys )
        {
          b4->cur_pos = ((char *)&b4->header ) + sizeof( B4STD_HEADER )
            + sizeof( B4NODE_HEADER ) + b4->node_hdr.info_len * b4->header.n_keys
              + b4->node_hdr.free_space ;
          n = b4->header.n_keys - b4->key_on - ( b4->key_on != b4->header.n_keys ) ;
          b4->key_on = b4->header.n_keys ;
          return (int)n ;
        }
        for( num_skipped = (int)n ; num_skipped != 0 ; num_skipped-- )
        {
          b4->key_on++ ;
          b4->cur_pos -= ( b4->tag->header.key_len - x4dup_cnt( b4, b4->key_on ) - x4trail_cnt( b4, b4->key_on ) ) ;
        }
      }
      else
      {
        if ( b4->key_on + n < 0 )
        {
          n = -b4->key_on ;
          b4->key_on = 0 ;
          b4->cur_pos = ((char *)&b4->header ) + B4BLOCK_SIZE - b4->tag->header.key_len + x4trail_cnt( b4, b4->key_on ) ;
          return (int) n ;
        }
        for( num_skipped = (int)n ; num_skipped != 0 ; num_skipped++ )
        {
          b4->cur_pos += ( b4->tag->header.key_len - x4dup_cnt( b4, b4->key_on ) - x4trail_cnt( b4, b4->key_on ) ) ;
          b4->key_on-- ;
        }
      }

      return (int) n ;
    }
  }
#endif  /* S4FOX */

#ifdef N4OTHER
#ifndef S4OFF_WRITE
  int S4FUNCTION b4flush( B4BLOCK *b4 )
  {
    int rc ;
#ifdef S4BYTE_SWAP
    char *swap, *swap_ptr ;
    int i ;
    S4LONG long_val ;
    short short_val ;
#endif

    if ( b4->changed )
    {
#ifdef S4INDEX_VERIFY
      if ( b4verify( b4 ) == -1 )
        e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4flush()", "" ) ;
#endif
#ifdef S4NDX
#ifdef S4BYTE_SWAP
      swap = (char *) u4alloc_er( b4->tag->code_base, B4BLOCK_SIZE ) ;
      if ( swap == 0 )
        return -1 ;

      memcpy( (void *)swap, (void *)&b4->n_keys, B4BLOCK_SIZE ) ;
      /* position swap_ptr at beginning of pointers */

      swap_ptr += swap + 2 + sizeof(short) ;

      for ( i = 0 ; i < (*(short *)swap) ; i++ )
      {
        long_val = x4reverse_long( (void *)swap_ptr ) ;
        memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
        long_val = x4reverse_long( (void *)swap_ptr+sizeof(S4LONG) ) ;
        memcpy( swap_ptr+sizeof(S4LONG), (void *) &long_val, sizeof(S4LONG) ) ;
        swap_ptr += r4->data->indexes->tags.header->group_len ;
      }

      long_val = x4reverse_long( (void *)swap_ptr ) ;
      memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;

      short_val = x4reverse_short( (void *)swap ) ;
      memcpy( swap, (void *) &short_val, sizeof(short) ) ;

      rc = file4write( &b4->tag->file, (long)b4->file_block*I4MULTIPLY, swap, B4BLOCK_SIZE ) ;
      u4free( swap ) ;
#else
      rc = file4write( &b4->tag->file, (long)b4->file_block*I4MULTIPLY, &b4->n_keys, B4BLOCK_SIZE ) ;
#endif
#endif  /* S4NDX */

#ifdef S4CLIPPER
#ifdef S4BYTE_SWAP
      swap = (char *)u4alloc_er( b4->tag->code_base, B4BLOCK_SIZE ) ;
      if ( swap == 0 )
        return -1 ;

      memcpy( (void *)swap, (void *)&b4->n_keys, B4BLOCK_SIZE ) ;

      /* position swap_ptr at beginning of pointers */
      short_val = x4reverse_short( (void *)swap ) ;
      memcpy( swap, (void *) &short_val, sizeof(short) ) ;

      swap_ptr = swap + 2 ;

      /* swap the short pointers to B4KEY_DATA */
      for ( i = 0 ; i < b4->tag->header.keys_max ; i++ )
      {
        short_val = x4reverse_short( (void *)swap_ptr ) ;
        memcpy( swap_ptr, (void *) &short_val, sizeof(short) ) ;
        swap_ptr += sizeof(short) ;
      }
      /* swap the B4KEY_DATA's */
      for ( i = 0 ; i < b4->tag->header.keys_max ; i++ )
      {
        long_val = x4reverse_long( (void *)swap_ptr ) ;
        memcpy( swap_ptr, (void *) &long_val, sizeof(S4LONG) ) ;
        long_val = x4reverse_long( (void *)swap_ptr+sizeof(S4LONG) ) ;
        memcpy( swap_ptr+sizeof(S4LONG), (void *) &long_val, sizeof(S4LONG) ) ;
        swap_ptr += b4->tag->header.group_len ;
      }

      rc = file4write( &b4->tag->file, (long)b4->file_block*I4MULTIPLY, swap, B4BLOCK_SIZE ) ;
      u4free( swap ) ;
#else
      rc = file4write( &b4->tag->file, (long)b4->file_block*I4MULTIPLY, &b4->n_keys, B4BLOCK_SIZE ) ;
#endif
#endif  /* S4CLIPPER */

      if ( rc < 0 )  return rc ;
      b4->changed = 0 ;
    }
    return 0 ;
  }

  void S4FUNCTION b4append( B4BLOCK *b4, long pointer )
  {
#ifdef S4CLIPPER
    long adj_pointer = pointer * 512 ;
#endif  /* S4CLIPPER */
    B4KEY_DATA *data_ptr ;
#ifdef S4DEBUG
    int left_len ;
    if ( b4leaf( b4 ) || pointer <1L )
      e4severe( e4parm, E4_B4APPEND ) ;
#endif  /* S4DEBUG */

    b4go_eof( b4 ) ;
    data_ptr = b4key( b4, b4->key_on ) ;

#ifdef S4DEBUG
    left_len = B4BLOCK_SIZE - b4->key_on * b4->tag->header.group_len -
      sizeof(short) - sizeof(char[2]) - sizeof(pointer) ;
    if ( b4->key_on < 0  ||  b4->key_on != b4->n_keys ||  left_len < 0 )
      e4severe( e4info, E4_B4APPEND ) ;
#endif  /* S4DEBUG */

#ifdef S4NDX
    memcpy( &data_ptr->pointer, &pointer, sizeof(pointer) ) ;
#endif  /* S4NDX */
#ifdef S4CLIPPER
    memcpy( &data_ptr->pointer, &adj_pointer, sizeof(pointer) ) ;
#endif  /* S4CLIPPER */
    b4->changed = 1 ;
#ifdef S4INDEX_VERIFY
    if ( b4verify( b4 ) == -1 )
      e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4append()-after append", "" ) ;
#endif
  }
#endif /* S4OFF_WRITE */

#ifndef S4OFF_WRITE
#ifdef S4CLIPPER
  void S4FUNCTION b4append2( B4BLOCK *b4, void *k, long r, long pointer )
  {
    unsigned short temp ;
    B4KEY_DATA *data_ptr ;
    long adj_pointer ;

    b4go_eof( b4 ) ;

    if ( b4->n_keys > 0 )
    {
      if ( !b4leaf( b4 ) )   /* insert after branch */
        b4->key_on++ ;
      else
        if ( b4->key_on + !b4leaf( b4 ) < b4->tag->header.keys_max )
        {
          temp = b4->pointers[b4->n_keys+1] ;
          b4->pointers[b4->n_keys+1] = b4->pointers[b4->n_keys] ;
          b4->pointers[b4->n_keys] = temp ;
        }
    }

    data_ptr  = b4key( b4, b4->key_on ) ;
    adj_pointer = pointer * 512 ;
    b4->n_keys++ ;

    memcpy( data_ptr->value, k, b4->tag->header.group_len-2*sizeof(long) ) ;
    memcpy( &data_ptr->num, &r, sizeof(r) ) ;
    memcpy( &data_ptr->pointer, &adj_pointer, sizeof(pointer) ) ;
    b4->changed = 1 ;
  }
#endif  /* S4CLIPPER */

#ifdef S4NDX

  /* S4NDX */
  void  S4FUNCTION b4insert( B4BLOCK *b4, void *k, long r, long pointer )
  {
    B4KEY_DATA *data_ptr, *next_ptr ;
    int left_len ;
#ifdef S4DEBUG
    if ( k == 0 || r < 0L || pointer <0L )
      e4severe( e4parm, E4_B4INSERT ) ;
#endif  /* S4DEBUG */

    data_ptr = b4key( b4, b4->key_on ) ;
    next_ptr= b4key( b4, b4->key_on + 1 ) ;

    left_len = B4BLOCK_SIZE -  (b4->key_on + 1) * b4->tag->header.group_len -
      sizeof(short) - sizeof(char[2]) ;   /* 2 for S4NDX version, not 6 */

#ifdef S4DEBUG
    if ( b4->key_on < 0  ||  ( b4->key_on >  b4->n_keys && b4leaf( b4 ) )  ||
        ( b4->key_on > (b4->n_keys+1)  &&  !b4leaf( b4 ) )  || left_len < 0 )
      e4severe( e4info, E4_B4INSERT ) ;
#endif  /* S4DEBUG */

    memmove( next_ptr, data_ptr, left_len ) ;
    b4->n_keys++ ;
    memcpy( data_ptr->value, k, b4->tag->header.key_len ) ;
    memcpy( &data_ptr->num, &r, sizeof(r) ) ;
    memcpy( &data_ptr->pointer, &pointer, sizeof(pointer) ) ;
    b4->changed = 1 ;
  }
#endif  /* S4NDX */

#ifdef S4CLIPPER
  /* clipper just puts at end and inserts into the index part */
  void  S4FUNCTION b4insert( B4BLOCK *b4, void *k, long r, long pointer )
  {
    short temp, insert_pos ;
#ifdef S4DEBUG
    if ( k == 0 || r < 0L || pointer <0L )
      e4severe( e4parm, E4_B4INSERT ) ;
#endif  /* S4DEBUG */

    insert_pos = b4->key_on ;

    /* put at block end: */
    b4append2( b4, k, r, pointer ) ;

    temp = b4->pointers[b4->key_on] ;   /* save the placed position */
    memmove( &b4->pointers[insert_pos+1], &b4->pointers[insert_pos], sizeof(short) * ( b4lastpos( b4 ) - insert_pos - (!b4leaf( b4 ) && b4->n_keys < 2) ) ) ;
    b4->pointers[insert_pos] = temp ;
    if ( b4leaf( b4 ) )
      if ( b4key( b4, b4->n_keys )->pointer != 0 )
        b4key( b4, b4->n_keys )->pointer = 0L ;
  }
#endif  /* S4CLIPPER */
#endif /* S4OFF_WRITE */

  /* goes to one past the end of the block */
  void S4FUNCTION b4go_eof( B4BLOCK *b4 )
  {
    b4->key_on = b4->n_keys ;
  }

  B4KEY_DATA *S4FUNCTION b4key( B4BLOCK *b4, int i_key )
  {
#ifdef S4NDX
    return  (B4KEY_DATA *) ((char *) &b4->data + b4->tag->header.group_len * i_key) ;
#endif  /* S4NDX */

#ifdef S4CLIPPER
#ifdef S4DEBUG
    if ( i_key > 2 + b4->tag->header.keys_max )
      e4severe( e4parm, E4_B4KEY ) ;
    if ( ( b4->pointers[i_key] < (sizeof(short)) * ( b4->tag->header.keys_max + 1 ) ) ||
        ( b4->pointers[i_key] > B4BLOCK_SIZE - b4->tag->header.key_len ) )
      e4severe( e4info, E4_B4KEY ) ;
#endif  /* S4DEBUG */
    return  (B4KEY_DATA *) ((char *) &b4->n_keys + b4->pointers[i_key] ) ;
#endif  /* S4CLIPPER */
  }

  unsigned char *S4FUNCTION b4key_key( B4BLOCK *b4, int i_key )
  {
    return  (unsigned char *) b4key( b4, i_key )->value ;
  }

  int S4FUNCTION b4lastpos( B4BLOCK *b4 )
  {
    if ( !b4leaf( b4 ) )
      return b4->n_keys ;
    else
      return b4->n_keys - 1 ;
  }

  int S4FUNCTION b4leaf( B4BLOCK *b4 )
  {
    return( b4key( b4, 0 )->pointer == 0L ) ;
  }

  long  S4FUNCTION b4recno( B4BLOCK *b4, int i )
  {
    return b4key( b4, i )->num ;
  }

#ifndef S4OFF_WRITE
#ifdef S4NDX
  void  S4FUNCTION b4remove( B4BLOCK *b4 )
  {
    B4KEY_DATA *key_on ;
    int left_len = -1 ;

    key_on = b4key( b4, b4->key_on ) ;

    if( !b4leaf( b4 ) )
    {
      if ( b4->key_on >= b4->n_keys )
        left_len = 0 ;
      else   /* on last pos, so copy only the rec_num */
        if ( b4lastpos( b4 ) + 1 == b4->n_keys )
          left_len = sizeof( long ) ;
    }

    if ( left_len == -1 )
      left_len = B4BLOCK_SIZE - sizeof(b4->n_keys) - sizeof(b4->dummy) - (b4->key_on+1) * b4->tag->header.group_len ;

#ifdef S4DEBUG
    if ( b4->key_on < 0  ||  b4->key_on > b4lastpos( b4 )  ||  left_len < 0 )
      e4severe( e4info, E4_B4REMOVE ) ;
#endif  /* S4DEBUG */

    if ( left_len > 0 )
    {
      B4KEY_DATA *key_next= b4key( b4, b4->key_on+1 ) ;
      memmove( key_on, key_next, left_len ) ;
    }
    b4->n_keys-- ;
    b4->changed = 1 ;
  }
#endif  /* S4NDX */

#ifdef S4CLIPPER
  void  S4FUNCTION b4remove( B4BLOCK *b4 )
  {
    short temp ;

    /* just delete this entry */
    temp = b4->pointers[b4->key_on] ;
    if ( b4leaf( b4 ) && ( b4->key_on + !b4leaf( b4 ) < b4->tag->header.keys_max ) )
    {
      memmove( &b4->pointers[b4->key_on], &b4->pointers[b4->key_on+1],
              sizeof(short) * (b4lastpos( b4 ) - b4->key_on + 1) ) ;
      b4->pointers[b4lastpos( b4 )+1] = temp ;
    }
    else
    {
      memmove( &b4->pointers[b4->key_on], &b4->pointers[b4->key_on+1],
              sizeof(short) * (b4lastpos( b4 ) - b4->key_on) ) ;
      b4->pointers[b4lastpos( b4 )] = temp ;
    }
    b4->n_keys-- ;
    b4->changed = 1 ;

    if ( b4leaf( b4 ) )
      memset( b4key( b4, b4lastpos( b4 ) + 1 ), 0, b4->tag->header.key_len + 2 * sizeof( long ) ) ;
  }
#endif  /* S4CLIPPER */

  int S4FUNCTION b4room( B4BLOCK *b4 )
  {
    if ( b4leaf( b4 ) )
      return ( b4->n_keys < b4->tag->header.keys_max ) ;

    return( ( b4->n_keys < b4->tag->header.keys_max ) && ( ( B4BLOCK_SIZE -
                                                            b4->n_keys * b4->tag->header.group_len - sizeof(short) - 2*sizeof(char)) >= sizeof(long) ) ) ;
  }
#endif /* S4OFF_WRITE */

  int  S4FUNCTION b4seek( B4BLOCK *b4, char *search_value, int len )
  {
    int rc, save_rc, key_cur ;
    S4CMP_FUNCTION *cmp = b4->tag->cmp ;

    /* key_on must be between  key_lower and  key_upper */
    int key_lower = -1 ;
    int key_upper = b4->n_keys ;

    if ( key_upper == 0 )
    {
      b4->key_on = 0 ;
      return r4after ;
    }

    save_rc = 1 ;

    for(;;)  /* Repeat until the key is found */
    {
      key_cur  = (key_upper + key_lower) / 2  ;
      rc = (*cmp)( b4key_key(b4,key_cur), search_value, len ) ;

      if ( rc >= 0 )
      {
        key_upper = key_cur ;
        save_rc = rc ;
      }
      else
        key_lower = key_cur ;

      if ( key_lower >= (key_upper-1) )  /* then there is no exact match */
      {
        b4->key_on = key_upper ;
        if ( save_rc )
          return r4after ;
        return 0 ;
      }
    }
  }

  int S4FUNCTION b4skip( B4BLOCK *b4, long n )
  {
    int num_left ;

    if ( n > 0 )
    {
      num_left = b4->n_keys - b4->key_on ;
      if ( b4leaf( b4 ) )
        if ( num_left != 0 )
          num_left -- ;
    }
    else
      num_left = -b4->key_on ;

    if ( ( n <= 0L ) ? ( (long)num_left <= n ) : ( (long)num_left >= n ) )
    {
      b4->key_on = b4->key_on + (int) n ;
      return (int) n ;
    }
    else
    {
      b4->key_on = b4->key_on + num_left ;
      return num_left ;
    }
  }
#endif  /* N4OTHER */
#endif  /* S4INDEX_OFF */

#ifdef S4INDEX_VERIFY
  int S4FUNCTION b4verify( B4BLOCK *b4 )
  {
    int i, j, type ;
    long val ;
#ifdef S4FOX
    int hold_dup, hold_trail ;

    hold_dup = b4->cur_dup_cnt ;
    hold_trail = b4->cur_trail_cnt ;
#endif

    if ( b4->tag->code_base->do_index_verify == 0 )
      return 0 ;

#ifdef S4CLIPPER
    /* block internal verification... */
    for ( i = 0 ; i < b4->tag->header.keys_max ; i++ )
      for ( j = i + 1 ; j <= b4->tag->header.keys_max ; j++ )
        if ( b4->pointers[i] == b4->pointers[j] )
        {
#ifdef S4DEBUG_DEV
          e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", "b4 pointer duplication error" ) ;
#endif
          e4( b4->tag->code_base, e4index, E4_INFO_CIF ) ;
          return -1 ;
        }

    /* validate key count */
    if ( b4->n_keys < b4->tag->header.keys_half && b4->tag->header.root / 512 != b4->file_block )
      return e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", E4_RESULT_CII ) ;
#endif

    /*      #ifdef S4FOX */
    /*          */
    /*         if ( b4->node_hdr.free_space != B4BLOCK_SIZE - sizeof( B4STD_HEADER ) */
    /*              - sizeof( B4NODE_HEADER ) -  ) */
    /*            return e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", E4_RESULT_CII ) ; */
    /*      #endif */

    /* all keys in a given block should be of the same type... - branch = 1 */
#ifndef S4FOX
    type = b4leaf( b4 ) ? 0 : 1 ;
#endif

    /* key order verification */
#ifdef N4OTHER
    for ( i = 0 ; i <= b4->n_keys ; i++ )
    {
#ifdef S4CLIPPER
      val = b4key( b4, i )->pointer ;
      if ( ( b4key( b4, i )->pointer ? 1 : 0 ) != type )
#endif
#ifdef S4NDX
        if ( b4key( b4, i )->pointer >= b4->tag->header.eof )
          return e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", "block pointer value exceeds index eof value" ) ;
      if ( ( b4key( b4, i )->pointer ? 1 : 0 ) != type )
#endif
      {
#ifdef S4DEBUG_DEV
        e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", "b4 branch/leaf block type inconsistent" ) ;
#endif
        e4( b4->tag->code_base, e4index, E4_INFO_CIF ) ;
        return -1 ;
      }
    }
#endif

#ifdef S4FOX
    for ( i = 0 ; i < b4->header.n_keys - 1 ; i++ )
    {
      if ( (u4memcmp)( b4key_key( b4, i ), b4key_key( b4, i + 1 ), b4->tag->header.key_len ) > 0 )
#else
        for ( i = 0 ; i < b4->n_keys - 1 ; i++ )
        {
          if ( (*b4->tag->cmp)( b4key_key( b4, i ), b4key_key( b4, i + 1 ), b4->tag->header.key_len ) > 0 )
#endif
          {
#ifdef S4DEBUG_DEV
            e4describe( b4->tag->code_base, e4index, b4->tag->alias, "b4verify()", "b4 block ordering invalid" ) ;
#endif
            e4( b4->tag->code_base, e4index, E4_INFO_CIF ) ;
            return -1 ;
          }
        }

#ifdef S4FOX
      b4->cur_dup_cnt = hold_dup ;
      b4->cur_trail_cnt = hold_trail ;
#endif

      return 0 ;
    }
#endif
