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

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

#ifndef S4INDEX_OFF

#ifdef S4CLIENT
/* if i4old is set to a value, then it is used instead of creating a new i4 */
/* if doFull is set to false and i4old is valid, a tag update between i4file
   and i4 are done only */

static INDEX4 *i4setup2( CODE4 *c4, INDEX4FILE *i4file, DATA4 *d4, const char *name, INDEX4 *i4old, int doFull )
{
   INDEX4 *i4 ;
   TAG4FILE *tagOn ;
   TAG4 *tag, *tag2 ;
   int doUpdate ;

   if ( i4old == 0 )
   {
      if ( c4->indexMemory == 0 )
      {
         c4->indexMemory = mem4create( c4, c4->memStartIndex, sizeof(INDEX4), c4->memExpandIndex, 0 ) ;
         if ( c4->indexMemory == 0 )
            return 0 ;
      }

      i4 = (INDEX4 *)mem4alloc( c4->indexMemory ) ;
      i4->codeBase = c4 ;
      i4->data = d4 ;
      i4->indexFile = i4file ;
      l4add( &d4->indexes, i4 ) ;
      u4ncpy( i4->alias, name, sizeof( i4->alias ) - 1 ) ;
   }
   else
      i4 = i4old ;

   for ( tagOn = 0 ;; )
   {
      tagOn = (TAG4FILE *)l4next( &i4file->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;
      if ( doFull == 0 )   /* check that tag doesn't already exit */
      {
         doUpdate = 1 ;
         for ( tag2 = 0 ;; )
         {
            tag2 = (TAG4 *)l4next( &i4->tags, tag2 ) ;
            if ( tag2 == 0 )
               break ;
            if ( tag2->tagFile == tagOn )
            {
               doUpdate = 0 ;
               break ;
            }
         }
         if ( doUpdate == 0 )
            continue ;
      }
      tag = (TAG4 *)mem4alloc( c4->tagMemory ) ;
      if ( tag == 0 )
         return 0 ;
      tag->tagFile = tagOn ;
      tag->index = i4 ;
      tag->errUnique = tagOn->errUniqueHold ;
      l4add( &i4->tags, tag ) ;
   }

   return i4 ;
}

/* if i4old is set to a value, then it is used instead of creating a new i4 */
int i4setup( CODE4 *c4, DATA4 *d4, const char *name, int autoOpened, INDEX4 *i4old )
{
   INDEX4FILE *i4file ;
   INDEX4 *i4 ;
   int addIndex, addTags ;

   /* now set up the tags */
   if ( c4->tagMemory == 0 )
   {
      c4->tagMemory = mem4create( c4, c4->memStartTag, sizeof(TAG4), c4->memExpandTag, 0 ) ;
      if ( c4->tagMemory == 0 )
      {
         d4close( d4 ) ;
         return 0 ;
      }
   }

   for ( i4file = 0 ;; )
   {
      i4file = (INDEX4FILE *)l4next( &d4->dataFile->indexes, i4file ) ;
      if ( i4file == 0 )
         break ;
      addIndex = 1 ;
      addTags = 0 ;
      for ( i4 = 0 ;; )   /* only set up for i4file's not in i4's of d4 */
      {
         i4 = (INDEX4 *)l4next( &d4->indexes, i4 ) ;
         if ( i4 == 0 )
            break ;
         if ( i4->indexFile == i4file )
         {
            if ( l4numNodes( &i4->tags ) < l4numNodes( &i4file->tags ) )
               addTags = 1 ;
            addIndex = 0 ;
            break ;
         }
      }
      if ( addIndex == 0 )
      {
         if ( addTags == 0 )
            continue ;
      }
      else
         i4file->userCount++ ;
      i4 = i4setup2( c4, i4file, d4, name, i4old, addIndex ) ;
      if ( i4 == 0 )
      {
         d4close( d4 ) ;
         return 0 ;
      }
      i4file->autoOpened = autoOpened ;    /* if in i4open, must be a manual open */
   }

   return 0 ;
}
#else
#ifdef S4CLIPPER
#ifdef P4ARGS_USED
   #pragma argsused
#endif
int i4setup( CODE4 *c4, DATA4 *d4, const char *name, int autoOpened )
{
   TAG4FILE *tagFile ;
   TAG4 *tag ;
   DATA4FILE *dfile ;
   INDEX4 *i4 = 0 ;

   dfile = d4->dataFile ;

   for ( tagFile = 0 ;; )
   {
      tagFile = (TAG4FILE *)l4next( &dfile->tagfiles, tagFile ) ;
      if ( tagFile == 0 )
         break ;
      if ( i4 == 0 )
      {
         i4 = (INDEX4 *)mem4alloc( c4->indexMemory ) ;
         i4->codeBase = c4 ;
         i4->data = d4 ;
         l4add( &d4->indexes, i4 ) ;
         u4ncpy( i4->accessName, name, sizeof( i4->accessName ) - 1 ) ;
      }
      tag = (TAG4 *)mem4alloc( c4->tagMemory ) ;
      if ( tag == 0 )
         return 0 ;
      tag->tagFile = tagFile ;
      tag->tagFile->userCount++ ;
      tag->index = i4 ;
      #ifdef S4SERVER
         tag->errUnique = tfile4unique( tag->tagFile, (short int)d4->codeBase->errDefaultUnique ) ;
      #endif
      l4add( &i4->tags, tag ) ;
   }

   return 0 ;
}
#endif
#endif /* S4CLIENT */

#ifdef S4CLIENT
int index4close( INDEX4FILE *i4 )
{
   CONNECTION4 *connection ;
   CODE4 *c4 ;
   TAG4FILE *tagOn ;
   int finalRc, rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91702 ) ;
   #endif
   #ifdef E4ANALYZE
      if ( i4->userCount <= 0 )
         return error4( i4->codeBase, e4struct, E81702 ) ;
      if ( i4->codeBase == 0 )
         return error4( i4->codeBase, e4struct, E91702 ) ;
   #endif

   i4->userCount-- ;
   finalRc = 0 ;
   if ( i4->userCount == 0 )
   {
      c4 = i4->codeBase ;
      if ( i4->autoOpened == 0 )   /* must manually close ... */
      {
         #ifndef S4OFF_TRAN
            if ( code4transEnabled( c4 ) )
               if ( code4trans( c4 )->currentTranStatus == r4active )  /* disallow on current active only */
                  return error4( c4, e4transViolation, E81522 ) ;
         #endif
         connection = i4->dataFile->connection ;
         #ifdef E4ANALYZE
            if ( connection == 0 )
               finalRc = error4( c4, e4struct, E91702 ) ;
            else
            {
         #endif
            connection4assign( connection, CON4INDEX_CLOSE, i4->clientId, i4->serverId ) ;
            connection4addData( connection, i4->accessName, strlen( i4->accessName ) + 1, 0 ) ;
            connection4send( connection ) ;
            rc = connection4receive( connection ) ;
            if ( rc != 0 )
               finalRc = error4( c4, rc, E81701 ) ;
            else
            {
               rc = connection4status( connection ) ;
               if ( rc != 0 )
                  finalRc = connection4error( connection, c4, rc, E91702 ) ;
            }
         #ifdef E4ANALYZE
            }
         #endif
      }
      for( ;; )
      {
         tagOn = (TAG4FILE *)l4pop( &i4->tags ) ;
         if ( tagOn == 0 )
            break ;
         if ( tagOn->exprPtr != 0 )
         {
            u4free( tagOn->exprPtr ) ;
            tagOn->exprPtr = 0 ;
         }
         if ( tagOn->filterPtr != 0 )
         {
            u4free( tagOn->filterPtr ) ;
            tagOn->filterPtr = 0 ;
         }
         mem4free( c4->tagFileMemory, tagOn ) ;
         tagOn = 0 ;
      }
      l4remove( &i4->dataFile->indexes, i4 ) ;
      mem4free( c4->index4fileMemory, i4 ) ;
      i4 = 0 ;
      return finalRc ;
   }

   return 0 ;
}

int S4FUNCTION i4close( INDEX4 *i4 )
{
   int rc, finalRc ;
   TAG4 *tagOn ;
   CODE4 *c4 ;

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E91701 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91701 ) ;
      if ( i4->codeBase == 0 )
         return error4( 0, e4parm, E91701 ) ;
   #endif

   c4 = i4->codeBase ;

   finalRc = 0 ;

   #ifndef S4OFF_WRITE
      if ( i4->data )
         if ( d4update( i4->data ) < 0 )
            finalRc = error4set( c4, 0 ) ;
   #endif

   #ifdef E4ANALYZE
      if ( i4->data == 0 )
         return error4( 0, e4struct, E91701 ) ;
      if ( i4->data->dataFile == 0 )
         return error4( 0, e4struct, E91701 ) ;
   #endif
   if ( i4->data->tagSelected != 0 )
      if ( i4->data->tagSelected->index == i4 )
         i4->data->tagSelected = 0 ;
   for( ;; )
   {
      tagOn = (TAG4 *)l4pop( &i4->tags ) ;
      if ( tagOn == 0 )
         break ;
      mem4free( c4->tagMemory, tagOn ) ;
      tagOn = 0 ;
   }
   l4remove( &i4->data->indexes, i4 ) ;
   rc = index4close( i4->indexFile ) ;
   mem4free( c4->indexMemory, i4 ) ;
   i4 = 0 ;
   if ( rc < 0 )
      return rc ;
   return finalRc ;
}

