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

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

#ifdef S4CLIENT
int S4FUNCTION d4check( DATA4 *d4 )
{
   #ifdef S4INDEX_OFF
      return 0 ;
   #else
      CONNECTION4 *connection ;
      int rc ;
      CONNECTION4CHECK_INFO_OUT *out ;

      #ifdef E4PARM_HIGH
         if ( d4 == 0 )
            return error4( 0, e4parm_null, E95702 ) ;
      #endif

      #ifndef S4OFF_MULTI
         #ifdef S4SERVER
            rc = dfile4lockFile( d4->dataFile, d4->currentClientId, d4->serverId ) ;   /* returns -1 if error4code( codeBase ) < 0 */
         #else
            rc = d4lockFile( d4 ) ;   /* returns -1 if error4code( codeBase ) < 0 */
         #endif
         if ( rc )
            return rc ;
      #endif

      connection = d4->dataFile->connection ;
      if ( connection == 0 )
         return e4connection ;
      connection4assign( connection, CON4CHECK, data4clientId( d4 ), data4serverId( d4 ) ) ;
      connection4send( connection ) ;
      rc = connection4receive( connection ) ;
      if ( rc < 0 )
         return rc ;
      rc = connection4status( connection ) ;
      if ( rc != 0 )
         return connection4error( connection, d4->codeBase, rc, E95702 ) ;

      if ( connection4len( connection ) != sizeof( CONNECTION4CHECK_INFO_OUT ) )
         return error4( d4->codeBase, e4packetLen, E95702 ) ;
      out = (CONNECTION4CHECK_INFO_OUT *)connection4data( connection ) ;
      if ( out->lockedDatafile == 1 )
         d4->dataFile->fileLock = d4 ;
      return 0 ;
   #endif  /* S4INDEX_OFF */
}
#else

#ifndef S4INDEX_OFF

typedef struct
{
   F4FLAG flag ;

   TAG4FILE *tag ;
   char *oldKey ;
   long oldRec ;
   long numRecs ;
   int doCompare ;  /* Do not compare the first time */
   CODE4 *codeBase ;
   DATA4 *data ;
} C4CHECK ;

static int c4checkInit( C4CHECK *check, CODE4 *cb, TAG4FILE *t4, long nRecs, DATA4 *d4 )
{
   int rc ;

   memset( (void *)check, 0, sizeof(C4CHECK) ) ;

   rc = f4flagInit( &check->flag, cb, (unsigned long)nRecs ) ;
   if ( rc < 0 )
      return rc ;

   check->codeBase = cb ;
   check->tag = t4 ;
   check->numRecs = nRecs ;
   check->data = d4 ;

   check->oldKey = (char *)u4allocFree( t4->codeBase, (long)t4->header.keyLen ) ;
   if (check->oldKey == 0)
      return e4memory ;
   return 0 ;
}

static void c4checkFree( C4CHECK *c4 )
{
   u4free( c4->flag.flags ) ;
   u4free( c4->oldKey ) ;
}

