/* r4reinde.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */

#include "d4all.h"

#ifdef __TURBOC__
   #pragma hdrstop
#endif  /* __TURBOC__ */

#ifndef S4OFF_WRITE
#ifndef S4INDEX_OFF

#ifndef S4CLIENT
#ifndef S4OFF_TRAN
void i4deleteRemoveKeys( INDEX4 *index )
{
   TAG4 *tagOn ;
   TAG4KEY_REMOVED *removed ;

   for( tagOn = 0 ;; )
   {
      tagOn = (TAG4 *)l4next( &index->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;

      for ( ;; )
      {
         removed =(TAG4KEY_REMOVED *)l4first( &tagOn->removedKeys ) ;
         if ( removed == 0 )
            break ;
         l4remove( &tagOn->removedKeys, removed ) ;
         u4free( removed ) ;
      }
   }
}
#endif /* S4OFF_TRAN */
#endif /* S4CLIENT */

#ifndef N4OTHER
#ifdef S4CLIENT
int S4FUNCTION i4reindex( INDEX4 *index )
{
   int rc ;
   CONNECTION4 *connection ;
   CONNECTION4REINDEX_INFO_OUT *out ;
   CODE4 *c4 ;
   DATA4 *d4 ;

   #ifdef S4VBASIC
      if ( c4parm_check( index, 0, E92101 ) )
         return -1 ;
   #endif  /* S4VBASIC */

   #ifdef E4PARM_HIGH
      if ( index == 0 )
         return error4( 0, e4parm_null, E92101 ) ;
   #endif

   d4 = index->data ;
   if ( error4code( d4->codeBase ) < 0 )
      return e4codeBase ;

   rc = 0 ;

   connection = d4->dataFile->connection ;
   if ( connection == 0 )
      return e4connection ;

   c4 = d4->codeBase ;
   rc = connection4assign( connection, CON4INDEX_REINDEX, data4clientId( d4 ), data4serverId( d4 ) ) ;
   if ( rc < 0 )
      return rc ;
   connection4addData( connection, index->indexFile->accessName, sizeof( index->indexFile->accessName ), 0 ) ;
   rc = connection4repeat( connection, -2, -1, -1, d4 ) ;
   if ( rc == r4locked )
      return r4locked ;
   if ( rc != 0 )
      return connection4error( connection, c4, rc, E92101 ) ;

   if ( connection4len( connection ) != sizeof( CONNECTION4REINDEX_INFO_OUT ) )
      return error4( c4, e4packetLen, E92101 ) ;
   out = (CONNECTION4REINDEX_INFO_OUT *)connection4data( connection ) ;
   if ( out->lockedDatafile == 1 )
      d4->dataFile->fileLock = d4 ;

   d4->recNum = -1 ;
   d4->recNumOld = -1 ;
   memset( d4->record, ' ', dfile4recWidth( d4->dataFile ) ) ;

   return 0 ;
}
#else

#include "r4reinde.h"

int S4FUNCTION i4reindex( INDEX4 *i4 )
{
   R4REINDEX reindex ;
   INDEX4FILE *indexFile ;
   CODE4 *c4 ;
   TAG4 *tagOn ;
   int rc ;
   DATA4 *data ;
   #ifndef S4OPTIMIZE_OFF
      #ifdef S4LOW_MEMORY
         int hasOpt ;
      #endif
   #endif
   #ifdef S4FOX
      B4BLOCK *block ;
      long rNode, goTo ;
      char tagName[LEN4TAG_ALIAS + 1] ;
      long i ;
      int len ;
      #ifdef S4BYTE_SWAP
         char *swapPtr ;
         S4LONG longVal ;
         short shortVal ;
      #endif
   #endif  /* S4FOX */

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E92101 ) )
         return -1 ;
   #endif  /* S4VBASIC */

   #ifdef E4PARM_HIGH
      if ( i4 == 0  )
         return error4( 0, e4parm_null, E92101 ) ;
   #endif

   c4 = i4->codeBase ;
   #ifdef E4ANALYZE
      if ( c4 == 0 )
         return error4( 0, e4struct, E92101 ) ;
   #endif

   if ( error4code( c4 ) < 0 )
      return e4codeBase ;

   indexFile = i4->indexFile ;
   data = i4->data ;

   #ifndef S4OPTIMIZE_OFF
      #ifdef S4LOW_MEMORY
         hasOpt = c4->hasOpt ;
         code4optSuspend( c4 ) ;
      #endif
   #endif

   #ifndef S4SINGLE
      rc = d4lockAll( data ) ;
      if ( rc )
         return rc ;
   #endif  /* S4SINGLE */

   #ifndef S4OFF_TRAN
      /* reindex is allowed, but need to fix-up any unique settings */
      i4deleteRemoveKeys( i4 ) ;
   #endif

   for( ;; )
   {
      rc = r4reindexInit( &reindex, i4, i4->indexFile ) ;
      if ( rc < 0 )
         break ;
      rc = r4reindexTagHeadersCalc( &reindex ) ;
      if ( rc < 0 )
         break ;
      rc = r4reindexBlocksAlloc(&reindex ) ;
      if ( rc < 0 )
         break ;

      #ifndef S4SINGLE
         #ifdef S4FOX
            if ( indexFile->file.lowAccessMode != OPEN4DENY_RW )
               indexFile->tagIndex->header.version = indexFile->versionOld + 1 ;
         #endif
      #endif

      #ifdef E4ANALYZE
         if ( i4->tags.nLink != indexFile->tags.nLink )
         {
            rc = e4struct ;
            break ;
         }
      #endif

      #ifdef S4FOX
         reindex.nBlocksUsed = 0 ;
         tagName[LEN4TAG_ALIAS] = '\0' ;

         if ( indexFile->tagIndex->header.typeCode >= 64 )  /* if .cdx */
         {
            reindex.tag = indexFile->tagIndex ;
            rc = sort4init( &reindex.sort, c4, indexFile->tagIndex->header.keyLen, 0 ) ;
            if ( rc < 0 )
               break ;
            reindex.sort.cmp = (S4CMP_FUNCTION *)u4memcmp ;

            for( tagOn = 0, i = 1 ; ; i++ )
            {
               tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
               if ( tagOn == 0 )
                  break ;
               len = strlen( tfile4alias( tagOn->tagFile ) ) ;
               memset( tagName, ' ', LEN4TAG_ALIAS ) ;
               memcpy( tagName, tfile4alias( tagOn->tagFile ), (unsigned int)len ) ;
               rc = sort4put( &reindex.sort, 2 * B4BLOCK_SIZE * i, tagName, "" ) ;
               if ( rc < 0 )
                  break ;
               #ifdef E4MISC
                  reindex.keyCount++ ;
               #endif /* E4MISC */
            }

            if ( rc < 0 )
               break ;

            rc = r4reindexWriteKeys( &reindex, e4unique ) ;  /* tag index should have no uniques */
            if ( rc != 0 )
            {
               r4reindexFree( &reindex ) ;
               break ;
            }
         }
         else
            if ( reindex.nTags > 1 )   /* should only be 1 tag in an .idx */
            {
               rc = e4index ;
               break ;
            }
      #endif  /* S4FOX */

      for( tagOn = 0 ; ; )
      {
         tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
         if ( tagOn == 0 )
            break ;
         reindex.tag = tagOn->tagFile ;
         #ifdef S4FOX
            reindex.nBlocksUsed = 0 ;
         #else  /* S4MDX */
            reindex.tag->header.version++ ;
         #endif  /* S4FOX */

         rc = expr4context( tagOn->tagFile->expr, data ) ;
         if ( rc < 0 )
            break ;
         if ( tagOn->tagFile->filter != 0 )
         {
            rc = expr4context( tagOn->tagFile->filter, data ) ;
            if ( rc < 0 )
               break ;
         }

         rc = r4reindexSupplyKeys( &reindex ) ;
         if ( rc )
         {
            r4reindexFree( &reindex ) ;
            break ;
         }

         rc = r4reindexWriteKeys( &reindex, t4unique( tagOn ) ) ;
         if ( rc )
         {
            r4reindexFree( &reindex ) ;
            break ;
         }
      }

      if ( rc != 0 )   /* r4unique or error */
         break ;

      rc = r4reindexTagHeadersWrite( &reindex ) ;
      if ( rc < 0 )
         break ;

      #ifdef S4FOX
         /* now must fix the right node branches for all blocks by moving leftwards */
         for( tagOn = 0 ; ; )
         {
            tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
            if ( tagOn == 0 )
               break ;

            for( tfile4rlBottom( tagOn->tagFile ) ; tagOn->tagFile->blocks.lastNode ; tfile4up( tagOn->tagFile ) )
            {
               block = tfile4block( tagOn->tagFile ) ;
               goTo = block->header.leftNode ;

               while ( goTo != -1 )
               {
                  #ifdef E4DEBUG
                     if ( goTo <= 0 )  /* invalid value, esp. zero */
                        return error4( c4, e4struct, E92101 ) ;
                  #endif

                  rNode = block->fileBlock ;
                  if ( block->changed )
                  {
                     rc = b4flush( block ) ;
                     if ( rc < 0 )
                        break ;
                  }

                  rc = file4readAll( &indexFile->file, I4MULTIPLY*goTo, &block->header, B4BLOCK_SIZE ) ;
                  if ( rc < 0 )
                     break ;

                  #ifdef S4BYTE_SWAP
                     block->header.nodeAttribute = x4reverseShort( (void *)&block->header.nodeAttribute ) ;
                     block->header.nKeys = x4reverseShort( (void *)&block->header.nKeys ) ;
                     block->header.leftNode = x4reverseLong( (void *)&block->header.leftNode ) ;
                     block->header.rightNode = x4reverseLong( (void *)&block->header.rightNode ) ;

                     if (block->header.nodeAttribute >= 2 ) /* if block is a leaf */
                     {
                        block->nodeHdr.freeSpace = x4reverseShort( (void *)&block->nodeHdr.freeSpace ) ;
                        longVal = x4reverseLong( (void *)&block->nodeHdr.recNumMask[0] ) ;
                        memcpy( (void *)&block->nodeHdr.recNumMask[0], (void *)&longVal, sizeof(S4LONG) ) ;
                     }
                     else /* if block is a branch */
                     {
                        shortVal = block->tag->header.keyLen + sizeof(S4LONG) ;
                        /* position swapPtr to end of first key expression */
                        swapPtr = (char *) &block->nodeHdr.freeSpace + block->tag->header.keyLen ;

                        /* move through all B4KEY's to swap 'long's */
                        for ( i = 0 ; i < (int) block->header.nKeys ; i++ )
                        {
                           longVal = x4reverseLong( (void *)swapPtr ) ;
                           memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
                           swapPtr += sizeof(S4LONG) ;
                           longVal = x4reverseLong( (void *)swapPtr ) ;
                           memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
                           swapPtr += shortVal ;
                        }
                     }
                  #endif

                  block->fileBlock = goTo ;
                  if ( block->header.rightNode != rNode )  /* if a bad value */
                  {
                     block->header.rightNode = rNode ;
                     block->changed = 1 ;
                  }
                  goTo = block->header.leftNode ;
               }
               if ( rc < 0 )
                  break ;
               block->builtOn = -1 ;
               rc = b4top( block ) ;
               if ( rc < 0 )
                  break ;
            }
            if ( rc < 0 )
               break ;
         }
         if ( rc < 0 )
            break ;
      #endif  /* S4FOX */

      r4reindexFree( &reindex ) ;
      #ifndef S4OPTIMIZE_OFF
         #ifdef S4LOW_MEMORY
            if ( hasOpt )
               code4optRestart( c4 ) ;
         #endif
      #endif

      break ;
   }
   if ( rc < 0 )
      return error4stack( c4, (short)rc, E92101 ) ;

   data->recNum = -1 ;
   data->recNumOld = -1 ;
   memset( data->record, ' ', dfile4recWidth( data->dataFile ) ) ;

   return rc ;
}