#endif /* S4CLIENT */

const char *S4FUNCTION i4fileName( INDEX4 *i4 )
{
   #ifdef S4CLIENT
      CONNECTION4 *connection ;
      int rc ;
   #else
      #ifdef S4CLIPPER
         TAG4FILE *tag ;
      #endif
   #endif

   #ifdef E4PARM_HIGH
      if ( i4 == 0 )
      {
         error4( 0, e4parm_null, E91720 ) ;
         return 0 ;
      }
   #endif

   #ifdef S4CLIENT
      if ( error4code( i4->codeBase ) < 0 )
         return 0 ;

      connection = i4->data->dataFile->connection ;
      connection4assign( connection, CON4INDEX_FNAME, data4clientId( i4->data ), data4serverId( i4->data ) ) ;
      connection4addData( connection, i4->indexFile->accessName, strlen( i4->indexFile->accessName ) + 1, 0 ) ;
      connection4send( connection ) ;
      rc = connection4receive( connection ) ;
      if ( rc < 0 )
      {
         #ifdef E4STACK
            error4stack( i4->codeBase, rc, E95501 ) ;
         #endif
         return 0 ;
      }

      rc = connection4status( connection ) ;
      if ( rc < 0 )
      {
         connection4error( connection, i4->codeBase, rc, E95501 ) ;
         return 0 ;
      }

      return connection4data( connection ) ;
   #else
      #ifdef S4CLIPPER
         if ( i4->path != 0 )
            return i4->path ;
         if ( l4numNodes( &i4->tags ) == 1 )
         {
            tag = (TAG4FILE *)(((TAG4 *)(i4->tags.lastNode))->tagFile) ;
            return tag->alias ;
         }
         else
            return d4fileName( i4->data ) ;
      #else
         return i4->indexFile->file.name ;
      #endif /* S4CLIPPER */
   #endif /* S4CLIENT */
}

#ifndef S4CLIPPER

#ifndef S4CLIENT
int S4FUNCTION i4close( INDEX4 *i4 )
{
   int rc, finalRc ;
   TAG4 *tagOn ;
   CODE4 *c4 ;

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E91701 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91701 ) ;
      if ( i4->codeBase == 0 )
         return error4( 0, e4parm, E91701 ) ;
   #endif

   c4 = i4->codeBase ;

   #ifndef S4OFF_TRAN
      if ( i4->isValid == 1 ) /* if invalid (failed create/open) then allow close */
         if ( code4transEnabled( c4 ) )
            if ( code4trans( c4 )->currentTranStatus == r4active )  /* disallow on current active only */
               return error4( c4, e4transViolation, E81522 ) ;
   #endif

   finalRc = 0 ;

   #ifndef S4OFF_WRITE
      #ifndef S4OFF_TRAN
         if ( i4->isValid == 1 ) /* if invalid (failed create/open) then allow close */
      #endif
      if ( i4->data )
         if ( d4update( i4->data ) < 0 )
            finalRc = error4set( c4, 0 ) ;
   #endif

   for( ;; )
   {
      tagOn = (TAG4 *)l4pop( &i4->tags ) ;
      if ( tagOn == 0 )
         break ;
      #ifndef S4OFF_TRAN
         #ifdef E4ANALYZE
            if ( tagOn->removedKeys.nLink != 0 )
               return error4( c4, e4info, E91701 ) ;
         #endif
      #endif
      if ( i4->data->tagSelected == tagOn )  /* can't have a tag selected from a closed index */
         i4->data->tagSelected = 0 ;
      mem4free( c4->tagMemory, tagOn ) ;
      tagOn = 0 ;
   }
   if ( i4->indexFile != 0 )
   {
      rc = index4close( i4->indexFile ) ;
      if ( rc != 0 )
         finalRc = rc ;
   }
   if ( i4->link.n != 0 )
      l4remove( &i4->data->indexes, i4 ) ;
   mem4free( c4->indexMemory, i4 ) ;
   i4 = 0 ;

   if ( finalRc != 0 )
   {
      error4set( c4, finalRc ) ;
      return finalRc ;
   }

   return 0 ;
}

int index4close( INDEX4FILE *i4 )
{
   int finalRc, isProduction ;
   CODE4 *c4 ;
   TAG4FILE *tagOn ;
   #ifndef S4SINGLE
      int saveAttempts ;
   #endif

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91702 ) ;
   #endif
   #ifdef E4ANALYZE
      if ( i4->userCount < 0 )
         return error4( i4->codeBase, e4struct, E81702 ) ;
   #endif

   isProduction = index4isProduction( i4 ) ;
   if ( ( i4->userCount <= 1 && isProduction == 0 ) || ( i4->userCount == 0 && i4->dataFile->userCount == 0 ) )
   {
      c4 = i4->codeBase ;

      finalRc = error4code( c4 ) ;
      #ifndef S4SINGLE
         saveAttempts = c4->lockAttempts ;
         c4->lockAttempts = WAIT4EVER ;
      #endif

      #ifndef S4OFF_WRITE
         if ( index4update( i4 ) < 0 )
            finalRc = error4set( c4, 0 ) ;
      #endif

      #ifndef S4SINGLE
         if ( index4unlock( i4, 0UL ) < 0 )
            finalRc = error4set( c4, 0 ) ;
      #endif

      #ifdef S4FOX
         if ( i4->tagIndex )
            if ( i4->tagIndex->header.typeCode >= 64 )  /* compound index */
      #endif
      for( ;; )
      {
         tagOn = (TAG4FILE *)l4pop( &i4->tags ) ;
         if ( tagOn == 0 )
            break ;
         if ( tfile4freeAll( tagOn ) < 0 )
         {
            finalRc = error4set( c4, 0 ) ;
            break ;
         }
         expr4free( tagOn->expr ) ;
         expr4free( tagOn->filter ) ;
         #ifdef S4FOX
            mem4release( tagOn->builtKeyMemory ) ;
         #endif
         mem4free( c4->tagFileMemory, tagOn ) ;
         tagOn = 0 ;
      }

      #ifdef S4FOX
         if ( i4->tagIndex != 0 )
         {
            if ( tfile4freeAll( i4->tagIndex ) < 0 )
               finalRc = error4set( c4, 0 ) ;
            else
            {
               expr4free( i4->tagIndex->expr ) ;
               expr4free( i4->tagIndex->filter ) ;
               #ifdef S4FOX
                  mem4release( i4->tagIndex->builtKeyMemory ) ;
               #endif
               mem4free( c4->tagFileMemory, i4->tagIndex ) ;
               i4->tagIndex = 0 ;
            }
         }
      #endif

      mem4release( i4->blockMemory ) ;

      if ( file4openTest( &i4->file ) )
      {
         if ( i4->dataFile )
            l4remove( &i4->dataFile->indexes, i4 ) ;
         #ifndef S4CLIPPER
            #ifndef S4SERVER
               if ( c4->doRemove == 1 )
                  i4->file.isTemp = 1 ;
            #endif
         #endif
         if ( file4close( &i4->file ) < 0 )
            finalRc = error4set( c4, 0 ) ;
      }

      mem4free( c4->index4fileMemory, i4 ) ;
      i4 = 0 ;
      #ifndef S4SINGLE
         c4->lockAttempts = saveAttempts ;
      #endif
      error4set( c4, (short)finalRc ) ;
      return finalRc ;
   }
   else
   {
      i4->userCount-- ;
      return 0 ;
   }
}

#ifndef S4OFF_WRITE
long index4extend( INDEX4FILE *i4 )
{
   long oldEof ;
   unsigned len ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91703 ) ;
   #endif

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

   #ifndef S4FOX
      oldEof = i4->header.freeList ;

      if( i4->header.freeList == 0L )  /* case where no free list */
      {
         oldEof = i4->header.eof ;
         i4->header.eof = i4->header.eof + i4->header.blockRw/I4MULTIPLY ;
      }
      else
      {
         len = file4read( &i4->file, i4->header.freeList*I4MULTIPLY + sizeof(S4LONG),
               (char *)&i4->header.freeList, sizeof(i4->header.freeList)) ;

         #ifdef S4BYTE_SWAP
            i4->header.freeList = x4reverseLong( (void *)&i4->header.freeList ) ;
         #endif

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

         switch( len )
         {
            case 0:
               #ifdef E4ANALYZE
                  return error4( i4->codeBase, e4index, E91703 ) ;
               #else   /* try to fix up */
                  i4->header.freeList = 0L ;
                  oldEof = i4->header.eof ;
                  i4->header.eof = i4->header.eof + i4->header.blockRw/I4MULTIPLY ;
                  break ;
               #endif
            case sizeof(i4->header.freeList):
               break ;
            default:
               return file4readError( &i4->file, i4->header.freeList*I4MULTIPLY + sizeof(S4LONG), sizeof(i4->header.freeList), "index4extend" ) ;
         }
      }
   #endif

   #ifdef S4FOX
      #ifdef E4ANALYZE
         if ( i4->tagIndex->header.version == i4->versionOld )
            return error4( i4->codeBase, e4index, E91703 ) ;
      #endif

      oldEof = i4->tagIndex->header.freeList ;

      if( oldEof == 0L )  /* case where no free list */
      {
         oldEof = i4->eof ;
         i4->eof += B4BLOCK_SIZE ;
      }
      else
      {
         len = file4read( &i4->file, i4->tagIndex->header.freeList*I4MULTIPLY,
               (char *)&i4->tagIndex->header.freeList, sizeof(i4->tagIndex->header.freeList)) ;

         #ifdef S4BYTE_SWAP
            i4->tagIndex->header.freeList = x4reverseLong( &i4->tagIndex->header.freeList ) ;
         #endif

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

         switch( len )
         {
            case 0:
               #ifdef E4ANALYZE
                  return error4( i4->codeBase, e4index, E91703 ) ;
               #else  /* else fix up */
                  i4->tagIndex->header.freeList = 0L ;
                  oldEof = i4->eof ;
                  i4->eof += B4BLOCK_SIZE ;
                  break ;
               #endif
            case sizeof(i4->tagIndex->header.freeList):
               break ;
            default:
               return file4readError( &i4->file, i4->tagIndex->header.freeList*I4MULTIPLY, sizeof(i4->tagIndex->header.freeList), "index4extend" ) ;
         }
      }
   #endif

   return oldEof ;
}