static int c4checkRecord( C4CHECK *check )
{
   B4KEY_DATA *keyData ;
   TAG4FILE *t4 ;
   unsigned char *newPtr ;
   int len, rc ;

   t4 = check->tag ;

   keyData = tfile4keyData( check->tag ) ;
   if ( keyData == 0 )
      return error4( check->codeBase, e4index, E95701 ) ;

   if ( keyData->num < 1  ||  keyData->num > check->numRecs )
      return error4describe( check->codeBase, e4index, E85703, check->tag->alias, (char *)0, (char *)0 ) ;

   if ( f4flagIsSet( &check->flag, (unsigned long)keyData->num) )
      return error4describe( check->codeBase, e4index, E85703, check->tag->alias, (char *)0, (char *)0 ) ;
   else
      f4flagSet( &check->flag, (unsigned long)keyData->num ) ;

   rc = d4go( check->data, keyData->num ) ;
   if ( rc < 0 )
      return rc ;
   rc = expr4context( t4->expr, check->data ) ;
   if ( rc < 0 )
      return rc ;

   len = tfile4exprKey( t4, &newPtr ) ;

   if ( len != t4->header.keyLen )
      return error4describe( check->codeBase, e4index, E85704, t4->alias, (char *)0, (char *)0 ) ;

   #ifdef S4MDX
      if ( expr4type( t4->expr ) == r4num )
      {
         if ( c4bcdCmp( newPtr, keyData->value, 0 ) != 0 )
            return error4describe( check->codeBase, e4index, E85705, t4->alias, (char *)0, (char *)0 ) ;
      }
      else
   #endif
   if ( c4memcmp( newPtr, keyData->value, (unsigned int)t4->header.keyLen ) != 0 )
      return error4describe( check->codeBase, e4index, E85705, t4->alias, (char *)0, (char *)0  ) ;

   if ( check->doCompare )
   {
      #ifdef S4FOX
         #ifdef S4VFP_KEY
            if ( tfile4type( t4 ) != r4str )
               rc = c4memcmp( check->oldKey, newPtr, (unsigned int)t4->header.keyLen ) ;
            else
         #endif
               rc = u4keycmp( check->oldKey, newPtr, (unsigned int)t4->header.keyLen, (unsigned int)t4->header.keyLen, 0, &t4->vfpInfo ) ;
      #else
         rc = (*t4->cmp)( check->oldKey, newPtr, (unsigned int)t4->header.keyLen ) ;
      #endif

      if ( rc > 0)
         error4describe( check->codeBase, e4index, E85706, t4->alias, (char *)0, (char *)0 ) ;
      #ifdef S4FOX
         if ( rc == 0  &&  keyData->num <= check->oldRec )
            error4describe( check->codeBase, e4index, E85707, t4->alias, (char *)0, (char *)0 ) ;
      #endif /* S4FOX */

      #ifdef S4FOX
         if ( t4->header.typeCode & 0x01 )
      #else
         if ( t4->header.unique )
      #endif /* S4FOX */
            if ( rc == 0 )
               error4describe( check->codeBase, e4index, E85708, t4->alias, (char *)0, (char *)0 ) ;
   }
   else
      check->doCompare = 1 ;

   memcpy( check->oldKey, newPtr, (unsigned int)t4->header.keyLen ) ;

   check->oldRec = keyData->num ;

   if ( error4code( check->codeBase ) < 0 )
      return error4code( check->codeBase )  ;
   return 0 ;
}