int r4reindexInit( R4REINDEX *r4, INDEX4 *i4, INDEX4FILE *indexFile )
{
   #ifdef E4PARM_LOW
      if ( r4 == 0 || i4 == 0 || indexFile == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   memset( (void *)r4, 0, sizeof( R4REINDEX ) ) ;

   r4->indexFile = indexFile ;
   r4->data = i4->data ;
   r4->dataFile = indexFile->dataFile ;
   r4->codeBase = i4->codeBase ;

   r4->minKeysmax = INT_MAX ;
   r4->startBlock = 0 ;
   r4->sort.file.hand = -1 ;

   #ifndef S4FOX
      r4->blocklen = indexFile->header.blockRw ;
   #endif  /* S4FOX */

   r4->bufferLen = i4->codeBase->memSizeSortBuffer ;
   if ( r4->bufferLen < 1024 )
      r4->bufferLen = 1024 ;

   r4->buffer = (char *)u4allocEr( i4->codeBase, (long)r4->bufferLen ) ;
   if ( r4->buffer == 0 )
      return e4memory ;

   #ifdef S4FOX
      r4->lastblock = 1024 ;  /* leave space for the index header block  */
   #endif  /* S4FOX */

   return 0 ;
}

void r4reindexFree( R4REINDEX *r4 )
{
   u4free( r4->buffer ) ;
   u4free( r4->startBlock ) ;
   sort4free( &r4->sort ) ;
}

int r4reindexBlocksAlloc( R4REINDEX *r4 )
{
   long onCount ;

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   #ifdef E4MISC
      if ( (unsigned)r4->minKeysmax > INT_MAX )
         return error4( r4->codeBase, e4info, E92102 ) ;
   #endif

   /* Calculate the block stack height */
   onCount = dfile4recCount( r4->dataFile, -2 ) ;
   if ( onCount < 0 )
      return error4stack( r4->codeBase, (short)onCount, E92102 ) ;
   for ( r4->nBlocks = 2; onCount != 0L; r4->nBlocks++ )
      onCount /= r4->minKeysmax ;

   if ( r4->startBlock == 0 )
   {
      #ifdef S4FOX
         r4->startBlock = (R4BLOCK_DATA *)u4allocEr( r4->codeBase, (long)B4BLOCK_SIZE * r4->nBlocks ) ;
      #endif  /* S4FOX */

      #ifdef S4MDX
         r4->startBlock = (R4BLOCK_DATA *)u4allocEr( r4->codeBase, (long)r4->blocklen * r4->nBlocks ) ;
      #endif  /* S4MDX */
   }

   if ( r4->startBlock == 0 )
      return e4memory ;

   return 0 ;
}

int r4reindexSupplyKeys( R4REINDEX *r4 )
{
   FILE4SEQ_READ seqRead ;
   EXPR4 *filter ;
   unsigned char *keyResult ;
   int rc, *filterResult ;
   long  count, iRec ;
   DATA4FILE *dataFile ;
   TAG4FILE *t4 ;
   #ifndef S4MEMO_OFF
      int i ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   dataFile = r4->dataFile ;
   t4 = r4->tag ;
   #ifdef E4MISC
      r4->keyCount = 0L ;
   #endif  /* E4MISC */

   rc =sort4init( &r4->sort, r4->codeBase, t4->header.keyLen, 0 ) ;
   if ( rc < 0 )
      return error4stack( r4->codeBase, (short)rc, E92102 ) ;

   #ifdef S4FOX
      r4->sort.cmp = (S4CMP_FUNCTION *)u4memcmp ;
   #endif  /* S4FOX */

   #ifdef S4MDX
      r4->sort.cmp = (S4CMP_FUNCTION *)t4->cmp ;
   #endif  /* S4MDX */

   filter = t4->filter ;
   count = dfile4recCount( dataFile, -2L ) ;
   if ( count < 0 )
      return error4stack( r4->codeBase, (short)rc, E92102 ) ;

   rc = expr4context( r4->tag->expr, r4->data ) ;
   if ( rc < 0 )
      return rc ;
   if ( r4->tag->filter != 0 )
   {
      rc = expr4context( r4->tag->filter, r4->data ) ;
      if ( rc < 0 )
         return rc ;
   }

   #ifdef S4ADVANCE_READ
      file4seqReadInitDo( &seqRead, &dataFile->file, dfile4recordPosition( dataFile, 1L ), r4->buffer, r4->bufferLen, 1 ) ;
   #else
      file4seqReadInit( &seqRead, &dataFile->file, dfile4recordPosition( dataFile, 1L ), r4->buffer, r4->bufferLen ) ;
   #endif

   for ( iRec = 1L; iRec <= count; iRec++ )
   {
      rc = file4seqReadAll( &seqRead, dataFile->record, dfile4recWidth( dataFile ) ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      r4->data->recNum = iRec ;

      #ifndef S4MEMO_OFF
         for ( i = 0; i < dataFile->nFieldsMemo; i++ )
            f4memoReset( r4->data->fieldsMemo[i].field ) ;
      #endif  /* S4MEMO_OFF */

      if ( filter )
      {
         rc = expr4vary( filter, (char **)&filterResult ) ;
         if ( rc < 0 )
         {
            #ifdef S4ADVANCE_READ
               file4seqReadInitUndo( &seqRead ) ;
            #endif
            return error4stack( r4->codeBase, (short)rc, E92102 ) ;
         }
         #ifdef E4MISC
            if ( expr4type( filter ) != r4log )
            {
               #ifdef S4ADVANCE_READ
                  file4seqReadInitUndo( &seqRead ) ;
               #endif
               return error4( r4->codeBase, e4result, E92102 ) ;
            }
         #endif  /* E4MISC */
         if ( ! *filterResult )
            continue ;
         t4->hasKeys = 1 ;
         #ifdef S4MDX
            t4->hadKeys = 0 ;
         #endif
      }

      tfile4exprKey( t4, &keyResult ) ;

      rc = sort4put( &r4->sort, iRec, keyResult, "" ) ;
      if ( rc < 0 )
      {
         #ifdef S4ADVANCE_READ
            file4seqReadInitUndo( &seqRead ) ;
         #endif
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      }
      #ifdef E4MISC
         r4->keyCount++ ;
      #endif  /* E4MISC */
   }

   #ifdef S4ADVANCE_READ
      file4seqReadInitUndo( &seqRead ) ;
   #endif

   return 0 ;
}

int r4reindexTagHeadersCalc( R4REINDEX *r4 )
{
   TAG4FILE *tag ;
   int rc ;
   CODE4 *c4 ;
   #ifdef S4FOX
      #ifdef S4DATA_ALIGN
         unsigned int size, delta ;
      #endif
      int keysmax, exprType ;
   #endif  /* S4FOX */

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   c4 = r4->codeBase ;
   r4->nTags = 0 ;
   for( tag = 0 ;; )
   {
      tag = (TAG4FILE *)l4next( &r4->indexFile->tags, tag ) ;
      if ( tag == 0 )
         break ;
      rc = tfile4freeAll( tag ) ;
      if ( rc < 0 )
         return error4stack( c4, (short)rc, E92102 ) ;

      expr4context( tag->expr, r4->data ) ;

      tag->header.keyLen = (short)expr4keyLen( tag->expr ) ;
      #ifdef S4FOX
         #ifdef S4DATA_ALIGN
            size = (unsigned int)sizeof(long) + tag->header.keyLen ;
            delta = 4 - size % 4 ;
            tag->builtKeyMemory = mem4create( c4, 3, size + delta, 2, 0 ) ;
         #else
            tag->builtKeyMemory = mem4create( c4, 3, (unsigned int)sizeof(long) + tag->header.keyLen + 1, 2, 0 ) ;
         #endif
         exprType = expr4type( tag->expr ) ;
         if ( exprType < 0 )
            return error4stack( c4, (short)rc, E92102 ) ;
         tfile4initSeekConv( tag, exprType ) ;
         if ( tag->header.keyLen < 0 )
            return error4( c4, e4index, E92102 ) ;

         keysmax = ( B4BLOCK_SIZE - sizeof(B4STD_HEADER) ) / ( tag->header.keyLen + 2*sizeof(long) ) ;

         if ( keysmax < r4->minKeysmax )
            r4->minKeysmax = keysmax ;
      #endif  /* S4FOX */

      #ifdef S4MDX
         if ( tag->header.keyLen < 0 )
            return error4( c4, e4index, E92102 ) ;

         rc = expr4type( tag->expr ) ;
         if ( rc < 0 )
            return error4( c4, rc, E92102 ) ;
         tag->header.type = (char)rc ;
         if ( tag->header.type == r4dateDoub )
            tag->header.type = r4date ;
         if ( tag->header.type == r4numDoub )
            tag->header.type = r4num ;

         tfile4initSeekConv( tag, tag->header.type ) ;
         tag->header.groupLen = (short)(tag->header.keyLen+ 2*sizeof(S4LONG)-1) ;
         tag->header.groupLen-= (short)(tag->header.groupLen % sizeof(S4LONG)) ;

         tag->header.keysMax = (short)((r4->indexFile->header.blockRw - sizeof(short)
                       - 6 - sizeof(S4LONG)) / tag->header.groupLen) ;
         if ( tag->header.keysMax < r4->minKeysmax )
            r4->minKeysmax = tag->header.keysMax ;
         tag->hasKeys = 0 ;
         tag->hadKeys = 1 ;
      #endif  /* S4MDX */

      r4->nTags++ ;
   }

   #ifdef S4FOX
      if ( r4->indexFile->tagIndex->header.typeCode >= 64 )
      {
         r4->lastblock += ((long)r4->nTags-1)*2*B4BLOCK_SIZE + B4BLOCK_SIZE ;
         tfile4initSeekConv( r4->indexFile->tagIndex, r4str ) ;
      }
      else
         r4->lastblock -= B4BLOCK_SIZE ;
   #endif  /* S4FOX */

   #ifdef S4MDX
      r4->lastblockInc = r4->indexFile->header.blockRw/ 512 ;
      r4->lastblock = 4 + (r4->nTags-1)*r4->lastblockInc ;
   #endif  /* S4MDX */

   return 0 ;
}

TAG4FILE *r4reindexFindITag( R4REINDEX *r4, const int tagNum )
{
   /* First 'iTag' starts at '1' for this specific routine */
   TAG4FILE *tagOn ;
   int iTag ;

   #ifdef E4PARM_LOW
      if ( r4 == 0 || tagNum <= 0 )
      {
         error4( 0, e4parm, E92102 ) ;
         return 0 ;
      }
   #endif

   iTag = tagNum ;

   tagOn = (TAG4FILE *)l4first( &r4->indexFile->tags ) ;

   while ( --iTag >= 1 )
   {
      tagOn = (TAG4FILE *) l4next( &r4->indexFile->tags, tagOn ) ;
      if ( tagOn == 0 )
         return 0 ;
   }
   return tagOn ;
}

#ifdef S4MDX

#define GARBAGE_LEN 518

int r4reindexTagHeadersWrite( R4REINDEX *r4 )
{
   /* First, calculate the T4DESC.leftChld, T4DESC.rightChld values, T4DESC.parent values */
   int rc, higher[49], lower[49], parent[49] ;
   TAG4FILE *tagOn, *tagPtr ;
   INDEX4FILE *i4 ;
   DATA4 *d4 ;
   CODE4 *c4 ;
   int nTag, iTag, jField, len, saveCode ;
   T4DESC tagInfo ;
   const char *ptr ;
   #ifdef S4BYTE_SWAP
      I4HEADER swapHeader ;
      T4HEADER swapTagHeader ;
   #endif  /* S4BYTE_SWAP */

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   memset( (void *)higher, 0, sizeof( higher ) ) ;
   memset( (void *)lower,  0, sizeof( lower ) ) ;
   memset( (void *)parent, 0, sizeof( parent ) ) ;

   i4 = r4->indexFile ;
   d4 = r4->data ;
   c4 = r4->codeBase ;

   #ifdef E4ANALYZE
      if ( i4 == 0 || d4 == 0 )
         return error4( c4, e4struct, E92102 ) ;
   #endif

   tagOn = (TAG4FILE *) l4first( &i4->tags ) ;
   if ( tagOn != 0 )
   {
      nTag = 1 ;

      for ( ;; )
      {
         tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn) ;
         if ( tagOn == 0 )
            break ;
         nTag++ ;
         iTag = 1 ;
         for (;;)
         {
            tagPtr = r4reindexFindITag( r4, iTag ) ;
            #ifdef E4MISC
               if ( tagPtr == 0 || iTag < 0 || iTag >= 48 || nTag > 48 )
                  return error4( c4, e4result, E92102 ) ;
            #endif  /* E4MISC */
            if ( u4memcmp( tagOn->alias, tagPtr->alias, sizeof(tagOn->alias)) < 0)
            {
               if ( lower[iTag] == 0 )
               {
                  lower[iTag] = nTag ;
                  parent[nTag] = iTag ;
                  break ;
               }
               else
                  iTag = lower[iTag] ;
            }
            else
            {
               if ( higher[iTag] == 0 )
               {
                  higher[iTag] = nTag ;
                  parent[nTag] = iTag ;
                  break ;
               }
               else
                  iTag = higher[iTag] ;
            }
         }
      }
   }

   /* Now write the headers */
   file4seqWriteInit( &r4->seqwrite, &i4->file, 0L, r4->buffer, r4->bufferLen ) ;

   i4->header.eof = r4->lastblock + r4->lastblockInc ;
   i4->header.freeList = 0L ;
   u4yymmdd( i4->header.yymmdd ) ;

   #ifdef S4BYTE_SWAP
      memcpy( (void *)&swapHeader, (void *)&i4->header, sizeof(I4HEADER) ) ;

      swapHeader.blockChunks = x4reverseShort( (void *)&swapHeader.blockChunks ) ;
      swapHeader.blockRw = x4reverseShort( (void *)&swapHeader.blockRw ) ;
      swapHeader.slotSize = x4reverseShort( (void *)&swapHeader.slotSize ) ;
      swapHeader.numTags = x4reverseShort( (void *)&swapHeader.numTags ) ;
      swapHeader.eof = x4reverseLong( (void *)&swapHeader.eof ) ;
      swapHeader.freeList = x4reverseLong( (void *)&swapHeader.freeList ) ;

      rc = file4seqWrite( &r4->seqwrite, &swapHeader, sizeof(I4HEADER) ) ;
   #else
      rc = file4seqWrite( &r4->seqwrite, &i4->header, sizeof(I4HEADER) ) ;
   #endif  /* S4BYTE_SWAP */

   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;

   rc = file4seqWriteRepeat( &r4->seqwrite, 512-sizeof(I4HEADER)+17, 0 ) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;

   /* There is a 0x01 on byte 17 of the first 32 bytes. */
   rc = file4seqWrite( &r4->seqwrite, "\001", 1 ) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;

   rc = file4seqWriteRepeat( &r4->seqwrite, 14, 0 ) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;

   tagOn = (TAG4FILE *) l4first( &i4->tags ) ;

   for ( iTag = 0; iTag < 47; iTag++ )
   {
      memset( (void *)&tagInfo, 0, sizeof(tagInfo) ) ;

      if ( iTag < r4->nTags )
      {
         tagInfo.headerPos = 4 + (long) iTag * r4->lastblockInc ;
         tagOn->headerOffset = tagInfo.headerPos * 512 ;

         memcpy( (void *)tagInfo.tag, tagOn->alias, sizeof(tagInfo.tag) ) ;

         tagInfo.indexType = tagOn->header.type ;

         #ifdef S4BYTE_SWAP
            tagInfo.headerPos = x4reverseLong( (void *)&tagInfo.headerPos ) ;
            tagInfo.x1000 = 0x0010 ;
         #else
            tagInfo.x1000 = 0x1000 ;
         #endif  /* S4BYTE_SWAP */

         tagInfo.x2 = 2 ;
         tagInfo.leftChld = (char) lower[iTag+1] ;
         tagInfo.rightChld = (char) higher[iTag+1] ;
         tagInfo.parent = (char) parent[iTag+1] ;

         if ( i4->header.isProduction )
         {
            saveCode = c4->errFieldName ;
            c4->errFieldName = 0 ;
            jField = d4fieldNumber( d4, tagOn->expr->source ) ;
            c4->errFieldName = saveCode ;
            if ( jField > 0 )
            {
               rc = file4write( &r4->dataFile->file, ( jField + 1 ) * sizeof( FIELD4IMAGE ) - 1, "\001", 1 ) ;
               if ( rc < 0 )
                  return error4stack( c4, rc, E92102 ) ;
            }
         }
         tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn ) ;
      }
      rc = file4seqWrite( &r4->seqwrite, &tagInfo, sizeof( T4DESC ) ) ;
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;
   }

   for (tagOn = 0 ;; )
   {
      tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;
      #ifdef S4BYTE_SWAP
         memcpy( (void *)&swapTagHeader, (void *)&tagOn->header, sizeof(T4HEADER) ) ;

         swapTagHeader.root = x4reverseLong( (void *)&swapTagHeader.root ) ;
         swapTagHeader.keyLen = x4reverseShort( (void *)&swapTagHeader.keyLen ) ;
         swapTagHeader.keysMax = x4reverseShort( (void *)&swapTagHeader.keysMax ) ;
         swapTagHeader.groupLen = x4reverseShort( (void *)&swapTagHeader.groupLen ) ;
         swapTagHeader.unique = x4reverseShort( (void *)&swapTagHeader.unique ) ;

         rc = file4seqWrite( &r4->seqwrite, &swapTagHeader, sizeof( T4HEADER ) ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, &tagOn->header, sizeof( T4HEADER ) ) ;
      #endif  /* S4BYTE_SWAP */
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;

      ptr = tagOn->expr->source ;
      len = strlen( ptr ) ;
      rc = file4seqWrite( &r4->seqwrite, ptr, len) ;
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;

      rc = file4seqWriteRepeat( &r4->seqwrite, 221-len, 0 ) ;
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;

      if( tagOn->filter != 0 )
      {
         rc = file4seqWriteRepeat( &r4->seqwrite, 1, 1 ) ;
         if ( rc < 0 )
            return error4stack( c4, rc, E92102 ) ;
         if ( tagOn->hasKeys )
            rc = file4seqWriteRepeat( &r4->seqwrite, 1, 1 ) ;
         else
            rc = file4seqWriteRepeat( &r4->seqwrite, 1, 0 ) ;
      }
      else
         rc = file4seqWriteRepeat( &r4->seqwrite, 2, 0 ) ;

      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;

      /* write extra space up to filter write point */
      rc = file4seqWriteRepeat( &r4->seqwrite, GARBAGE_LEN-3 , 0 ) ;
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;

      if ( tagOn->filter == 0 )
         len = 0 ;
      else
      {
         ptr = tagOn->filter->source ;
         len = strlen(ptr) ;
         rc = file4seqWrite( &r4->seqwrite, ptr, len ) ;
         if ( rc < 0 )
            return error4stack( c4, rc, E92102 ) ;
      }
      rc = file4seqWriteRepeat( &r4->seqwrite, r4->blocklen - GARBAGE_LEN - len - 220 - sizeof(tagOn->header), 0 ) ;
      if ( rc < 0 )
         return error4stack( c4, rc, E92102 ) ;
   }
   rc = file4lenSet( &i4->file, i4->header.eof * 512) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;

   rc =  file4seqWriteFlush( &r4->seqwrite ) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E92102 ) ;
   return 0 ;
}