int index4flush( INDEX4FILE *i4 )
{
   int rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91704 ) ;
   #endif

   rc = index4update( i4 ) ;
   if ( file4flush( &i4->file ) < 0 )
      rc = -1 ;

   return rc ;
}

int index4update( INDEX4FILE *i4 )
{
   TAG4FILE *tagOn ;
   int rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91705 ) ;
   #endif

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

   #ifndef S4SINGLE
      if ( i4->fileLocked != 0 )
      {
   #endif
   rc = index4updateHeader( i4 ) ;
   if ( rc < 0 )
      return error4stack( i4->codeBase, (short)rc, E91705 ) ;
   #ifdef S4FOX
      rc = tfile4update(i4->tagIndex) ;
      if ( rc < 0 )
         return error4stack( i4->codeBase, (short)rc, E91705 ) ;
      if ( i4->tagIndex->header.typeCode >= 64 )  /* compound index */
   #endif

   for ( tagOn = 0 ;; )
   {
      tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;
      rc = tfile4update( tagOn ) ;
      if ( rc < 0 )
         return error4stack( i4->codeBase, (short)rc, E91705 ) ;
      tagOn->header.root = -1L ;
   }

   #ifndef S4SINGLE
      }
   #endif

   return 0 ;
}
#endif  /* S4OFF_WRITE */
#endif  /* S4CLIENT */

INDEX4 *S4FUNCTION i4open( DATA4 *d4, const char *fileName )
{
   CODE4  *c4 ;
   INDEX4 *i4 ;
   #ifdef S4CLIENT
      INDEX4FILE *i4file ;
      unsigned char buf[258] ;
   #else
      TAG4 *tag ;
      TAG4FILE *tagFile ;
   #endif

   #ifdef E4PARM_HIGH
      if ( d4 == 0 )
      {
         error4( 0, e4parm_null, E91706 ) ;
         return 0 ;
      }
   #endif

   #ifdef S4VBASIC
      if ( c4parm_check( d4, 2, E91706 ) )
         return 0 ;
   #endif

   c4 = d4->codeBase ;
   if ( error4code( c4 ) < 0 )
      return 0 ;

   #ifdef S4CLIENT
      if ( fileName == 0 )
         u4ncpy( (char *)buf, d4->dataFile->accessName, sizeof( buf ) - 1 ) ;
      else
      {
         if ( strlen( fileName ) > sizeof( buf ) - 1 )
         {
            error4( c4, e4name, E91706 ) ;
            return 0 ;
         }
         strcpy( (char*)buf, fileName ) ;
      }
      c4upper( (char*)buf ) ;
      i4 = d4index( d4, (char S4PTR*)buf ) ;
      if ( i4 != 0 )   /* duplicates not allowed */
         error4( c4, e4instance, E91706 ) ;
      i4file = index4open( d4, (char S4PTR*)buf, 0 ) ;
      if ( error4code( c4 ) < 0 )
         return 0 ;
      i4 = d4index( d4, (char S4PTR*)buf ) ;
      if ( i4file == 0 )
      {
         if ( i4 == 0 )
            return 0 ;
         #ifdef E4ANALZE
            if ( i4->indexFile == 0 )
            {
               error4( c4, e4info, E91706 ) ;
               return 0 ;
            }
         #endif
         i4file = i4->indexFile ;
         i4file->clientId = data4clientId( d4 ) ;
         i4file->serverId = data4serverId( d4 ) ;
      }
      else  /* indexfile already exists so set up another index4 structure */
      {
         i4 = i4setup2( c4, i4file, d4, (char S4PTR*)buf, 0, 1 ) ;
         if ( i4 == 0 )
         {
            index4close( i4file ) ;
            return 0 ;
         }
      }
      #ifdef E4ANALZE
         else
         {
            if ( i4->indexFile != i4file )
            {
               error4( c4, e4info, E91706 ) ;
               return 0 ;
            }
         }
      #endif
      i4->codeBase = c4 ;
      #ifndef S4OFF_TRAN
         i4->isValid = 1 ;
      #endif
      return i4 ;
   #else
      if ( c4->indexMemory == 0 )
      {
         c4->indexMemory = mem4create( c4, c4->memStartIndex, sizeof(INDEX4), c4->memExpandIndex, 0 ) ;
         if ( c4->indexMemory == 0 )
            return 0 ;
      }

      i4 = (INDEX4 *)mem4alloc( c4->indexMemory ) ;
      if ( i4 == 0 )
      {
         #ifdef ERROR4STACK
            error4stack( c4, e4memory, E91706 ) ;
         #endif
         return 0 ;
      }

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

      if ( fileName != 0 )
      {
         #ifdef E4MISC
            if ( strlen( fileName ) > sizeof( i4->accessName ) )
            {
               error4describe( c4, e4name, E91706, fileName, 0, 0 ) ;
               i4close( i4 ) ;
               return 0 ;
            }
         #endif
         u4ncpy( i4->accessName, fileName, sizeof( i4->accessName ) - 1 ) ;
      }
      #ifdef S4STAND_ALONE
         else
         {
            u4namePiece( i4->accessName, sizeof( i4->accessName ), d4->alias, 0, 0 ) ;
         }
         #ifndef S4CASE_SEN
            c4upper( i4->accessName ) ;
         #endif
      #endif

      i4->indexFile = index4open( d4, fileName, i4 ) ;
      if ( i4->indexFile == 0 )
      {
         i4close( i4 ) ;
         return 0 ;
      }

      l4add( &d4->indexes, i4 ) ;

      for ( tagFile = 0 ;; )
      {
         tagFile = (TAG4FILE *)l4next( &i4->indexFile->tags, tagFile ) ;
         if ( tagFile == 0 )
            break ;

         tag = (TAG4 *)mem4alloc( c4->tagMemory ) ;
         if ( tag == 0 )
         {
            i4close( i4 ) ;
            error4( c4, e4memory, E91706 ) ;
            return 0 ;
         }
         tag->index = i4 ;
         tag->tagFile = tagFile ;

         #ifdef S4FOX
            if ( tag->tagFile->header.typeCode & 0x04 )  /* r4/e4 candidate */
            {
               if ( c4->errDefaultUnique == e4unique )
                  tag->errUnique = e4candidate ;
               else
                  tag->errUnique = r4candidate ;
            }
            else
               if ( tag->tagFile->header.typeCode & 0x01 )
         #else
            if ( tag->tagFile->header.unique )
         #endif
               tag->errUnique = c4->errDefaultUnique ;


         l4add( &i4->tags, tag ) ;
      }

      #ifndef S4OFF_TRAN
         i4->isValid = 1 ;
      #endif
      return i4 ;
   #endif
}

/* for the client, if index is not null, then the function only verifies the
   existance of the index file and does not actually open it */