#ifdef S4CLIPPER
static int tfile4blockCheck( TAG4FILE *t4, int firstTime )
{
   B4BLOCK *b4 ;
   int i, bType, rc ;
   CODE4 *c4 ;

   if ( firstTime )
      tfile4upToRoot( t4 ) ;

   c4 = t4->codeBase ;
   b4 = (B4BLOCK *)t4->blocks.lastNode ;
   if ( b4 == 0 )
      return 0 ;
   if ( b4->nKeys < t4->header.keysHalf && t4->header.root / 512 != b4->fileBlock )
      return error4describe( c4, e4index, E85709, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
   if ( !b4leaf( b4 ) )
   {
      for ( i = 0 ; i <= b4->nKeys ; i++ )
      {
         b4->keyOn = i ;
         rc = tfile4down( t4 ) ;
         if ( rc != 0 )
            return error4describe( c4, e4index, E81601, tfile4alias( t4 ), 0, 0 ) ;
         if ( i == 0 )
            bType = b4leaf( (B4BLOCK *)t4->blocks.lastNode ) ;
         else
            if ( bType != b4leaf( (B4BLOCK *)t4->blocks.lastNode ) )
               return error4describe( c4, e4index, E85709, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
         rc = tfile4blockCheck( t4, 0 ) ;
         if ( rc != 0 )
            return rc ;
         rc = tfile4up( t4 ) ;
         if ( rc != 0 )
            return error4describe( c4, e4index, E81601, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
      }
   }
   return 0 ;
}
#endif

#ifdef S4NDX
static int tfile4blockCheck( TAG4FILE *t4, int firstTime )
{
   B4BLOCK *b4 ;
   int i, bType, rc ;
   CODE4 *c4 ;

   if ( firstTime )
      tfile4upToRoot( t4 ) ;

   c4 = t4->codeBase ;
   b4 = (B4BLOCK *)t4->blocks.lastNode ;
   if ( b4 == 0 )
      return 0 ;
   if ( !b4leaf( b4 ) )
   {
      for ( i = 0 ; i <= b4->nKeys ; i++ )
      {
         if ( b4key( b4, b4->keyOn )->pointer >= t4->header.eof )
            return error4describe( c4, e4index, E81601, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
         b4->keyOn = i ;
         rc = tfile4down( t4 ) ;
         if ( rc != 0 )
            return error4describe( c4, e4index, E81601, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
         rc = tfile4blockCheck( t4, 0 ) ;
         if ( rc != 0 )
            return rc ;
         rc = tfile4up( t4 ) ;
         if ( rc != 0 )
            return error4describe( c4, e4index, E81601, tfile4alias( t4 ), (char *)0, (char *)0 ) ;
      }
   }
   return 0 ;
}
#endif

int t4check( TAG4 *t4 )
{
   C4CHECK check ;
   int rc, isRecord, keysSkip, rc2 ;
   CODE4 *c4 ;
   TAG4 *oldSelectedTag ;
   B4BLOCK *blockOn ;
   long baseSize, onRec ;
   unsigned char *ptr ;
   DATA4 *d4 ;
   #ifdef S4FOX
      unsigned char *tempVal ;
      long tempLong ;
   #endif
   #ifndef S4CLIPPER
      B4KEY_DATA *keyBranch, *keyLeaf ;
   #endif
   #ifdef S4PRINTF_OUT
      unsigned long loop ;
   #endif

   #ifdef E4PARM_LOW
      if ( t4 == 0 )
         return error4( 0, e4parm_null, E95703 ) ;
   #endif

   d4 = t4->index->data ;
   c4 = d4->codeBase ;

   rc = expr4context( t4->tagFile->expr, d4 ) ;
   if ( rc < 0 )
      return rc ;
   if ( t4->tagFile->filter != 0 )
   {
      rc = expr4context( t4->tagFile->filter, d4 ) ;
      if ( rc < 0 )
         return rc ;
   }

   #ifndef S4OFF_MULTI
      #ifdef S4SERVER
         rc = dfile4lockFile( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ) ) ;   /* returns -1 if error4code( codeBase ) < 0 */
      #else
         rc = d4lockFile( d4 ) ;   /* returns -1 if error4code( codeBase ) < 0 */
      #endif
      if ( rc != 0 )
         return rc ;
      #ifdef N4OTHER
         rc = i4lock( t4->index ) ;
      #else
         rc = index4lock( t4->tagFile->indexFile, data4serverId( d4 ) ) ;
      #endif
      if ( rc != 0 )
         return rc ;
      rc = d4refresh( d4 ) ;
      if ( rc != 0 )
         return rc ;
   #endif

   #ifndef S4OFF_WRITE
      rc = d4updateRecord( d4, 1 ) ;
      if ( rc < 0 )
         return rc ;
      if ( rc )
         return error4( c4, rc, E95703 ) ;
   #endif

   oldSelectedTag = d4tagSelected( d4 ) ;
   d4tagSelect( d4, t4 ) ;

   #ifdef N4OTHER
      rc = tfile4blockCheck( t4->tagFile, 1 ) ;
      if ( rc != 0 )
         return rc ;
   #endif

   baseSize = d4recCount( d4 ) ;
   if ( baseSize < 0L )
      return (int)baseSize ;

   rc = d4top( d4 ) ;
   if (rc < 0 )
      return rc ;
   if ( rc == 0 )
      rc = 1 ;

   if ( baseSize == 0L )
   {
      if ( tfile4skip( t4->tagFile, 1L ) == 0 )
      {
         d4tagSelect( d4, oldSelectedTag ) ;
         return( 0 ) ;
      }
      else
         return error4describe( c4, e4index, E85710, d4alias( d4 ), tfile4alias( t4->tagFile ), (char *)0 ) ;
   }

   rc2 = c4checkInit( &check, c4, t4->tagFile, baseSize, d4 ) ;
   if ( rc2 < 0 )
      return rc2 ;

   #ifdef S4PRINTF_OUT
      loop = 0 ;
      printf( "On Rec %10ld\n", loop ) ;
   #endif
   while ( rc == 1 )
   {
      rc = c4checkRecord( &check ) ;
      if ( rc )
         break ;
      rc = (int)tfile4skip( t4->tagFile, 1L ) ;
      if ( rc < 0 )
         break ;
      #ifdef S4PRINTF_OUT
         if ( (loop++ % 100) == 0 )
            printf( "\b\b\b\b\b\b\b\b\b\b%10ld", loop ) ;
      #endif
   }

   if ( rc < 0 )
   {
      c4checkFree( &check ) ;
      return rc ;
   }

   isRecord = 1 ;

   /* Now Test for Duplication */
   for ( onRec = 1;  onRec <= baseSize; onRec++)
   {
      #ifndef S4NDX
         if ( t4->tagFile->filter != 0 )
         {
            if ( d4go( d4, onRec ) < 0 )
               break ;
            rc2 = expr4context( t4->tagFile->filter, check.data ) ;
            if ( rc2 < 0 )
               return rc2 ;

            isRecord = expr4true( t4->tagFile->filter ) ;
         }
      #endif

      if ( f4flagIsSet( &check.flag, (unsigned long)onRec ) )
      {
         if ( !isRecord )
         {
            error4describe( c4, e4index, E95703, t4->tagFile->alias, (char *)0, (char *)0 ) ;
            break ;
         }
      }
      else
      {
         if ( ! isRecord )
            continue ;

         #ifdef S4FOX
            if ( t4->tagFile->header.typeCode & 0x01 )
         #else
            if ( t4->tagFile->header.unique )
         #endif
            {
               if ( d4go(d4,onRec) < 0 )
                  break ;
               if ( expr4context( t4->tagFile->expr, check.data ) < 0 )
                  break ;
               if ( tfile4exprKey( t4->tagFile, &ptr) < 0 )
                  break ;
               if ( tfile4seek( t4->tagFile, ptr, expr4keyLen( t4->tagFile->expr ) ) == 0 )
                  continue ;
            }

         error4describe( c4, e4index, E85711, t4->tagFile->alias, 0, 0 ) ;
         break ;
      }
   }

   c4checkFree( &check ) ;
   if ( error4code( c4 ) < 0 )
      return error4code( c4 ) ;

   /* Now make sure the block key pointers match the blocks they point to. */
   /* This needs to be true for d4seek to function perfectly. */

   rc = d4bottom( d4 ) ;
   if ( rc < 0 )
      return rc ;

   if ( rc == 3 )
   {
      d4tagSelect( d4, oldSelectedTag ) ;
      return 0 ;
   }

   for(;;)
   {
      #ifdef S4FOX
         keysSkip = -tfile4block(t4->tagFile)->header.nKeys ;
      #else
         keysSkip = -tfile4block(t4->tagFile)->nKeys ;
      #endif

      rc = (int)tfile4skip( t4->tagFile, (long) keysSkip ) ;
      if ( error4code( c4 ) < 0 )
         return error4code( c4 ) ;
      if ( rc != keysSkip )
      {
         d4tagSelect( d4, oldSelectedTag ) ;
         return 0 ;
      }

      blockOn = (B4BLOCK *)t4->tagFile->blocks.lastNode ;
      if ( blockOn == 0 )
         return error4describe( c4, e4index, E85712, tfile4alias( t4->tagFile ), (char *)0, (char *)0 ) ;

      #ifdef S4FOX
         tempVal = (unsigned char *)u4allocFree( c4, (long)t4->tagFile->header.keyLen ) ;
         if ( tempVal == 0 )
            return error4stack( c4, e4memory, E95703 ) ;
         memcpy( tempVal, (void *)b4keyKey( blockOn, blockOn->keyOn ), (unsigned int)t4->tagFile->header.keyLen ) ;
         tempLong = b4recNo( blockOn, blockOn->keyOn ) ;

         if ( tfile4go( t4->tagFile, tempVal, tempLong, 0 ) )
         {
            u4free( tempVal ) ;
            return error4describe( c4, e4index, E85712, tfile4alias( t4->tagFile ), (char *)0, (char *)0 ) ;
         }
         u4free( tempVal ) ;
      #endif

      #ifndef S4CLIPPER
         for ( ;; )
         {
            blockOn = (B4BLOCK *)blockOn->link.p ;
            if ( blockOn == 0 )
               break ;
            if ( blockOn == (B4BLOCK *)t4->tagFile->blocks.lastNode )
               break ;

            #ifdef S4FOX
               if ( blockOn->keyOn < blockOn->header.nKeys )
            #else
               if ( blockOn->keyOn < blockOn->nKeys )
            #endif
               {
                  keyBranch = b4key( blockOn, blockOn->keyOn ) ;
                  keyLeaf = b4key( tfile4block( t4->tagFile ), tfile4block( t4->tagFile )->keyOn ) ;

                  if ( c4memcmp( keyBranch->value, keyLeaf->value, (unsigned int)t4->tagFile->header.keyLen) != 0 )
                     return error4describe( c4, e4index, E85712, tfile4alias( t4->tagFile ), (char *)0, (char *)0 ) ;

                  break ;
               }
         }
         if ( blockOn == 0 )
            return error4describe( c4, e4index, E85712, tfile4alias( t4->tagFile ), (char *)0, (char *)0 ) ;
      #endif
   }
}

#ifdef S4FOX
static int flag4blocks( TAG4FILE *t4, F4FLAG *f4, long *node1, long *node2, long *node3 )
{
   int i, rc ;
   B4BLOCK *blockOn ;
   long flagNo ;

   rc = tfile4down( t4 ) ;
   if ( rc < 0 )
      return rc ;
   if ( rc == 2 )
      return e4index ;
   if ( rc == 1 )
      return error4( t4->codeBase, e4index, E95704 ) ;

   blockOn = tfile4block(t4) ;

   flagNo = blockOn->fileBlock / B4BLOCK_SIZE ;
   if ( *node2 != -2 )
      if ( *node2 != blockOn->fileBlock )
         return error4( t4->codeBase, e4index, E81601 ) ;
   if ( *node1 != -2 )
      if ( *node1 != blockOn->header.leftNode )
         return error4( t4->codeBase, e4index, E81601 ) ;
   if ( *node3 != -2 )
      if ( *node3 != blockOn->header.rightNode )
         return error4( t4->codeBase, e4index, E81601 ) ;

   if ( f4flagIsSet( f4, (unsigned long)flagNo ) )
      return error4( t4->codeBase, e4index, E81601 ) ;

   rc = f4flagSet( f4, (unsigned long)flagNo ) ;
   if ( rc < 0 )
      return rc ;
   if ( ! b4leaf(blockOn) )
   {
      if ( blockOn->header.leftNode == -1 )
         *node1 = -1L ;
      else
         *node1 = -2L ;
      *node2 = b4key( blockOn, 0 )->num ;

      for( i = 0; i < blockOn->header.nKeys; i++ )
      {
         b4go( blockOn, (long)i ) ;
         if ( i == blockOn->header.nKeys - 1 && blockOn->header.rightNode == -1 )
            *node3 = -1 ;
         else
            *node3 = -2 ;
         rc = flag4blocks( t4, f4, node1, node2, node3 ) ;
         if ( rc < 0 )
            return rc ;
      }
   }

   *node1 = blockOn->fileBlock ;
   *node2 = blockOn->header.rightNode ;
   tfile4up(t4) ;
   return 0 ;
}
#else
#ifndef S4NDX
static int flag4blocks( TAG4FILE *t4, F4FLAG *f4 )
{
   int i, rc ;
   B4BLOCK *blockOn ;
   long flagNo ;

   rc = tfile4down( t4 ) ;
   if ( rc < 0 )
      return rc ;
   if ( rc == 2 )
      return -1 ;
   if ( rc == 1 )
      return error4( t4->codeBase, e4index, E95704 ) ;

   blockOn = tfile4block(t4) ;

   #ifdef S4CLIPPER
      flagNo = (blockOn->fileBlock) * I4MULTIPLY / B4BLOCK_SIZE ;
   #else
      flagNo = (blockOn->fileBlock-4) * I4MULTIPLY / t4->indexFile->header.blockRw ;
   #endif

   if ( f4flagIsSet( f4, flagNo ) )
      return error4( t4->codeBase, e4index, E81601 ) ;

   rc = f4flagSet( f4, flagNo ) ;
   if ( rc < 0 )
      return rc ;
   if ( ! b4leaf(blockOn) )
   {
      #ifdef S4MDX
         for( i = 0; i <= blockOn->nKeys; i++ )
         {
            blockOn->keyOn = i ;
            rc = flag4blocks( t4, f4 ) ;
            if ( rc < 0 )
               return rc ;
         }
      #else
         #ifdef S4CLIPPER
            for( i = 0; i <= blockOn->nKeys; i++ )
            {
               blockOn->keyOn = i ;
               rc = flag4blocks( t4, f4 ) ;
               if ( rc < 0 )
                  return rc ;
            }
         #endif
      #endif
   }

   tfile4up(t4) ;
   return 0 ;
}
#endif   /*  ifndef S4NDX  */
#endif   /*  ifdef S4FOX   */

/* checks that all blocks in the file are on free list or are being used */
#ifdef P4ARGS_USED
   #pragma argsused
#endif
static int i4checkBlocks( INDEX4 *i4 )
{
   #ifndef N4OTHER
      TAG4FILE  *tagOn ;
      F4FLAG  flags ;
      #ifndef S4OFF_MULTI
         int rc ;
      #endif
      long flagNo ;
      S4LONG totBlocks, freeBlock, eofBlockNo, len ;
      CODE4 *c4 ;
      #ifdef S4FOX
         long node1, node2, node3 ;
      #else
         T4DESC  desc[48] ;
         int i ;
      #endif

      c4 = i4->codeBase ;

      #ifndef S4OFF_MULTI
         rc = d4lockIndex( i4->data ) ;
         if ( rc < 0 )
            return rc ;
      #endif

      len = file4len(&i4->indexFile->file) ;

      #ifdef S4MDX
         totBlocks = (len-2048) / i4->indexFile->header.blockRw ;
      #else
         totBlocks = len / B4BLOCK_SIZE ;
      #endif

      /* First Flag for the Free Chain */
      f4flagInit( &flags, i4->codeBase, (unsigned long)totBlocks ) ;

      eofBlockNo = len/I4MULTIPLY ;
      #ifdef S4FOX
         for ( freeBlock = i4->indexFile->tagIndex->header.freeList ; freeBlock ; )
      #else
         for ( freeBlock = i4->indexFile->header.freeList ; freeBlock ; )
      #endif
         {
            if ( freeBlock == eofBlockNo  ||  error4code( c4 ) < 0 )
               break ;

            #ifdef S4MDX
               flagNo = (int)((freeBlock-4)*I4MULTIPLY/i4->indexFile->header.blockRw) ;
            #else
               flagNo = (int) (freeBlock / B4BLOCK_SIZE) ;
            #endif

            if ( freeBlock >= eofBlockNo  || f4flagIsSet(&flags, (unsigned long)flagNo ) )
            {
               error4( c4, e4index, E85701 ) ;
               break ;
            }
            f4flagSet( &flags, (unsigned long)flagNo ) ;

            #ifdef S4MDX
               file4readAll( &i4->indexFile->file, freeBlock * I4MULTIPLY + sizeof(long), &freeBlock, sizeof(freeBlock) ) ;
            #else
               file4readAll( &i4->indexFile->file, freeBlock * I4MULTIPLY, &freeBlock, sizeof(freeBlock) ) ;
            #endif

            #ifdef S4BYTE_SWAP
               freeBlock = x4reverseLong( (void *)&freeBlock ) ;
            #endif
         }

      #ifdef S4FOX
         /* do the header tag */
         tagOn = i4->indexFile->tagIndex ;
         flagNo = (int)((tagOn->headerOffset) / (long)B4BLOCK_SIZE) ;
         if ( f4flagIsSet( &flags, (unsigned long)flagNo ) )
            return error4( i4->codeBase, e4index, E81601 ) ;
         f4flagSet( &flags, (unsigned long)flagNo ) ;
         f4flagSet( &flags, (unsigned long)flagNo + 1L ) ;  /* tag header is 2 blocks long */

         if ( tfile4freeAll( tagOn ) >= 0 )
         {
            #ifdef S4FOX
               node1 = -1L ;
               node2 = tagOn->header.root ;
               node3 = -1L ;
               flag4blocks( tagOn, &flags, &node1, &node2, &node3 ) ;
            #else
               flag4blocks( tagOn, &flags ) ;
            #endif

            /* Now Flag for each block in each tag */
            for ( tagOn = 0 ;; )
            {
               tagOn = (TAG4FILE *)l4next( &i4->indexFile->tags,tagOn ) ;
               if ( tagOn == 0 )
                  break ;
               flagNo = (int)( tagOn->headerOffset / (long)B4BLOCK_SIZE) ;
               if ( f4flagIsSet( &flags, (unsigned long)flagNo ) )
                  return error4( i4->codeBase, e4index, E81601 ) ;
               f4flagSet( &flags, (unsigned long)flagNo ) ;
               f4flagSet( &flags, (unsigned long)flagNo + 1L ) ;  /* tag header is 2 blocks long */

               if ( tfile4freeAll( tagOn ) < 0 )
                  break ;
               #ifdef S4FOX
                  node1 = -1L ;
                  node2 = tagOn->header.root ;
                  node3 = -1L ;
                  if ( node2 == -1 )
                  {
                     if ( file4readAll( &i4->indexFile->file, tagOn->headerOffset, &node2, sizeof(node2)) < 0 )
                        return error4( i4->codeBase, e4index, E81601 ) ;
                     #ifdef S4BYTE_SWAP
                        node2 = x4reverseLong( (void *)&node2 ) ;
                     #endif
                  }
                  flag4blocks( tagOn, &flags, &node1, &node2, &node3 ) ;
               #else
                  flag4blocks( tagOn, &flags ) ;
               #endif
            }
         }
      #else
         /* Read header information to flag the tag header blocks */
         file4readAll( &i4->indexFile->file, 512, desc, sizeof(desc) ) ;

         /* Now Flag for each block in each tag */
         i = 1 ;

         for ( tagOn = 0 ;; i++ )
         {
            tagOn = (TAG4FILE *)l4next( &i4->indexFile->tags, tagOn ) ;
            if ( tagOn == 0 )
               break ;
            #ifdef S4BYTE_SWAP
               desc[i].headerPos = x4reverseLong( (void *)&desc[i].headerPos ) ;
               desc[i].x1000 = 0x1000 ;
            #endif

            flagNo = (int) ((desc[i].headerPos * I4MULTIPLY - 2048) / (long) i4->indexFile->header.blockRw) ;
            if ( f4flagIsSet( &flags, flagNo ) )
               return error4( i4->codeBase, e4index, E81601 ) ;
            f4flagSet( &flags, flagNo ) ;

            if ( tfile4freeAll(tagOn) < 0 )
               break ;
            flag4blocks( tagOn, &flags ) ;
         }
      #endif

      if ( f4flagIsAllSet( &flags, 0UL, (unsigned long)totBlocks - 1L ) == 0 )
         error4( i4->codeBase, e4index, E85702 ) ;

      u4free( flags.flags ) ;
      if ( error4code( i4->codeBase ) < 0 )
          return error4code( i4->codeBase ) ;

   #endif
   return 0 ;
}

int i4check( INDEX4 *i4 )
{
   int rc ;
   TAG4 *tagOn ;
   #ifdef S4HAS_DESCENDING
      int oldDesc ;
   #endif

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

   if ( error4code( i4->codeBase ) < 0 )
      return e4codeBase ;

   #ifndef S4OFF_WRITE
      #ifdef N4OTHER
         rc = i4update( i4 ) ;
      #else
         rc = index4update( i4->indexFile ) ;
      #endif
      if ( rc < 0 )
         return rc ;
   #endif

   rc = i4checkBlocks( i4 ) ;
   if ( rc < 0 )
      return rc ;

   for( tagOn = 0 ;; )
   {
      tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
      if ( tagOn == 0 )
         return 0 ;
      #ifdef S4HAS_DESCENDING
         oldDesc = tagOn->tagFile->header.descending ;
         tagOn->tagFile->header.descending = 0 ;   /* force ascending */
         rc = t4check( tagOn ) ;
         tagOn->tagFile->header.descending = (short)oldDesc ;   /* return to previous */
         if ( rc < 0 )
            return rc ;
      #else
         rc = t4check( tagOn ) ;
         if ( rc < 0 )
            return rc ;
      #endif
   }
}

#endif  /* S4INDEX_OFF */

#ifdef P4ARGS_USED
   #pragma argsused
#endif
int S4FUNCTION d4check( DATA4 *d4 )
{
   #ifdef S4INDEX_OFF
      return 0 ;
   #else
      INDEX4 *indexOn ;
      int rc ;

      #ifdef E4PARM_HIGH
         if ( d4 == 0 )
            return error4( 0, e4parm_null, E95702 ) ;
      #endif

      #ifndef S4OFF_WRITE
         rc = d4updateRecord( d4, 1 ) ;
         if ( rc != 0 )  /* either an error or r4unique */
            return rc ;
      #endif

      #ifndef S4OFF_MULTI
         #ifdef S4SERVER
            rc = dfile4lockFile( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ) ) ;   /* returns -1 if error4code( codeBase ) < 0 */
         #else
            rc = d4lockFile( d4 ) ;   /* returns -1 if error4code( codeBase ) < 0 */
         #endif
         if ( rc )
            return rc ;
      #endif

      #ifndef S4OFF_TRAN
         rc = tran4active( d4->codeBase, d4 ) ;
         if ( rc != 0 )
            return error4( d4->codeBase, rc, E81517 ) ;
      #endif

      for( indexOn = 0 ;; )
      {
         indexOn = (INDEX4 *)l4next( &d4->indexes, indexOn ) ;
         if ( indexOn == 0 )
            return 0 ;
         rc = i4check( indexOn ) ;
         if ( rc < 0 )
            return -1 ;
      }
   #endif  /* S4INDEX_OFF */
}

#endif /* S4CLIENT */