int r4reindexWriteKeys( R4REINDEX *r4, short int errUnique )
{
   TAG4FILE *t4 ;
   char  lastKey[I4MAX_KEY_SIZE], *keyData ;
   int   isUnique, rc, isFirst ;
   void *dummyPtr ;
   long  keyRec ;

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   t4 = r4->tag ;

   r4->grouplen = t4->header.groupLen ;
   r4->valuelen = t4->header.keyLen ;
   r4->keysmax = t4->header.keysMax ;
   memset( (void *)r4->startBlock, 0, r4->nBlocks*r4->blocklen ) ;

   rc = sort4getInit( &r4->sort ) ;
   if ( rc < 0 )
      return error4stack( r4->codeBase, rc, E92102 ) ;

   file4seqWriteInit( &r4->seqwrite, &r4->indexFile->file, (r4->lastblock+r4->lastblockInc)*512, r4->buffer,r4->bufferLen) ;

   #ifdef E4MISC
      if ( I4MAX_KEY_SIZE < r4->sort.sortLen )
         return error4( r4->codeBase, e4index, E82102 ) ;
   #endif

   isFirst = 1 ;
   isUnique = t4->header.unique ;

   for(;;)  /* For each key to write */
   {
      rc = sort4get( &r4->sort, &keyRec, (void **) &keyData, &dummyPtr) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, rc, E92102 ) ;

      #ifdef E4MISC
         if ( r4->keyCount < 0L || r4->keyCount == 0L && rc != 1 || r4->keyCount > 0L && rc == 1 )
            return error4( r4->codeBase, e4info, E92102 ) ;
         r4->keyCount-- ;
      #endif

      if ( rc == 1 )  /* No more keys */
      {
         rc = r4reindexFinish( r4 ) ;
         if ( rc < 0 )
            return error4stack( r4->codeBase, rc, E92102 ) ;
         rc = file4seqWriteFlush( &r4->seqwrite ) ;
         if ( rc < 0 )
            return error4stack( r4->codeBase, rc, E92102 ) ;
         break ;
      }

      if ( isUnique )
      {
         if( isFirst )
            isFirst = 0 ;
         else
            if ( (*t4->cmp)( keyData, lastKey, r4->sort.sortLen) == 0 )
            {
               switch( errUnique )
               {
                  case e4unique:
                     return error4describe( r4->codeBase, e4unique, E82103, t4->alias, (char *)0, (char *)0 ) ;
                  case r4unique:
                     return r4unique ;
                  default:
                     continue ;
               }
            }
         memcpy( lastKey, keyData, r4->sort.sortLen ) ;
      }

      /* Add the key */
      rc = r4reindexAdd( r4, keyRec, (unsigned char *)keyData ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, rc, E92102 ) ;
   }

   /* Now complete the tag header info. */
   t4->header.root = r4->lastblock ;
   return 0 ;
}