INDEX4FILE *index4open( DATA4 *d4, const char *fileName, INDEX4 *index )
{
   CODE4  *c4 ;
   int    rc ;
   INDEX4FILE *i4 ;
   #ifdef S4CLIENT
      CONNECTION4OPEN_INDEX_INFO_OUT *info ;
      CONNECTION4OPEN_INDEX_INFO_IN dataIn ;
      CONNECTION4 *connection ;
   #else
      char buf[258] ;
      TAG4FILE *tagFile ;
      DATA4FILE *dfile ;
      #ifdef E4MISC
         INDEX4FILE *i4ptr ;
      #endif
      #ifdef S4FOX
         B4BLOCK *b4 ;
         #ifndef S4SINGLE
            long oldFileLock ;
         #endif
      #else
         T4DESC tagInfo[47] ;
         int iTag ;
      #endif
   #endif
   #ifndef S4SERVER
      INDEX4 *indexLoop ;
   #endif

   #ifdef E4PARM_LOW
      if ( d4 == 0 )
      {
         error4( 0, e4parm_null, E91707 ) ;
         return 0 ;
      }
      #ifndef S4CLIENT
         if ( index == 0 )
         {
            error4( 0, e4parm_null, E91707 ) ;
            return 0 ;
         }
      #endif
   #endif

   c4 = d4->codeBase ;

   #ifdef S4CLIENT
      i4 = dfile4index( d4->dataFile, fileName ) ;
   #else
      dfile = d4->dataFile ;
      #ifdef E4ANALYZE
         if ( code4indexExtension( c4 ) == 0 )
         {
            error4( c4, e4struct, E91707 ) ;
            return 0 ;
         }
      #endif
      if ( fileName == 0 )
         u4ncpy( (char *)buf, dfile->file.name, sizeof( buf ) - 1 ) ;
      else
      {
         rc = u4nameCurrent( (char *)buf, sizeof( buf ), fileName ) ;
         if ( rc < 0 )
         {
            error4( c4, rc, E94509 ) ;  /* from u4nameCurrent */
            return 0 ;
         }
      }
      u4nameExt( (char *)buf, sizeof( buf ), code4indexExtension( c4 ), ( fileName == 0 ? 1 : 0 ) ) ;
      #ifndef S4CASE_SEN
         c4upper( (char *)buf ) ;
      #endif
      i4 = dfile4index( dfile, (char *)buf ) ;
   #endif
   if ( i4 != 0 )
   {
      #ifndef S4SERVER
         /* allowed if current data4 does not have a pointer to index */
         for ( indexLoop = 0 ;; )
         {
            indexLoop = (INDEX4 *)l4next( &d4->indexes, indexLoop ) ;
            if ( indexLoop == 0 )
               break ;
            if ( indexLoop->indexFile == i4 )
            {
               error4( c4, e4instance, E91707 ) ;
               return 0 ;
            }
         }
         #ifdef S4OFF_FOR_NOW
         if ( i4->userCount > 0 && c4->singleOpen != OPEN4SPECIAL )   /* only one instance allowed unless performing additional d4open */
         {
            #ifdef S4STAND_ALONE
               #ifndef S4OFF_TRAN
                  /* verify that index4 not on the closed data list if within a
                     transaction (which is allowed) */
                  if ( code4tranStatus( c4 ) == r4active )
                  {
                     list = tran4dataList( (&(c4->c4trans.trans)) ) ;
                     for ( data4 = 0 ;; )
                     {
                        data4 = (DATA4 *)l4next( list, data4 ) ;
                        if ( data4 == 0 )
                           break ;
                        for ( indexLoop = 0 ;; )
                        {
                           indexLoop = (INDEX4 *)l4next( &data4->indexes, indexLoop ) ;
                           if ( indexLoop == 0 )
                              break ;
                           if ( indexLoop->indexFile == i4 )
                           {
                              error4( c4, e4instance, E91707 ) ;
                              return 0 ;
                           }
                        }
                     }
                  }
                  else
               #endif /* S4OFF_TRAN */
            #endif /* S4STAND_ALONE */
            {
               error4( c4, e4instance, E91707 ) ;
               return 0 ;
            }
         }
         #endif /* OFF_FOR_NOW */
      #endif
      i4->userCount++ ;
      return i4 ;
   }

   #ifdef S4VBASIC
      if ( c4parm_check( d4, 2, E91707 ) )
         return 0 ;
   #endif

   #ifdef S4CLIENT
      if ( index != 0 )   /* just wanted to verify existance of... */
         return 0 ;
      c4 = d4->dataFile->c4 ;
   #else
      c4 = dfile->c4 ;
   #endif
   if ( error4code( c4 ) < 0 )
      return 0 ;

   if ( c4->index4fileMemory == 0 )
      c4->index4fileMemory = mem4create( c4, c4->memStartIndexFile, sizeof(INDEX4FILE), c4->memExpandIndexFile, 0 ) ;
   if ( c4->index4fileMemory == 0 )
       return 0 ;

   if ( c4->tagMemory == 0 )
   {
      c4->tagMemory = mem4create( c4, c4->memStartTag, sizeof(TAG4), c4->memExpandTag, 0 ) ;
      if ( c4->tagMemory == 0 )
         return 0 ;
   }

   if ( c4->tagFileMemory == 0 )
   {
      c4->tagFileMemory = mem4create( c4, c4->memStartTagFile, sizeof(TAG4FILE), c4->memExpandTagFile, 0 ) ;
      if ( c4->tagFileMemory == 0 )
         return 0 ;
   }

   #ifdef S4CLIENT
      memset( &dataIn, 0, sizeof( CONNECTION4OPEN_INDEX_INFO_IN ) ) ;
      connection = d4->dataFile->connection ;
      if ( connection == 0 )
      {
         error4( c4, e4connection, E81704 ) ;
         return 0 ;
      }
      connection4assign( connection, CON4INDEX_OPEN, data4clientId( d4 ), data4serverId( d4 ) ) ;

      dataIn.nameLen = strlen( (char*)fileName ) + 1 ;
      dataIn.openForCreate = c4->openForCreate ;

      #ifdef S4SINGLE
         dataIn.exclusiveClient = 1 ;
      #else
         if ( c4->singleOpen == OPEN4DENY_RW )
            dataIn.accessMode = OPEN4DENY_RW ;
         else
            dataIn.accessMode = c4->accessMode ;
      #endif

      dataIn.readOnly = c4->readOnly ;
      dataIn.safety = c4->safety ;  /* for catalog */
      dataIn.errDefaultUnique = c4->errDefaultUnique ;

      connection4addData( connection, &dataIn, sizeof( CONNECTION4OPEN_INDEX_INFO_IN ), 0 ) ;
      connection4addData( connection, fileName, dataIn.nameLen, 0 ) ;
      connection4send( connection ) ;
      rc = connection4receive( connection ) ;
      if ( rc < 0 )
      {
         error4( c4, rc, E81701 ) ;
         return 0 ;
      }
      rc = connection4status( connection ) ;
      if ( rc != 0 )
      {
         if ( rc < 0 )
         {
            if ( c4->errOpen == 0 )
            {
               if ( error4code( c4 ) >= 0 )
                  error4set( c4, r4noOpen ) ;
            }
            else
               connection4error( connection, c4, rc, E91707 ) ;
         }
         return 0 ;
      }

      #ifdef E4MISC
         if ( connection4len( connection ) < sizeof( info ) )
         {
            error4( c4, e4packetLen, E91707 ) ;
            return 0 ;
         }
      #endif

      info = (CONNECTION4OPEN_INDEX_INFO_OUT *)connection4data( connection ) ;
      if ( client4indexSetup( c4, d4, d4->dataFile, info->numTags, connection4data( connection ) + sizeof(CONNECTION4OPEN_INDEX_INFO_OUT),
           (unsigned int)connection4len( connection ) - sizeof(CONNECTION4OPEN_INDEX_INFO_OUT), (char*)fileName, 0 ) < 0 )
      {
         error4( c4, e4connection, E91707 ) ;
         return 0 ;
      }

      /* in the client case, a null is a valid return code as the index is
         later extracted */
      i4setup( c4, d4, (char*)fileName, 0, 0 ) ;
      return 0 ;
   #else
      i4 = (INDEX4FILE *)mem4alloc( c4->index4fileMemory ) ;
      if ( i4 == 0 )
      {
         #ifdef ERROR4STACK
            error4stack( c4, e4memory, E91707 ) ;
         #endif
         return 0 ;
      }

      /* next line for this function duration only since the return of this
         function is assigned into index->indexFile but upper level.
         Therefore, we still must clean up ourselves if failure */
      index->indexFile = i4 ;
      i4->dataFile = dfile ;
      i4->codeBase = c4 ;
      #ifdef S4FOX
         #ifdef E4MISC
            for ( i4ptr = 0 ;; )
            {
               i4ptr = (INDEX4FILE *)l4next( &dfile->indexes, i4ptr ) ;
               if ( i4ptr == 0 )
                  break ;
               if ( !c4memcmp( i4ptr->file.name, buf, (size_t)strlen( (char *)buf ) ) )
               {
                  mem4free( c4->index4fileMemory, i4 ) ;
                  index->indexFile = 0 ;
                  error4( c4, e4parm, E81703 ) ;
                  return 0 ;
               }
            }
         #endif

         rc = file4open( &i4->file, c4, (char *)buf, 1 ) ;
         if ( rc )
         {
            index->indexFile = 0 ;
            mem4free( c4->index4fileMemory, i4 ) ;
            return 0 ;
         }

         i4->eof = file4len( &i4->file ) ;

         i4->tagIndex = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ;
         if ( i4->tagIndex == 0 )
         {
            file4close( &i4->file ) ;
            index->indexFile = 0 ;
            mem4free( c4->index4fileMemory, i4 ) ;
            error4( c4, e4memory, E91707 ) ;
            return 0 ;
         }

         l4add( &dfile->indexes, i4 ) ;
         if ( fileName == 0 )
         {
            if ( tfile4init( i4->tagIndex, index, 0L, (unsigned char *)"" ) < 0 )
            {
               index4close( i4 ) ;
               return 0 ;
            }
         }
         else
         {
            u4namePiece( (char *)buf, 258, fileName, 0, 0 ) ;  /* get the tagName based on the fileName */
            if ( tfile4init( i4->tagIndex, index, 0L, (unsigned char *)buf) < 0 )
            {
               index4close( i4 ) ;
               return 0 ;
            }
         }
         if ( tfile4setCodePage( i4->tagIndex, d4->codePage ) < 0 )
         {
            error4( c4, e4index, E91642 ) ;
            index4close( i4 ) ;
            return 0 ;
         }

         /* Perform some checks */
         if ( i4->tagIndex->header.root <= 0L || i4->tagIndex->header.typeCode < 32 )
         {
            #ifdef E4ANALYZE_ALL
               error4describe( c4, e4index, E81714, buf, 0, 0 ) ;
            #endif
            index4close( i4 ) ;
            #ifndef E4ANALYZE_ALL
               error4describe( c4, e4index, E81714, (char *)buf, 0, 0 ) ;
            #endif
            return 0 ;
         }

         i4->versionOld = i4->tagIndex->header.version ;
         i4->blockMemory = mem4create( c4, c4->memStartBlock, sizeof(B4BLOCK) + B4BLOCK_SIZE
                         - sizeof(B4STD_HEADER) - sizeof(B4NODE_HEADER), c4->memExpandBlock, 0 ) ;
         if ( i4->blockMemory == 0 )
         {
            index4close( i4 ) ;
            return 0 ;
         }

         /* do an initial block allocation to make sure minimal is allocated while optimization is suspended */
         b4 = (B4BLOCK *)mem4alloc2( i4->blockMemory, c4 ) ;
         if ( b4 == 0 )
         {
            index4close( i4  ) ;
            error4( c4, e4memory, E91707 ) ;
            return 0 ;
         }
         else
         {
            mem4free( i4->blockMemory, b4 ) ;
            b4 = 0 ;
         }

         #ifndef S4SINGLE
            /* disable locking */
            oldFileLock = i4->fileLocked ;
            i4->fileLocked = data4serverId( d4 ) ;
         #endif

         rc = tfile4top( i4->tagIndex ) ;
         if ( rc < 0 )
         {
            #ifndef S4SINGLE
               i4->fileLocked = oldFileLock ;
            #endif
            index4close( i4 ) ;
            return 0 ;
         }

         /* if we have a compound index, then load the tags, otherwise this is the only tag */
         if ( i4->tagIndex->header.typeCode >= 64 )
         {
            if ( b4numKeys( tfile4block( i4->tagIndex ) ) )
               do
               {
                  tagFile = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ;
                  if ( tagFile == 0 )
                  {
                     index4close( i4 ) ;
                     error4( c4, e4memory, E91707 ) ;
                     #ifndef S4SINGLE
                        i4->fileLocked = oldFileLock ;
                     #endif
                     return 0 ;
                  }

                  if ( tfile4init( tagFile, index, b4recNo( tfile4block(i4->tagIndex), tfile4block(i4->tagIndex)->keyOn ), tfile4keyData( i4->tagIndex )->value ) < 0 )
                  {
                     #ifndef S4SINGLE
                        i4->fileLocked = oldFileLock ;
                     #endif
                     index4close( i4 ) ;
                     return 0 ;
                  }
                  if ( tfile4setCodePage( tagFile, d4->codePage ) < 0 )
                  {
                     error4( c4, e4index, E91642 ) ;
                     index4close( i4 ) ;
                     return 0 ;
                  }

                  l4add( &i4->tags, tagFile ) ;
               } while ( tfile4skip( i4->tagIndex, 1L ) == 1L ) ;
         }
         else
         {
            #ifdef E4MISC
               if ( fileName == 0 )
               {
                  index4close( i4 ) ;
                  error4( c4, e4index, E81715 ) ;
               }
            #endif
            tagFile = i4->tagIndex ;
            l4add( &i4->tags, i4->tagIndex ) ;   /* if an .idx, add single tag */
         }
         #ifndef S4SINGLE
            i4->fileLocked = oldFileLock ;
         #endif
      #endif

      #ifndef S4FOX
         #ifdef E4MISC
            for ( i4ptr = 0 ;; )
            {
               i4ptr = (INDEX4FILE *)l4next(&dfile->indexes, i4ptr) ;
               if ( i4ptr == 0 )
                  break ;
               if ( !c4memcmp( i4ptr->file.name, buf, (size_t) strlen(buf) ) )
               {
                  error4( c4, e4parm, E81703 ) ;
                  return 0 ;
               }
            }
         #endif

         rc = file4open( &i4->file, c4, buf, 1 ) ;
         if ( rc )
         {
            index->indexFile = 0 ;
            mem4free( c4->index4fileMemory, i4 ) ;
            return 0 ;
         }

         if ( file4readAll( &i4->file, 0L, &i4->header, sizeof(I4HEADER) ) < 0 )
         {
            file4close( &i4->file ) ;
            index->indexFile = 0 ;
            mem4free( c4->index4fileMemory, i4 ) ;
            return 0 ;
         }

         #ifdef S4BYTE_SWAP
            i4->header.blockChunks = x4reverseShort( (void *)&i4->header.blockChunks ) ;
            i4->header.blockRw = x4reverseShort( (void *)&i4->header.blockRw ) ;
            i4->header.slotSize = x4reverseShort( (void *)&i4->header.slotSize ) ;
            i4->header.numTags = x4reverseShort( (void *)&i4->header.numTags ) ;
            i4->header.eof = x4reverseLong( (void *)&i4->header.eof ) ;
            i4->header.freeList = x4reverseLong( (void *)&i4->header.freeList ) ;
         #endif

         l4add( &dfile->indexes, i4 ) ;

         /* Perform some checks */
         if ( i4->header.blockRw != i4->header.blockChunks*512  ||
              i4->header.blockChunks <= 0 ||
              i4->header.blockChunks > 63 ||
              i4->header.numTags < 0  || i4->header.numTags > 47 ||
              i4->header.eof <= 0L )
         {
            index4close( i4 ) ;
            error4describe( c4, e4index, E81716, buf, 0, 0 ) ;
            return 0 ;
         }

         if ( file4readAll( &i4->file, 544L, tagInfo, sizeof(tagInfo)) < 0 )
         {
            index4close( i4 ) ;
            return 0 ;
         }

         for ( iTag = 0; iTag < (int) i4->header.numTags; iTag++ )
         {
            tagFile = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ;
            if ( tagFile == 0 )
            {
               index4close( i4 ) ;
               #ifdef E4STACK
                  error4stack( c4, e4memory, E91707 ) ;
               #endif
               return 0 ;
            }

            #ifdef S4BYTE_SWAP
               tagInfo[iTag].headerPos = x4reverseLong( (void *)&tagInfo[iTag].headerPos ) ;
               tagInfo[iTag].x1000 = 0x1000 ;
            #endif

            if ( tfile4init( tagFile, index, tagInfo + iTag ) < 0 )
            {
               index4close( i4 ) ;
               return 0 ;
            }

            l4add( &i4->tags, tagFile ) ;
         }

         i4->blockMemory = mem4create( c4, c4->memStartBlock, sizeof(B4BLOCK) + i4->header.blockRw -
                           sizeof(B4KEY_DATA) - sizeof(short) - sizeof(char[6]), c4->memExpandBlock, 0 ) ;
         if ( i4->blockMemory == 0 )
         {
            index4close( i4 ) ;
            return 0 ;
         }
      #endif

      #ifndef S4OPTIMIZE_OFF
         file4optimize( &i4->file, c4->optimize, OPT4INDEX ) ;
      #endif

      i4->userCount++ ;
      return i4 ;
   #endif
}

TAG4 *S4FUNCTION i4tag( INDEX4 *i4, const char *tagName )
{
   char tagLookup[LEN4TAG_ALIAS+1] ;
   TAG4 *tagOn ;

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E91709 ) )
         return 0 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( i4 == 0 )
      {
         error4( 0, e4parm_null, E91709 ) ;
         return 0 ;
      }
      if ( tagName == 0 )
      {
         error4( i4->codeBase, e4parm_null, E91709 ) ;
         return 0 ;
      }
   #endif

   u4ncpy( tagLookup, tagName, sizeof( tagLookup ) - 1 ) ;
   c4upper( tagLookup ) ;

   for( tagOn = 0 ;; )
   {
      tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
      if ( tagOn == 0 )
         break ;
      if ( strcmp( tagOn->tagFile->alias, tagLookup ) == 0 )
         return tagOn ;
   }

   if ( i4->codeBase->errTagName )
      error4describe( i4->codeBase, e4tagName, E91709, tagName, 0, 0 ) ;
   return 0 ;
}

#ifndef S4CLIENT
#ifndef S4OFF_WRITE
int index4shrink( INDEX4FILE *i4, long blockNo )
{
   int rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91708 ) ;
      if ( blockNo < 0 )
         return error4( i4->codeBase, e4parm, E91708 ) ;
   #endif

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

   #ifdef S4FOX
      #ifdef S4BYTE_SWAP
         i4->tagIndex->header.freeList = x4reverseLong( (void *)&i4->tagIndex->header.freeList ) ;
      #endif
      rc = file4write( &i4->file, blockNo, (char *)&i4->tagIndex->header.freeList,
           sizeof(i4->tagIndex->header.freeList) ) ;
      if ( rc < 0 )
         return error4stack( i4->codeBase, (short)rc, E91708 ) ;
      i4->tagIndex->header.freeList = blockNo ;
   #else
      #ifdef S4BYTE_SWAP
         i4->header.freeList = x4reverseLong( (void *)&i4->header.freeList ) ;
      #endif
      rc = file4write( &i4->file, blockNo*I4MULTIPLY + sizeof(S4LONG),
           (char *)&i4->header.freeList, sizeof(i4->header.freeList) ) ;
      if ( rc < 0 )
         return error4stack( i4->codeBase, rc, E91708 ) ;
      i4->header.freeList = blockNo ;
   #endif

   return 0 ;
}
#endif  /* S4OFF_WRITE */