int r4reindexAdd( R4REINDEX *r4, const long rec, const unsigned char *keyValue )
{
   B4KEY_DATA *keyTo ;
   R4BLOCK_DATA *startBlock ;
   int rc ;
   #ifdef E4ANALYZE
      long dif ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 || rec < 0 || keyValue == 0 )
         return error4( 0, e4parm, E92102 ) ;
   #endif

   startBlock = r4->startBlock ;
   if ( startBlock->nKeys >= r4->keysmax )
   {
      rc = r4reindexTodisk( r4 ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, rc, E92102 ) ;
      memset( (void *)startBlock, 0, r4->blocklen ) ;
   }

   keyTo = (B4KEY_DATA *)( startBlock->info + (startBlock->nKeys++) * r4->grouplen ) ;

   #ifdef E4ANALYZE
      dif = (char *) keyTo -  (char *) startBlock ;
      if ( ((unsigned)dif + r4->grouplen) > r4->blocklen || dif < 0 )
         return error4( r4->codeBase, e4index, E92102 ) ;
   #endif
   keyTo->num = rec ;
   memcpy( (void *)keyTo->value, keyValue, r4->valuelen ) ;

   return 0 ;
}

int r4reindexFinish( R4REINDEX *r4 )
{
   R4BLOCK_DATA *block ;
   int iBlock, rc ;
   B4KEY_DATA *keyTo ;
   #ifdef E4ANALYZE
      long dif ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   #ifdef S4BYTE_SWAP
      char *swap, *swapPtr ;
      int i ;
      S4LONG longVal ;
      short shortVal ;

      swap = (char *)u4allocEr( r4->codeBase, r4->blocklen ) ;
      if ( swap == 0 )
         return error4stack( r4->codeBase, e4memory, E92102 ) ;

      memcpy( (void *)swap, (void *)r4->startBlock, r4->blocklen ) ;
      /* position swapPtr at beginning of B4KEY's */
      swapPtr = swap ;
      swapPtr += 6 + sizeof(short) ;
      /* move through all B4KEY's to swap 'long' */
      for ( i = 0 ; i < (* (short *)swap) ; i++ )
      {
         longVal = x4reverseLong( (void *)swapPtr ) ;
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += r4->grouplen ;
      }
      /* swap the numKeys value */
      shortVal = x4reverseShort( (void *)swap ) ;
      memcpy( swap, (void *)&shortVal, sizeof(short) ) ;

      rc = file4seqWrite( &r4->seqwrite, swap ,r4->blocklen ) ;
      if ( rc < 0 )
      {
         u4free( swap ) ;
         return error4stack( r4->codeBase, rc, E92102 ) ;
      }
   #else
      rc = file4seqWrite( &r4->seqwrite, r4->startBlock, r4->blocklen ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, rc, E92102 ) ;
   #endif  /* S4BYTE_SWAP */

   r4->lastblock += r4->lastblockInc ;
   block = r4->startBlock ;

   for( iBlock=1; iBlock < r4->nBlocks; iBlock++ )
   {
      block = (R4BLOCK_DATA *)( (char *)block + r4->blocklen ) ;
      if ( block->nKeys >= 1 )
      {
         keyTo = (B4KEY_DATA *) (block->info + block->nKeys*r4->grouplen) ;
         #ifdef E4ANALYZE
            dif = (char *) keyTo  -  (char *) block ;
            if ( ( (unsigned)dif + sizeof( long ) ) > r4->blocklen  ||  dif < 0 )
               return error4( r4->codeBase, e4index, E92102 ) ;
         #endif
         keyTo->num = r4->lastblock ;

         #ifdef S4BYTE_SWAP
            memcpy( (void *)swap, (void *)block, r4->blocklen ) ;
            /* position swapPtr at beginning of B4KEY's */
            swapPtr = swap ;
            swapPtr += 6 + sizeof(short) ;
            /* move through all B4KEY's to swap 'long' */
            for ( i = 0 ; i < (*(short *)swap) ; i++ )
            {
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += r4->grouplen ;
            }
            /* this is a branch */
            longVal = x4reverseLong( (void *)swapPtr ) ;
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;

            /* swap the numKeys value */
            shortVal = x4reverseShort( (void *)swap ) ;
            memcpy( swap, (void *) &shortVal, sizeof(short) ) ;

            rc = file4seqWrite( &r4->seqwrite, swap, r4->blocklen ) ;
            if ( rc < 0 )
            {
               u4free( swap ) ;
               return error4stack( r4->codeBase, rc, E92102 ) ;
            }
         #else
            rc = file4seqWrite( &r4->seqwrite, block, r4->blocklen ) ;
            if ( rc < 0 )
               return error4stack( r4->codeBase, rc, E92102 ) ;
         #endif  /* S4BYTE_SWAP */

         r4->lastblock += r4->lastblockInc ;
      }
   }
   #ifdef S4BYTE_SWAP
      u4free( swap ) ;
   #endif  /* S4BYTE_SWAP */
   return 0 ;
}