#ifndef S4OFF_WRITE
/* Updates the header if the version has changed */
int i4updateHeader( INDEX4 *i4 )
{
   return index4updateHeader( i4->indexFile ) ;
}

int index4updateHeader( INDEX4FILE *i4 )
{
   #ifdef S4MDX
      int rc ;
      TAG4FILE *tagOn ;
      #ifdef S4BYTE_SWAP
         I4HEADER swap ;
      #endif
   #endif

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91710 ) ;
   #endif

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

   #ifdef S4FOX
      if ( i4->tagIndex == 0 )   /* index file not complete */
         return 0 ;

      if ( i4->versionOld != i4->tagIndex->header.version )
      {
         #ifdef S4BYTE_SWAP
            i4->tagIndex->header.root = x4reverseLong( (void *)&i4->tagIndex->header.root ) ;
            i4->tagIndex->header.freeList = x4reverseLong( (void *)&i4->tagIndex->header.freeList ) ;
            i4->tagIndex->header.keyLen = x4reverseShort( (void *)&i4->tagIndex->header.keyLen ) ;
         #else
            i4->tagIndex->header.version = (unsigned long)x4reverseLong( (void *)&i4->tagIndex->header.version ) ;
         #endif

         if ( file4write( &i4->file,0L, (char *)&i4->tagIndex->header, LEN4HEADER_WR ) < 0 )
            return -1;

         #ifdef S4BYTE_SWAP
            i4->tagIndex->header.root = x4reverseLong( (void *)&i4->tagIndex->header.root ) ;
            i4->tagIndex->header.freeList = x4reverseLong( (void *)&i4->tagIndex->header.freeList ) ;
            i4->tagIndex->header.keyLen = x4reverseShort( (void *)&i4->tagIndex->header.keyLen ) ;
         #else
            i4->tagIndex->header.version = (unsigned long)x4reverseLong( (void *)&i4->tagIndex->header.version ) ;
         #endif
         i4->versionOld = i4->tagIndex->header.version ;
      }
   #else
      if ( i4->changed )
      {
         #ifdef S4BYTE_SWAP
            memcpy( (void *)&swap, (void *)&i4->header, sizeof(I4HEADER) ) ;

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

            rc = file4write( &i4->file, 0L, (char *)&swap, sizeof( I4HEADER ) ) ;
            if ( rc < 0 )
               return error4stack( i4->codeBase, rc, E91710 ) ;
         #else
            rc = file4write( &i4->file, 0L, (char *)&i4->header, sizeof( I4HEADER ) ) ;
            if ( rc < 0 )
               return error4stack( i4->codeBase, rc, E91710 ) ;
         #endif
         i4->changed = 0 ;
         for( tagOn = 0 ;; )
         {
            tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn ) ;
            if ( tagOn == 0 )
               break ;
            if ( tagOn->changed == 1 )
            {
               tagOn->header.version++ ;
               tagOn->changed = 0 ;
               rc = file4write( &i4->file, tagOn->headerOffset + 20L, &tagOn->header.version, sizeof(char) ) ;
               if ( rc < 0 )
                  return error4stack( i4->codeBase, rc, E91710 ) ;
               if ( tagOn->hadKeys != tagOn->hasKeys )
               {
                  /* just update the tag to record that it has keys (no other update yet) */
                  rc = file4write( &i4->file, tagOn->headerOffset + 222 + sizeof( T4HEADER ), &tagOn->hasKeys, sizeof(char) ) ;
                  if ( rc < 0 )
                     return error4stack( i4->codeBase, rc, E91710 ) ;
                  tagOn->hadKeys = tagOn->hasKeys ;
               }
            }
         }
      }
   #endif

   return 0 ;
}
#endif  /* S4OFF_WRITE */

int t4versionCheck( TAG4 *t4, const int doSeek, const int updateVersion )
{
   #ifndef S4OPTIMIZE_OFF
      if ( t4->index->indexFile->file.doBuffer == 0 )
         return i4versionCheck( t4->index, doSeek, updateVersion ) ;
      else
         return 0 ;
   #else
      return i4versionCheck( t4->index, doSeek, updateVersion ) ;
   #endif
}

#ifdef P4ARGS_USED
   #pragma argsused
#endif
int i4versionCheck( INDEX4 *i4, const int doSeek, const int updateVersion )
{
   #ifndef S4SINGLE
      TAG4 *saveTag ;
      TAG4FILE *tagOn ;
      int needSeek ;
      B4BLOCK *b4 ;
      int rc ;

      #ifdef E4PARM_LOW
         if ( i4 == 0 )
            return error4( 0, e4parm_null, E91711 ) ;
      #endif

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

      rc = index4versionCheck( i4->indexFile, updateVersion ) ;
      if ( rc < 0 )
         return error4stack( 0, (short)rc, E91711 ) ;
      if ( rc == 0 )   /* version did not change */
         return 0 ;

      needSeek = 0 ;
      saveTag = d4tagSelected( i4->data ) ;
      if ( saveTag != 0 )
      {
         /* remember the old position */
         if ( doSeek )
         {
            b4 = (B4BLOCK *)saveTag->tagFile->blocks.lastNode ;
            if ( b4 != 0 )
            {
               if ( tfile4eof( saveTag->tagFile ) )
                  needSeek = 2 ;
               else
                  #ifdef S4FOX
                     if ( b4leaf( b4 ) && b4numKeys( b4 ) != 0 )
                  #else
                     if ( b4leaf( b4 ) && b4numKeys( b4 ) != 0 && b4->keyOn < b4numKeys( b4 ) )
                  #endif
                     {
                        #ifdef S4FOX
                           memcpy( i4->codeBase->savedKey, (void *)(b4key( b4, b4->keyOn )), saveTag->tagFile->header.keyLen + sizeof(long) ) ;
                        #else
                           memcpy( i4->codeBase->savedKey, (void *)(b4key( b4, b4->keyOn )), saveTag->tagFile->header.keyLen + 2 * sizeof(S4LONG) ) ;
                        #endif
                        needSeek = 1 ;
                     }
            }
         }
      }

      for ( tagOn = 0 ;; )
      {
         tagOn = (TAG4FILE *)l4next( &i4->indexFile->tags, tagOn ) ;
         if ( tagOn == 0 )
            break ;
         if ( tfile4freeAll( tagOn ) < 0 )  /* Should be a memory operation only */
            return error4( i4->codeBase, e4result, E91711 ) ;
      }

      switch ( needSeek )
      {
         case 1:
            tfile4go( saveTag->tagFile, ((B4KEY_DATA *)i4->codeBase->savedKey)->value, ((B4KEY_DATA *)i4->codeBase->savedKey)->num, 0 ) ;
            break ;
         case 2:
            tfile4goEof( saveTag->tagFile ) ;
            break ;
         default:
            break ;
      }
   #endif

   return 0 ;
}

/* Reads the header, checks the version to see if the blocks need to be freed. */
/* returns 1 if version needs to be updated, else 0 */
#ifdef P4ARGS_USED
   #pragma argsused
#endif
int index4versionCheck( INDEX4FILE *i4, const int updateVersion )
{
   #ifdef S4SINGLE
      return 0 ;
   #else
      #ifndef S4FOX
         TAG4FILE *tagOn ;
      #endif
      int rc ;

      #ifdef E4PARM_LOW
         if ( i4 == 0 )
            return error4( 0, e4parm_null, E91712 ) ;
      #endif

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

      if ( index4lockTest( i4 ) )
         return 0 ;

      #ifndef S4OPTIMIZE_OFF
         /* make sure read from disk unless file locked, etc. */
         if ( i4->file.doBuffer )  /* also makes sure 'opt' should exist */
            i4->codeBase->opt.forceCurrent = 1 ;
      #endif

      #ifdef S4FOX
         rc = file4readAll( &i4->file, 0L, &i4->tagIndex->header, LEN4HEADER_WR ) ;
         #ifdef S4BYTE_SWAP
            i4->tagIndex->header.root = x4reverseLong( (void *)&i4->tagIndex->header.root ) ;
            i4->tagIndex->header.freeList = x4reverseLong( (void *)&i4->tagIndex->header.freeList ) ;
            i4->tagIndex->header.version = x4reverseLong( (void *)&i4->tagIndex->header.version ) ;
            i4->tagIndex->header.keyLen = x4reverseShort( (void *)&i4->tagIndex->header.keyLen ) ;
         #endif
         #ifndef S4OPTIMIZE_OFF
            if ( i4->file.doBuffer )
               i4->codeBase->opt.forceCurrent = 0 ;
         #endif
         if ( rc < 0 )
            return error4stack( i4->codeBase, (short)rc, E91712 ) ;
         i4->tagIndex->header.version = (unsigned long)x4reverseLong( (void *)&i4->tagIndex->header.version ) ;
         if ( i4->tagIndex->header.version == i4->versionOld )
            return 0 ;

         if ( updateVersion == 1 )
            i4->versionOld = i4->tagIndex->header.version ;
         else
            i4->tagIndex->header.version = i4->versionOld ;
         return 1 ;
      #else
         rc = file4readAll( &i4->file, 0L, &i4->header, sizeof(I4HEADER) ) ;
         #ifndef S4OPTIMIZE_OFF
            if ( i4->file.doBuffer )
               i4->codeBase->opt.forceCurrent = 0 ;
         #endif
         if ( rc < 0 )
            return error4stack( i4->codeBase, rc, E91712 ) ;

         #ifdef S4BYTE_SWAP
            i4->header.blockChunks = x4reverseShort( (void *)&i4->header.blockChunks ) ;
            i4->header.blockRw = x4reverseShort( (void *)&i4->header.blockRw ) ;
            i4->header.slotSize = x4reverseShort( (void *)&i4->header.slotSize ) ;
            i4->header.numTags = x4reverseShort( (void *)&i4->header.numTags ) ;
            i4->header.eof = x4reverseLong( (void *)&i4->header.eof ) ;
            i4->header.freeList = x4reverseLong( (void *)&i4->header.freeList ) ;
         #endif
         #ifndef S4OPTIMIZE_OFF
            /* make sure read from disk unless file locked, etc. */
            if ( i4->file.doBuffer )  /* also makes sure 'opt' should exist */
              i4->codeBase->opt.forceCurrent = 1 ;
         #endif
         for( tagOn = 0 ;; )
         {
            tagOn = (TAG4FILE *)l4next( &i4->tags, tagOn ) ;
            if ( tagOn == 0 )
               break ;
            rc = file4readAll( &i4->file, tagOn->headerOffset + 20L, &tagOn->header.version, sizeof(char) ) ;
            if ( rc < 0 )
            {
               #ifndef S4OPTIMIZE_OFF
                  if ( i4->file.doBuffer )
                     i4->codeBase->opt.forceCurrent = 0 ;
               #endif
               return error4stack( i4->codeBase, rc, E91712 ) ;
            }
            rc = file4readAll( &i4->file, tagOn->headerOffset + 222 + sizeof( T4HEADER ), &tagOn->hasKeys, sizeof(char) ) ;
            if ( rc < 0 )
            {
               #ifndef S4OPTIMIZE_OFF
                  if ( i4->file.doBuffer )
                     i4->codeBase->opt.forceCurrent = 0 ;
               #endif
               return error4stack( i4->codeBase, rc, E91712 ) ;
            }
            tagOn->hadKeys = tagOn->hasKeys ;
         }

         #ifndef S4OPTIMIZE_OFF
            if ( i4->file.doBuffer )
               i4->codeBase->opt.forceCurrent = 0 ;
         #endif
         return 1 ;
      #endif
   #endif
}
#endif /* S4CLIENT */
#endif /* S4CLIPPER */


#ifdef S4CLIPPER

/* This function closes all the tags corresponding with the index */
int S4FUNCTION i4close( INDEX4 *i4 )
{
   int finalRc ;
   CODE4 *c4 ;
   TAG4 *tagOn ;
   int oldOpenErr, rc ;
   char buf[258] ;
   #ifndef S4SINGLE
      int saveAttempts ;
   #endif

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E91701 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91701 ) ;
   #endif

   c4 = i4->codeBase ;

   finalRc = error4code( c4 ) ;
   #ifndef S4OFF_WRITE
      if ( i4->data )
         if ( d4update( i4->data ) < 0 )
            finalRc = error4set( c4, 0 ) ;
   #endif

   #ifndef S4SINGLE
      saveAttempts = c4->lockAttempts ;
      c4->lockAttempts = WAIT4EVER ;
      if ( i4unlock(i4) < 0 )
         finalRc = error4set( c4, 0 ) ;
   #endif

   for( ;; )
   {
      tagOn = (TAG4 *)l4pop( &i4->tags ) ;
      if ( tagOn == 0 )
         break ;
      if ( i4->data->tagSelected == tagOn )   /* can't have a non-existant tag selected */
         i4->data->tagSelected = 0 ;
      t4close( tagOn ) ;
      tagOn = 0 ;
   }

   if ( c4->doRemove == 1 )
   {
      oldOpenErr = c4->errOpen ;
      c4->errOpen = 0 ;
      u4ncpy( buf, i4->accessName, sizeof( buf ) - 1 ) ;
      u4nameExt( buf, sizeof( buf ), "CGP", 1 ) ;
      rc = file4open( &i4->file, c4, buf, 0 ) ;
      if ( rc == 0 )
      {
         i4->file.isTemp = 1 ;
         file4close( &i4->file ) ;
      }
      c4->errOpen = oldOpenErr ;
   }

   if ( i4->data )
      l4remove( &i4->data->indexes, i4 ) ;

   mem4free( c4->indexMemory, i4 ) ;
   i4 = 0 ;
   #ifndef S4SINGLE
      c4->lockAttempts = saveAttempts ;
   #endif
   error4set( c4, finalRc ) ;
   return  finalRc ;
}

#ifndef S4OFF_WRITE
/* This function flushes all the tags corresponding with the index */
int i4flush( INDEX4 *i4 )
{
   TAG4 *tagOn ;
   int rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91713 ) ;
   #endif

   #ifndef S4SINGLE
      if ( i4->data->dataFile->indexLocked == 1 )
   #endif
      for ( tagOn = 0 ;; )
      {
         tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
         if ( tagOn == 0 )
            break ;
         rc = tfile4flush( tagOn->tagFile ) ;
         if ( rc < 0 )
            return error4stack( i4->codeBase, rc, E91713 ) ;
         tagOn->tagFile->header.root = -1L ;
      }
      return 0 ;
}

int i4update( INDEX4 *i4 )
{
   TAG4 *tagOn ;
   int rc ;

   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91705 ) ;
   #endif

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

   #ifndef S4SINGLE
      if ( i4->data->dataFile->indexLocked == 1 )
   #endif
      for ( tagOn = 0 ;; )
      {
         tagOn = (TAG4 *)l4next( &i4->tags, tagOn ) ;
         if ( tagOn == 0 )
            break ;
         rc = tfile4update( tagOn->tagFile ) ;
         if ( rc < 0 )
            return error4stack( i4->codeBase, rc, E91705 ) ;
         tagOn->tagFile->header.root = -1L ;
      }
      return 0 ;
}
#endif