int r4reindexTodisk( R4REINDEX *r4 )
{
   R4BLOCK_DATA *block ;
   int iBlock, rc ;
   B4KEY_DATA *keyOn, *keyTo ;
   #ifdef E4ANALYZE
      long dif ;
   #endif

   #ifdef S4BYTE_SWAP
      char *swap, *swapPtr ;
      int i ;
      S4LONG longVal ;
      short shortVal ;
   #endif  /* S4BYTE_SWAP */

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   /* Writes out the current block and adds references to higher blocks */
   block = r4->startBlock ;
   iBlock= 0 ;

   keyOn = (B4KEY_DATA *) (block->info + (block->nKeys-1) * r4->grouplen) ;

   #ifdef E4ANALYZE
      dif = (char *) keyOn -  (char *) block ;
      if ( ( (unsigned)dif + r4->grouplen ) > r4->blocklen || dif < 0 )
         return error4( r4->codeBase, e4result, E92102 ) ;
   #endif /* E4ANALYZE */

   for(;;)
   {
      #ifdef S4BYTE_SWAP
         swap = (char *) u4allocEr( r4->codeBase, r4->blocklen + sizeof(S4LONG) ) ;
         if ( swap == 0 )
            return error4stack( r4->codeBase, e4memory, E92102 ) ;

         memcpy( (void *)swap, (void *)block, r4->blocklen ) ;
         /* position swapPtr at beginning of B4KEY's */
         swapPtr = swap ;
         swapPtr += 6 + sizeof(short) ;
         /* move through all B4KEY's to swap 'long' */
         for ( i = 0 ; i < (*(short *)swap) ; i++ )
         {
            longVal = x4reverseLong( (void *)swapPtr ) ;
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
            swapPtr += r4->grouplen ;
         }

         longVal = x4reverseLong( (void *)swapPtr ) ;
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;

         /* swap the numKeys value */
         shortVal = x4reverseShort( (void *)swap ) ;
         memcpy( swap, (void *) &shortVal, sizeof(short) ) ;

         rc = file4seqWrite( &r4->seqwrite, swap, r4->blocklen) ;
         u4free( swap ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, block, r4->blocklen ) ;
      #endif  /* S4BYTE_SWAP */
      if ( rc < 0 )
         return error4stack( r4->codeBase, rc, E92102 ) ;

      if ( iBlock )
         memset( (void *)block, 0, r4->blocklen ) ;
      r4->lastblock += r4->lastblockInc ;

      block = (R4BLOCK_DATA *) ((char *)block + r4->blocklen) ;
      iBlock++ ;
      #ifdef E4ANALYZE
         if ( iBlock >= r4->nBlocks )
            return error4( r4->codeBase, e4info, E92102 ) ;
      #endif  /* E4ANALYZE */

      keyTo = (B4KEY_DATA *) (block->info +  block->nKeys * r4->grouplen) ;
      #ifdef E4ANALYZE
         dif = (char *) keyTo -  (char *) block  ;
         if ( ( (unsigned)dif + sizeof( long ) ) > r4->blocklen || dif < 0 )
            return error4( r4->codeBase, e4result, E92102 ) ;
      #endif  /* E4ANALYZE */
      keyTo->num = r4->lastblock ;

      if ( block->nKeys < r4->keysmax )
      {
         block->nKeys++ ;
         #ifdef E4ANALYZE
            if ( ((unsigned)dif+r4->grouplen) > r4->blocklen )
               return error4( r4->codeBase, e4result, E92102 ) ;
         #endif  /* E4ANALYZE */
         memcpy( keyTo->value, keyOn->value, r4->valuelen ) ;
         return 0 ;
      }
   }
}
#endif  /* ifdef S4MDX */

#ifdef S4FOX
int r4reindexTagHeadersWrite( R4REINDEX *r4 )
{
   TAG4FILE *tagOn ;
   INDEX4FILE *i4file ;
   int rc, totLen, iTag ;
   unsigned int exprHdrLen ;
   const char *ptr ;
   #ifdef S4BYTE_SWAP
      T4HEADER swapTagHeader ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   iTag = 2 ;
   i4file = r4->indexFile ;

   /* Now write the headers  */
   file4seqWriteInit( &r4->seqwrite, &i4file->file, 0L, r4->buffer, r4->bufferLen ) ;

   i4file->tagIndex->header.freeList = 0L ;
   exprHdrLen = 5 * sizeof(short) ;
   i4file->eof = r4->lastblock + B4BLOCK_SIZE ;

   if ( i4file->tagIndex->header.typeCode >= 64 )
   {
      #ifdef S4BYTE_SWAP
         memcpy( (void *)&swapTagHeader, (void *)&i4file->tagIndex->header, sizeof(T4HEADER) ) ;

         swapTagHeader.root = x4reverseLong( (void *)&swapTagHeader.root ) ;
         swapTagHeader.freeList = x4reverseLong( (void *)&swapTagHeader.freeList ) ;
         swapTagHeader.version = x4reverseLong( (void *)&swapTagHeader.version ) ;
         swapTagHeader.keyLen = x4reverseShort( (void *)&swapTagHeader.keyLen ) ;
         swapTagHeader.descending = x4reverseShort( (void *)&swapTagHeader.descending ) ;
         swapTagHeader.filterPos = x4reverseShort( (void *)&swapTagHeader.filterPos ) ;
         swapTagHeader.filterLen = x4reverseShort( (void *)&swapTagHeader.filterLen ) ;
         swapTagHeader.exprPos = x4reverseShort( (void *)&swapTagHeader.exprPos ) ;
         swapTagHeader.exprLen = x4reverseShort( (void *)&swapTagHeader.exprLen ) ;

         rc = file4seqWrite( &r4->seqwrite, &swapTagHeader, LEN4HEADER_WR ) ;  /* write first header part */
      #else
         rc = file4seqWrite( &r4->seqwrite, &i4file->tagIndex->header, LEN4HEADER_WR ) ;  /* write first header part */
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      rc = file4seqWriteRepeat( &r4->seqwrite, 478L, 0 ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      rc = file4seqWrite( &r4->seqwrite, &i4file->tagIndex->header.sortSeq, 8 ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      #ifdef S4BYTE_SWAP
         rc = file4seqWrite( &r4->seqwrite, &swapTagHeader.descending, exprHdrLen ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, &i4file->tagIndex->header.descending, exprHdrLen ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      rc = file4seqWriteRepeat( &r4->seqwrite, 512L, 0 ) ;  /* no expression */
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
   }

   for ( tagOn = 0 ;; )
   {
      tagOn = (TAG4FILE *)l4next( &i4file->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;
      if ( i4file->tagIndex->header.typeCode >= 64 )
         tagOn->headerOffset = ((long)iTag) * B4BLOCK_SIZE ;
      else
         tagOn->headerOffset = 0L ;

      #ifdef S4BYTE_SWAP
         memcpy( (void *)&swapTagHeader, (void *)&tagOn->header, sizeof(T4HEADER) ) ;

         swapTagHeader.root = x4reverseLong( (void *)&swapTagHeader.root ) ;
         swapTagHeader.freeList = x4reverseLong( (void *)&swapTagHeader.freeList ) ;
         swapTagHeader.version = x4reverseLong( (void *)&swapTagHeader.version ) ;
         swapTagHeader.keyLen = x4reverseShort( (void *)&swapTagHeader.keyLen ) ;
         swapTagHeader.descending = x4reverseShort( (void *)&swapTagHeader.descending ) ;
         swapTagHeader.filterPos = x4reverseShort( (void *)&swapTagHeader.filterPos ) ;
         swapTagHeader.filterLen = x4reverseShort( (void *)&swapTagHeader.filterLen ) ;
         swapTagHeader.exprPos = x4reverseShort( (void *)&swapTagHeader.exprPos ) ;
         swapTagHeader.exprLen = x4reverseShort( (void *)&swapTagHeader.exprLen ) ;

         rc = file4seqWrite( &r4->seqwrite, &swapTagHeader, LEN4HEADER_WR ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, &tagOn->header, LEN4HEADER_WR ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      rc = file4seqWriteRepeat( &r4->seqwrite, 478L, 0 ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      rc = file4seqWrite( &r4->seqwrite, &tagOn->header.sortSeq, 8 ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      #ifdef S4BYTE_SWAP
         rc = file4seqWrite( &r4->seqwrite, &swapTagHeader.descending, exprHdrLen ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, &tagOn->header.descending, exprHdrLen ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      ptr = tagOn->expr->source ;
      totLen = tagOn->header.exprLen ;
      rc = file4seqWrite( &r4->seqwrite, ptr, (unsigned int)tagOn->header.exprLen ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      if ( tagOn->filter != 0 )
      {
         ptr = tagOn->filter->source ;
         file4seqWrite( &r4->seqwrite, ptr, (unsigned int)tagOn->header.filterLen ) ;
         totLen += tagOn->header.filterLen ;
      }
      rc = file4seqWriteRepeat( &r4->seqwrite, (long)B4BLOCK_SIZE - totLen, 0 );
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      iTag += 2 ;
   }
   rc = file4lenSet( &i4file->file, i4file->eof ) ;
   if ( rc < 0 )
      return error4stack( r4->codeBase, (short)rc, E92102 ) ;

   rc = file4seqWriteFlush( &r4->seqwrite ) ;
   if ( rc < 0 )
      return error4stack( r4->codeBase, rc, E92102 ) ;
   return 0 ;

}

int r4reindexWriteKeys( R4REINDEX *r4, short int errUnique )
{
   char lastKey[I4MAX_KEY_SIZE] ;
   unsigned char *keyData ;
   int isUnique, rc, cLen, tLen, lastTrail ;
   int onCount, isFirst ;
   unsigned short int kLen ;
   void *dummyPtr ;
   long keyRec, recCount ;
   TAG4FILE *t4 ;
   unsigned long ff ;
   unsigned long rLen ;
   R4BLOCK_DATA *r4block ;

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   t4 = r4->tag ;
   kLen = (unsigned short int)t4->header.keyLen ;
   ff = 0xFFFFFFFFL ;
   isFirst = 1 ;

   memset( lastKey, r4->tag->pChar, kLen ) ;

   for ( cLen = 0 ; kLen ; kLen >>= 1, cLen++ ) ;
   kLen = (unsigned short int)t4->header.keyLen ;  /* reset the key length */
   r4->nodeHdr.trailCntLen = r4->nodeHdr.dupCntLen = (unsigned char)cLen ;

   r4->nodeHdr.trailByteCnt = (unsigned char)(0xFF >> ( 8 - ((cLen / 8) * 8 + cLen % 8))) ;
   r4->nodeHdr.dupByteCnt = r4->nodeHdr.trailByteCnt ;

   recCount = dfile4recCount( r4->dataFile, -2L ) ;
   if ( recCount < 0 )
      return error4stack( r4->codeBase, (short)recCount, E92102 ) ;
   rLen = (unsigned long)recCount ;

   for ( cLen = 0 ; rLen ; rLen>>=1, cLen++ ) ;
   r4->nodeHdr.recNumLen = (unsigned char) cLen ;
   if ( r4->nodeHdr.recNumLen < 12 )
      r4->nodeHdr.recNumLen = 12 ;

   for( tLen = r4->nodeHdr.recNumLen + r4->nodeHdr.trailCntLen + r4->nodeHdr.dupCntLen ;
        (tLen / 8)*8 != tLen ; tLen++, r4->nodeHdr.recNumLen++ ) ;  /* make at an 8-bit offset */

   rLen = ff >> ( sizeof(long)*8 - r4->nodeHdr.recNumLen ) ;
   memcpy( (void *)&r4->nodeHdr.recNumMask[0], (void *)&rLen, sizeof(long) ) ;

   r4->nodeHdr.infoLen = (unsigned char)((unsigned int)(r4->nodeHdr.recNumLen + r4->nodeHdr.trailCntLen + r4->nodeHdr.dupCntLen) / 8) ;
   r4->valuelen = t4->header.keyLen ;
   r4->grouplen = t4->header.keyLen + 2*sizeof(long) ;

   memset( (void *)r4->startBlock, 0, (unsigned int)r4->nBlocks * B4BLOCK_SIZE ) ;

   #ifdef S4FOX
      for ( r4block = r4->startBlock, onCount = 0 ; onCount < r4->nBlocks;
            r4block = (R4BLOCK_DATA *) ( (char *)r4block + B4BLOCK_SIZE), onCount++ )
      {
         memset( (void *)r4block, 0, B4BLOCK_SIZE ) ;
         r4block->header.leftNode = -1 ;
         r4block->header.rightNode = -1 ;
      }
   #endif  /* S4FOX */

   r4->nodeHdr.freeSpace = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - sizeof( B4NODE_HEADER ) ;

   r4->keysmax = (B4BLOCK_SIZE - sizeof( B4STD_HEADER ) ) / (unsigned)r4->grouplen ;

   #ifdef E4ANALYZE
      if ( r4->nodeHdr.freeSpace <= 0 || r4->keysmax <= 0 )
         return error4( r4->codeBase, e4index, E92102 ) ;
   #endif

   rc = sort4getInit( &r4->sort ) ;
   if ( rc < 0 )
      return error4stack( r4->codeBase, (short)rc, E92102 ) ;

   file4seqWriteInit( &r4->seqwrite, &r4->indexFile->file, r4->lastblock+B4BLOCK_SIZE, r4->buffer, r4->bufferLen ) ;

   #ifdef E4MISC
      if ( I4MAX_KEY_SIZE < r4->sort.sortLen )
         return error4( r4->codeBase, e4index, E92102 ) ;
   #endif  /* E4MISC */
   lastTrail = kLen ;   /* default is no available duplicates */
   isUnique = t4->header.typeCode & 0x01 ;

   for( ;; )  /* For each key to write */
   {
      rc = sort4get( &r4->sort, &keyRec, (void **) &keyData, &dummyPtr ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      #ifdef E4MISC
         if ( r4->keyCount < 0L || r4->keyCount == 0L && rc != 1 || r4->keyCount > 0L && rc == 1 )
            return error4( r4->codeBase, e4info, E92102 ) ;
         r4->keyCount-- ;
      #endif  /* E4MISC */

      if ( rc == 1 )  /* No more keys */
      {
         rc = r4reindexFinish( r4, lastKey ) ;
         if ( rc < 0 )
            return error4stack( r4->codeBase, (short)rc, E92102 ) ;
         rc = file4seqWriteFlush( &r4->seqwrite ) ;
         if ( rc < 0 )
            return error4stack( r4->codeBase, (short)rc, E92102 ) ;
         break ;
      }

      if ( isUnique )
      {
         if( isFirst )
            isFirst = 0 ;
         else
            if ( u4memcmp( keyData, lastKey, r4->sort.sortLen) == 0 )
            {
               switch( errUnique )
               {
                  case e4unique:
                  case e4candidate:
                     return error4describe( r4->codeBase, e4unique, E82103, t4->alias, (char *)0, (char *)0 ) ;
                  case r4unique:
                  case r4candidate:
                     return r4unique ;
                  default:
                     continue ;
               }
            }
      }

      /* Add the key */
      rc = r4reindexAdd( r4, keyRec, keyData, lastKey, &lastTrail ) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      memcpy( lastKey, keyData, r4->sort.sortLen ) ;
   }

   /* Now complete the tag header info. */
   t4->header.root = r4->lastblock ;
   return 0 ;
}

/* for compact leaf nodes only */
int r4reindexAdd( R4REINDEX *r4, const long rec, const unsigned char *keyValue, const char *lastKey, int *lastTrail )
{
   R4BLOCK_DATA *startBlock ;
   int rc, dupCnt, trail, kLen, iLen, len ;
   unsigned char buffer[6] ;
   char *infoPos ;

   #ifdef E4PARM_LOW
      if ( r4 == 0 || rec < 0 || keyValue == 0 )
         return error4( 0, e4parm, E92102 ) ;
   #endif

   startBlock = r4->startBlock ;
   kLen = r4->valuelen ;
   iLen = r4->nodeHdr.infoLen ;

   if ( startBlock->header.nKeys == 0 )   /* reset */
   {
      dupCnt = 0 ;
      r4->curPos = ((char *)startBlock) + B4BLOCK_SIZE ;
      memcpy( ((char *)startBlock) + sizeof( B4STD_HEADER ), (void *)&r4->nodeHdr, sizeof( B4NODE_HEADER ) ) ;
      startBlock->header.nodeAttribute |= 2 ;   /* leaf block */
      *lastTrail = kLen ;
   }
   else
      dupCnt = b4calcDups( keyValue,(const unsigned char*)lastKey, kLen ) ;

   if ( dupCnt > kLen - *lastTrail )  /* don't allow duplicating trail bytes */
      dupCnt = kLen - *lastTrail ;

   if ( dupCnt == kLen ) /* duplicate key */
      trail = 0 ;
   else
   {
      if ( d4version( r4->data ) != 0x30 && r4->codeBase->compatibility == 26 && r4->tag->filter != 0 )
         trail = 0 ;
      else
         trail = b4calcBlanks( keyValue, kLen, r4->tag->pChar ) ;
   }

   *lastTrail = trail ;

   if ( dupCnt > kLen - *lastTrail )  /* watch for case where < ' ' exissts */
      dupCnt = kLen - *lastTrail ;

   len = kLen - dupCnt - trail ;
   if ( r4->nodeHdr.freeSpace < iLen + len )
   {
      rc = r4reindexTodisk(r4, lastKey) ;
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      r4->nodeHdr.freeSpace = B4BLOCK_SIZE - sizeof( B4STD_HEADER ) - sizeof( B4NODE_HEADER ) ;
      dupCnt = 0 ;
      r4->curPos = ((char *)startBlock) + B4BLOCK_SIZE ;
      memcpy( ((char *)&startBlock->header) + sizeof( B4STD_HEADER ), (void *)&r4->nodeHdr, sizeof( B4NODE_HEADER ) ) ;
      startBlock->header.nodeAttribute |= 2 ;   /* leaf block */
      if ( d4version( r4->data ) != 0x30 && r4->codeBase->compatibility == 26 && r4->tag->filter != 0 )
         trail = 0 ;
      else
         trail = b4calcBlanks( keyValue, kLen, r4->tag->pChar ) ;
      len = kLen - trail ;
   }

   r4->curPos -= len ;
   memcpy( r4->curPos, keyValue + dupCnt, (unsigned int)len ) ;
   infoPos = ((char *)&startBlock->header) + sizeof(B4STD_HEADER) + sizeof(B4NODE_HEADER) + startBlock->header.nKeys * iLen ;
   x4putInfo( &r4->nodeHdr, buffer, rec, trail, dupCnt ) ;
   memcpy( infoPos, (void *)buffer, (unsigned int)iLen ) ;

   r4->nodeHdr.freeSpace -= (unsigned char) ( len + iLen ) ;
   startBlock->header.nKeys++ ;
   return 0 ;
}

int r4reindexFinish( R4REINDEX *r4, char *keyValue )
{
   R4BLOCK_DATA *block ;
   int rc, iBlock ;
   long revLb, lRecno ;
   char *keyTo ;
   #ifdef S4DATA_ALIGN
      long longTemp ;
   #endif
   #ifdef S4BYTE_SWAP
      char swap[B4BLOCK_SIZE] ;
      char *swapPtr ;
      int i ;
      S4LONG longVal ;
      short shortVal ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   block = r4->startBlock ;

   if ( r4->nBlocksUsed <= 1 ) /* just output first block */
   {
      memcpy( ((char *)block) + sizeof( B4STD_HEADER ), (void *)&r4->nodeHdr, sizeof( B4NODE_HEADER ) ) ;

      block->header.nodeAttribute |= (short)3 ;   /* leaf and root block */

      #ifdef S4BYTE_SWAP
         memcpy( (void *)swap, (void *)block, B4BLOCK_SIZE ) ;

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

         if (block->header.nodeAttribute >= 2 ) /* if block is a leaf */
         {
            /* swap B4NODE_HEADER members */
            shortVal = x4reverseShort( (void *)swapPtr ) ; /* freeSpace */
            memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
            swapPtr += sizeof(short) ;

            longVal = x4reverseLong( (void *)swapPtr ) ;   /* recNumMask */
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         }
         else /* if block is a branch */
         {
            shortVal = r4->tag->header.keyLen + sizeof(S4LONG) ;

            /* position swapPtr to end of first key expression */
            swapPtr += r4->tag->header.keyLen ;

            /* move through all B4KEY's to swap 'long's */
            for ( i = 0 ; i < (int)block->header.nKeys ; i++ )
            {
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += sizeof(S4LONG) ;
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += shortVal ;
            }
         }

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

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nodeAttribute */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nKeys */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* leftNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* rightNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         rc = file4seqWrite( &r4->seqwrite, swap,B4BLOCK_SIZE ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, block,B4BLOCK_SIZE ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;
      r4->lastblock += B4BLOCK_SIZE ;
   }
   else
   {
      memcpy( (void *)&lRecno, (void *) (((char *)(&block->header)) + sizeof(B4STD_HEADER)
              + sizeof(B4NODE_HEADER) + (block->header.nKeys - 1) * r4->nodeHdr.infoLen), sizeof( long ) ) ;
      #ifdef S4DO_BYTEORDER
         lRecno = x4reverseLong( (void *)&lRecno ) ;
      #endif
      #ifdef S4DATA_ALIGN
         memcpy( (void *)&longTemp, (void *)&r4->nodeHdr.recNumMask[0], sizeof(S4LONG) ) ;
         lRecno &= longTemp ;
      #else
         lRecno &= *(long *)&r4->nodeHdr.recNumMask[0] ;
      #endif

      if ( block->header.nodeAttribute >= 2 )  /* if leaf, record freeSpace */
         memcpy( ((char *)block) + sizeof( B4STD_HEADER ), (void *)&r4->nodeHdr, sizeof( B4NODE_HEADER ) ) ;

      #ifdef S4BYTE_SWAP
         memcpy( (void *)swap, (void *)r4->startBlock, B4BLOCK_SIZE ) ;

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

         if (block->header.nodeAttribute >= 2 ) /* if block is a leaf */
         {
            /* swap B4NODE_HEADER members */
            shortVal = x4reverseShort( (void *)swapPtr ) ; /* freeSpace */
            memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
            swapPtr += sizeof(short) ;

            longVal = x4reverseLong( (void *)swapPtr ) ;   /* recNumMask */
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         }
         else /* if block is a branch */
         {
            shortVal = r4->tag->header.keyLen + sizeof(S4LONG) ;

            /* position swapPtr to end of first key expression */
            swapPtr += r4->tag->header.keyLen ;

            /* move through all B4KEY's to swap 'long's */
            for ( i = 0 ; i < (int) block->header.nKeys ; i++ )
            {
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += sizeof(S4LONG) ;
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += shortVal ;
            }
         }

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

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nodeAttribute */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nKeys */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* leftNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* rightNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         rc = file4seqWrite( &r4->seqwrite, swap,B4BLOCK_SIZE ) ;
      #else
         rc = file4seqWrite(&r4->seqwrite, r4->startBlock,B4BLOCK_SIZE ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      r4->lastblock += B4BLOCK_SIZE ;

      lRecno = x4reverseLong( (void *)&lRecno ) ;

      for( iBlock=1; iBlock < r4->nBlocksUsed ; iBlock++ )
      {
         block = (R4BLOCK_DATA *) ((char *)block + B4BLOCK_SIZE) ;
         keyTo = ((char *) (&block->header)) + sizeof(B4STD_HEADER) + block->header.nKeys * r4->grouplen ;
         block->header.nKeys++ ;
         #ifdef E4MISC
            if ( (char *) keyTo -  (char *) block + r4->grouplen > B4BLOCK_SIZE ||
                 (char *) keyTo -  (char *) block < 0 )
               return error4( r4->codeBase, e4result, E92102 ) ;
         #endif  /* E4MISC */
         memcpy( keyTo, (void *)keyValue, (unsigned int)r4->valuelen ) ;
         keyTo += r4->valuelen ;
         memcpy( keyTo, (void *)&lRecno, sizeof( long ) ) ;
         revLb = x4reverseLong( (void *)&r4->lastblock ) ;
         memcpy( keyTo + sizeof( long ), (void *)&revLb, sizeof( long ) ) ;

         if ( iBlock == r4->nBlocksUsed - 1 )
            block->header.nodeAttribute = 1 ;  /* root block */

         #ifdef S4BYTE_SWAP
            memcpy( (void *)swap, (void *)block, B4BLOCK_SIZE ) ;

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

            if (block->header.nodeAttribute >= 2 ) /* if block is a leaf */
            {
               /* swap B4NODE_HEADER members */
               shortVal = x4reverseShort( (void *)swapPtr ) ; /* freeSpace */
               memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
               swapPtr += sizeof(short) ;

               longVal = x4reverseLong( (void *)swapPtr ) ;   /* recNumMask */
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
            }
            else /* if block is a branch */
            {
               shortVal = r4->tag->header.keyLen + sizeof(S4LONG) ;

               /* position swapPtr to end of first key expression */
               swapPtr += r4->tag->header.keyLen ;

               /* move through all B4KEY's to swap 'long's */
               for ( i = 0 ; i < (int) block->header.nKeys ; i++ )
               {
                  longVal = x4reverseLong( (void *)swapPtr ) ;
                  memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
                  swapPtr += sizeof(S4LONG) ;
                  longVal = x4reverseLong( (void *)swapPtr ) ;
                  memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
                  swapPtr += shortVal ;
               }
            }

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

            shortVal = x4reverseShort( (void *)swapPtr ) ; /* nodeAttribute */
            memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
            swapPtr += sizeof(short) ;

            shortVal = x4reverseShort( (void *)swapPtr ) ; /* nKeys */
            memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
            swapPtr += sizeof(short) ;

            longVal = x4reverseLong( (void *)swapPtr ) ;   /* leftNode */
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
            swapPtr += sizeof(S4LONG) ;

            longVal = x4reverseLong( (void *)swapPtr ) ;   /* rightNode */
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
            swapPtr += sizeof(S4LONG) ;

            rc = file4seqWrite( &r4->seqwrite, swap, B4BLOCK_SIZE ) ;
         #else
            rc = file4seqWrite( &r4->seqwrite, block, B4BLOCK_SIZE )  ;
         #endif
         if ( rc < 0 )
            return error4stack( r4->codeBase, (short)rc, E92102 ) ;

         r4->lastblock += B4BLOCK_SIZE ;
      }
   }

   return 0 ;
}

/* Writes out the current block and adds references to higher blocks */
int r4reindexTodisk( R4REINDEX *r4, const char *keyValue )
{
   R4BLOCK_DATA *block ;
   long lRecno, revLb ;
   int tnUsed, rc ;
   char *keyTo ;
   #ifdef S4DATA_ALIGN
      long longTemp ;
   #endif
   #ifdef S4BYTE_SWAP
      char swap[B4BLOCK_SIZE] ;
      char *swapPtr ;
      int i ;
      S4LONG longVal ;
      short shortVal ;
   #endif
   #ifdef E4ANALYZE
      int iBlock ;
      iBlock = 0 ;
   #endif

   #ifdef E4PARM_LOW
      if ( r4 == 0 )
         return error4( 0, e4parm_null, E92102 ) ;
   #endif

   block = r4->startBlock ;
   tnUsed = 1 ;

   memcpy( (void *)&lRecno, ((unsigned char *) (&block->header)) + sizeof(B4STD_HEADER)
           + sizeof(B4NODE_HEADER) + (block->header.nKeys - 1) * r4->nodeHdr.infoLen, sizeof( long ) ) ;
   #ifdef S4DO_BYTEORDER
      lRecno = x4reverseLong( (void *)&lRecno ) ;
   #endif
   #ifdef S4DATA_ALIGN
      memcpy( (void *)&longTemp, (void *)&r4->nodeHdr.recNumMask[0], sizeof(S4LONG) ) ;
      lRecno &= longTemp ;
   #else
      lRecno &= *(long *)&r4->nodeHdr.recNumMask[0] ;
   #endif
   lRecno = x4reverseLong( (void *)&lRecno ) ;

   for(;;)
   {
      tnUsed++ ;
      r4->lastblock += B4BLOCK_SIZE ;
      /* next line only works when on leaf branches... */
      block->header.rightNode = r4->lastblock + B4BLOCK_SIZE ;
      if ( block->header.nodeAttribute >= 2 )  /* if leaf, record freeSpace */
         memcpy( ((char *)block) + sizeof( B4STD_HEADER ), (void *)&r4->nodeHdr.freeSpace, sizeof( r4->nodeHdr.freeSpace ) ) ;

      #ifdef S4BYTE_SWAP
         memcpy( (void *)swap, (void *)block, B4BLOCK_SIZE ) ;

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

         /* if block is a leaf */
         if (r4->startBlock->header.nodeAttribute >= 2 )
         {
            /* swap B4NODE_HEADER members */
            shortVal = x4reverseShort( (void *)swapPtr ) ; /* freeSpace */
            memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
            swapPtr += sizeof(short) ;

            longVal = x4reverseLong( (void *)swapPtr ) ;   /* recNumMask */
            memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         }
         else /* if block is a branch */
         {
            shortVal = r4->tag->header.keyLen + sizeof(S4LONG) ;

            /* position swapPtr to end of first key expression */
            swapPtr += r4->tag->header.keyLen ;

            /* move through all B4KEY's to swap 'long's */
            for ( i = 0 ; i < (int) block->header.nKeys ; i++ )
            {
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += sizeof(S4LONG) ;
               longVal = x4reverseLong( (void *)swapPtr ) ;
               memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
               swapPtr += shortVal ;
            }
         }

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

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nodeAttribute */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         shortVal = x4reverseShort( (void *)swapPtr ) ; /* nKeys */
         memcpy( swapPtr, (void *) &shortVal, sizeof(short) ) ;
         swapPtr += sizeof(short) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* leftNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         longVal = x4reverseLong( (void *)swapPtr ) ;   /* rightNode */
         memcpy( swapPtr, (void *) &longVal, sizeof(S4LONG) ) ;
         swapPtr += sizeof(S4LONG) ;

         rc = file4seqWrite( &r4->seqwrite, swap, B4BLOCK_SIZE ) ;
      #else
         rc = file4seqWrite( &r4->seqwrite, block, B4BLOCK_SIZE ) ;
      #endif
      if ( rc < 0 )
         return error4stack( r4->codeBase, (short)rc, E92102 ) ;

      memset( (void *)block, 0, B4BLOCK_SIZE ) ;
      block->header.leftNode = r4->lastblock ;
      block->header.rightNode = -1 ;

      block = (R4BLOCK_DATA *) ((char *)block + B4BLOCK_SIZE) ;
      #ifdef E4ANALYZE
         iBlock++ ;
         if ( iBlock >= r4->nBlocks )
            return error4( r4->codeBase, e4info, E92102 ) ;
      #endif  /* E4ANALYZE */

      if ( block->header.nKeys < r4->keysmax )
      {
         keyTo = ((char *) (&block->header)) + sizeof(B4STD_HEADER) + block->header.nKeys * r4->grouplen ;
         block->header.nKeys++ ;
         #ifdef E4ANALYZE
            if ( (char *) keyTo -  (char *) block + r4->grouplen > B4BLOCK_SIZE || (char *) keyTo -  (char *) block < 0 )
               return error4( r4->codeBase, e4result, E92102 ) ;
         #endif  /* E4ANALYZE */
         memcpy( keyTo, (void *)keyValue, (unsigned int)r4->valuelen ) ;
         keyTo += r4->valuelen ;
         memcpy( keyTo, (void *)&lRecno, sizeof( long ) ) ;
         revLb = x4reverseLong( (void *)&r4->lastblock ) ;
         memcpy( keyTo + sizeof( long ), (void *)&revLb, sizeof( long ) ) ;

         if ( block->header.nKeys < r4->keysmax )  /* then done, else do next one up */
         {
            if ( tnUsed > r4->nBlocksUsed )
               r4->nBlocksUsed = tnUsed ;
            return 0 ;
         }
      }
      #ifdef E4ANALYZE
         else  /* should never occur */
            return error4( r4->codeBase, e4result, E92102 ) ;
      #endif  /* E4ANALYZE */
   }
}
#endif  /* S4FOX */
#endif  /* S4CLIENT */
#endif  /* N4OTHER  */
#endif  /* S4INDEX_OFF */
#endif  /* S4WRITE_OFF */