INDEX4 *S4FUNCTION i4open( DATA4 *d4, const char *fileName )
{
   INDEX4 *i4 ;
   CODE4 *c4 ;
   TAG4 *tag ;
   int len, rc, i ;
   char buf[258], tagBuf[258], ext[3] ;
   int numFiles ;
   FILE4SEQ_READ seqread ;
   char buffer[1024], tNames[258], firstByte ;
   int pos, iPos, saveLen, tempLen ;

   #ifdef S4VBASIC
      if ( c4parm_check( d4, 2, E91706 ) )
         return 0 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( d4 == 0 )
      {
         error4( 0, e4parm_null, E91706 ) ;
         return 0 ;
      }
   #endif

   c4 = d4->codeBase ;
   if ( error4code( c4 ) < 0 )
      return 0 ;

   #ifdef S4CLIENT
      if ( fileName == 0 )
         u4ncpy( (char *)buf, d4->dataFile->accessName, sizeof( buf ) - 1 ) ;
      else
      {
         if ( strlen( fileName ) > sizeof( buf ) - 1 )
         {
            error4( c4, e4name, E91707 ) ;
            return 0 ;
         }
         strcpy( (char*)buf, fileName ) ;
      }
      c4upper( (char*)buf ) ;
      i4file = index4open( d4, (char S4PTR*)buf, 0 ) ;
      if ( error4code( c4 ) < 0 )
         return 0 ;
      i4 = d4index( d4, (char S4PTR*)buf ) ;
      if ( i4file == 0 )
      {
         if ( i4 == 0 )
            return 0 ;
         #ifdef E4ANALZE
            if ( i4->indexFile == 0 )
            {
               error4( c4, e4info, E91706 ) ;
               return 0 ;
            }
         #endif
         i4file = i4->indexFile ;
         i4file->clientId = data4clientId( d4 ) ;
         i4file->serverId = data4serverId( d4 ) ;
      }
      else  /* indexfile already exists so set up another index4 structure */
      {
         i4 = i4setup2( c4, i4file, d4, (char S4PTR*)buf ) ;
         if ( i4 == 0 )
         {
            index4close( i4file ) ;
            return 0 ;
         }
      }
      #ifdef E4ANALZE
         else
         {
            if ( i4->indexFile != i4file )
            {
               error4( c4, e4info, E91706 ) ;
               return 0 ;
            }
         }
      #endif
      i4->codeBase = c4 ;
   #else
      if ( fileName == 0 )
      {
         u4ncpy( buf, d4->dataFile->file.name, sizeof( buf ) - 1 ) ;
         u4nameExt( buf, sizeof( buf ), "CGP", 1 ) ;
      }
      else
      {
         u4ncpy( buf, fileName, sizeof( buf ) - 1 ) ;
         c4upper( buf ) ;
         rc = u4nameRetExt( ext, 3, buf ) ;
         if ( rc )  /* extension provided */
         {
            if ( rc == 3 )
               if ( c4memcmp( ext, "NTX", 3 ) == 0 )
               {
                  tag = t4open( d4, (INDEX4 *)0, fileName ) ;
                  if ( tag == 0 )
                     return 0 ;
                  #ifndef S4OFF_TRAN
                     tag->index->isValid = 1 ;
                  #endif
                  return tag->index ;
               }
         }
         else
            u4nameExt( buf, sizeof(buf), "CGP", 0 ) ;
      }

      if ( c4->indexMemory == 0 )
      {
         c4->indexMemory = mem4create( c4, c4->memStartIndex, sizeof( INDEX4 ), c4->memExpandIndex, 0 ) ;
         if ( c4->indexMemory == 0 )
            return 0 ;
      }

      if ( c4->tagMemory == 0 )
      {
         c4->tagMemory = mem4create( c4, c4->memStartTag, sizeof( TAG4 ), c4->memExpandTag, 0 ) ;
         if ( c4->tagMemory == 0 )
            return 0 ;
      }

      if ( c4->tagFileMemory == 0 )
      {
         c4->tagFileMemory = mem4create( c4, c4->memStartTagFile, sizeof( TAG4FILE ), c4->memExpandTagFile, 0 ) ;
         if ( c4->tagFileMemory == 0 )
            return 0 ;
      }

      i4 = (INDEX4 *)mem4alloc( c4->indexMemory ) ;
      if ( i4 == 0 )
         return 0 ;

      i4->codeBase = c4 ;
      i4->data = d4 ;
      l4add( &d4->indexes, i4 ) ;
      if ( fileName == 0 )
         u4namePiece( i4->accessName, sizeof( i4->accessName ), buf, 0, 0 ) ;
      else
         strcpy( i4->accessName, fileName ) ;
      c4upper( i4->accessName ) ;

      if ( file4open( &i4->file, c4, buf, 1 ) )
      {
         i4close( i4 ) ;
         if ( c4->errOpen )
            error4( c4, e4open, E81708 ) ;
         return 0 ;
      }

      file4seqReadInit( &seqread, &i4->file, 0, buffer, sizeof(buffer) ) ;

      pos = 0L ;
      rc = file4seqReadAll( &seqread, &firstByte, sizeof( firstByte ) ) ;
      if ( rc )
      {
         i4close( i4 ) ;
         if ( c4->errOpen )
            error4( c4, e4info, E81709 ) ;
         return 0 ;
      }

      if ( firstByte < 65 )   /* old format - potential problem if >= 65 files in an old format file. */
      {
         numFiles = firstByte ;
         if ( file4seqReadAll( &seqread, &firstByte, sizeof( firstByte ) ) )
         {
            i4close( i4 ) ;
            if ( c4->errOpen )
               error4( c4, e4info, E81709 ) ;
            return 0 ;
         }

         for ( i = 0 ; i < numFiles ; i++ )
         {
            if ( file4seqReadAll( &seqread, &len, sizeof( len ) ) )
            {
               file4close( &i4->file ) ;
               i4close( i4 ) ;
               if ( c4->errOpen )
                  error4( c4, e4info, E81709 ) ;
               return 0 ;
            }
            pos += sizeof( len ) ;
            rc = u4namePath( tagBuf, sizeof( tagBuf ), buf ) ;
            tagBuf[rc+len] = '\0' ;
            if ( sizeof( tagBuf ) > rc + len ) /* make sure room to read */
               rc = file4seqReadAll( &seqread, tagBuf+rc, len ) ;
            else
               rc = -1 ;

            if ( rc )
            {
               if ( c4->errOpen )
                  error4( c4, e4info, E81709 ) ;
               file4close( &i4->file ) ;
               i4close( i4 ) ;
               return 0 ;
            }

            pos += len ;
            if  ( t4open( d4, i4, tagBuf ) == 0 )
            {
               file4close( &i4->file ) ;
               i4close( i4 ) ;
               return 0 ;
            }
         }

         file4close( &i4->file ) ;
      }
      else
      {
         file4seqReadInit( &seqread, &i4->file, 0, buffer, sizeof(buffer) ) ;
         saveLen = 0 ;

         for( len = sizeof( tNames ) ; len == sizeof( tNames ) ; )
         {
            len = file4seqRead( &seqread, tNames, sizeof( tNames )) ;
            if ( len < sizeof( tNames ) ) /* case where all read in now - free up this file handle for use */
            {
               if ( file4close ( &i4->file ) )
               {
                  i4close( i4 ) ;
                  if ( c4->errOpen )
                     error4( c4, e4info, E81710 ) ;
                  return 0 ;
               }
               if ( len == 0 )
                  break ;
            }
            for( iPos = 0, pos = 0 ; pos < len ; )
            {
               switch( tNames[pos] )
               {
                  /* cases where the values are ignored, or found name */
                  case ' ':
                  case '\r':
                  case '\n':
                  case '\t':
                  case '\x1A':
                     if ( iPos < pos )  /* try to open the file */
                     {
                        tempLen = pos - iPos ;
                        if ( saveLen == 0 )
                        {
                           rc = u4namePath( tagBuf, sizeof( tagBuf ), buf ) ;
                           tagBuf[rc + tempLen] = '\0' ;
                        }
                        else
                           rc = saveLen ;
                        memcpy( tagBuf + rc, &tNames[iPos], tempLen ) ;

                        if  ( t4open( d4, i4, tagBuf ) == 0 )
                        {
                           file4close( &i4->file ) ;
                           i4close( i4 ) ;
                           return 0 ;
                        }
                     }
                     iPos = ++pos ;
                     break ;

                  /* case where a name is attempted to be read in */
                  default:
                     pos++ ;
               }
            }
            tempLen = pos - iPos ;
            rc = u4namePath( tagBuf, sizeof( tagBuf ), buf ) ;
            tagBuf[rc+tempLen] = '\0' ;
            memcpy( tagBuf + rc, &tNames[iPos], tempLen ) ;
            saveLen = rc + tempLen ;
         }

         if ( ( saveLen - rc ) > 0 )  /* try to open the file */
         {
            if  ( t4open( d4, i4, tagBuf ) == 0 )
            {
               file4close( &i4->file ) ;
               i4close( i4 ) ;
               return 0 ;
            }
         }
      }
   #endif

   #ifndef S4OFF_TRAN
      i4->isValid = 1 ;
   #endif

   return i4 ;
}

TAG4 *S4FUNCTION i4tag( INDEX4 *i4, const char *tagName )
{
   char tagLookup[LEN4TAG_ALIAS+1] ;
   TAG4 *tagOn ;

   #ifdef S4VBASIC
      if ( c4parm_check( i4, 0, E91709 ) )
         return 0 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( i4 == 0 || tagName == 0 )
      {
         error4( 0, e4parm_null, E91709 ) ;
         return 0 ;
      }
   #endif

   u4ncpy( tagLookup, tagName, sizeof( tagLookup ) - 1 ) ;
   c4upper( tagLookup ) ;

   for( tagOn = 0 ;; )
   {
      tagOn = (TAG4 *)l4next( &i4->tags, tagOn) ;
      if ( tagOn == 0 )
         break ;
      if ( strcmp( tagOn->tagFile->alias, tagLookup) == 0 )
         return tagOn ;
   }

   if ( i4->codeBase->errTagName )
      error4describe( i4->codeBase, e4tagName, E91709, tagName, 0, 0 ) ;
   return 0 ;
}
#endif   /*  ifdef S4CLIPPER  */

#ifndef S4CLIPPER
#ifndef S4CLIENT
int index4isProduction( INDEX4FILE *i4 )
{
   #ifdef S4FOX
      int l1, l2, count ;
   #endif
   #ifdef E4PARM_LOW
      if ( i4 == 0 )
         return error4( 0, e4parm_null, E91714 ) ;
   #endif

   #ifdef S4MDX
      #ifdef S4SERVER
         return i4->header.isProduction ;
      #else
         return i4->dataFile->openMdx ;
      #endif
   #endif

   #ifdef S4FOX
      #ifdef S4SERVER
         if ( i4->dataFile->hasMdxMemo )
      #else
         if ( i4->dataFile->openMdx )
      #endif
      {
         if ( i4->file.name == 0 )   /* most likely a failure during open/create now closing */
            return 0 ;
         l1 = strlen( i4->file.name ) ;
         if ( l1 == 0 )
            return 0 ;
         for ( count = l1 - 1 ;; count-- )
         {
            if ( count <= 0 )
               break ;
            if ( i4->file.name[count] == '.' )
            {
               l1 = count ;
               break ;
            }
         }
         l2 = strlen( i4->dataFile->file.name ) ;
         if ( l2 == 0 )
            return 0 ;
         for ( count = l2 - 1 ;; count-- )
         {
            if ( count <= 0 )
               break ;
            if ( i4->dataFile->file.name[count] == '.' )
            {
               l2 = count ;
               break ;
            }
         }
         if ( l1 == l2 )
            return( c4memcmp( i4->file.name, i4->dataFile->file.name, (unsigned)l1 ) ? 0 : 1 ) ;
      }
      return 0 ;
   #endif
}
#endif /* S4CLIENT */
#endif /* S4CLIPPER */
#endif /* S4INDEX_OFF */

#ifdef S4VB_DOS
INDEX4 * i4open_v( DATA4 *d4, char *name )
{
   char *namePtr ;

   namePtr = c4str(name) ;

   if (namePtr[0] == '\0' )
      return i4open( d4, 0 ) ;

   return i4open( d4, namePtr ) ;
}

TAG4 *i4tag_v( INDEX4 *ind, char *tagName )
{
 return i4tag( ind, c4str(tagName) ) ;
}

#endif  /* S4VB_DOS */