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

#include "d4all.h"

#ifndef S4UNIX
   #ifdef __TURBOC__
      #pragma hdrstop
   #endif
#endif

#ifndef S4CLIENT
#ifndef S4INDEX_OFF

/* This function creates a branch out of the input constant, and combines it with the input map */
static int bitmap4constantCombine( BITMAP4 *parent, BITMAP4 *oldAndMap, CONST4 *con, int conType )
{
   BITMAP4 *tempLeaf, *andMap, *newBranch ;
   CONST4 *temp ;

   if ( con->len == 0 || error4code( parent->log->codeBase ) == e4memory )
      return 0 ;

   newBranch = bitmap4create( parent->log, parent->relate, 1, 1 ) ;
   if ( newBranch == 0 )
      return 0 ;

   andMap = bitmap4create( parent->log, parent->relate, 0, 0 ) ;
   if ( andMap == 0 )
      return 0 ;
   bitmap4copy( andMap, oldAndMap ) ;
   l4add( &newBranch->children, andMap ) ;

   tempLeaf = bitmap4create( parent->log, parent->relate, 1, 0 ) ;
   if ( tempLeaf == 0 )
      return 0 ;
   tempLeaf->type = andMap->type ;
   tempLeaf->tag = andMap->tag ;
   l4add( &newBranch->children, tempLeaf ) ;

   switch( conType )
   {
      case 1:
         memcpy( (void *)&tempLeaf->lt, (void *)con, sizeof( CONST4 ) ) ;
         break ;
      case 2:
         memcpy( (void *)&tempLeaf->le, (void *)con, sizeof( CONST4 ) ) ;
         break ;
      case 3:
         memcpy( (void *)&tempLeaf->gt, (void *)con, sizeof( CONST4 ) ) ;
         break ;
      case 4:
         memcpy( (void *)&tempLeaf->ge, (void *)con, sizeof( CONST4 ) ) ;
         break ;
      case 5:
         memcpy( (void *)&tempLeaf->eq, (void *)con, sizeof( CONST4 ) ) ;
         break ;
      case 6:
         temp = (CONST4 *)u4alloc( (long)sizeof( CONST4 ) ) ;
         if ( temp == 0 )
            return 0 ;
         memcpy( (void *)temp, (void *)con, sizeof( CONST4 ) ) ;
         l4add( &tempLeaf->ne, temp ) ;
         break ;
      default:
         return error4( parent->log->codeBase, e4info, E93701 ) ;
   }
   memset( (void *)con, 0 ,sizeof( CONST4 ) ) ;
   newBranch = bitmap4redistribute( 0, newBranch, 0 ) ;

   if ( error4code( parent->log->codeBase ) < 0 )
      return error4code( parent->log->codeBase ) ;

   if ( newBranch->children.nLink == 0 )
      bitmap4destroy( newBranch ) ;
   else
      l4add( &parent->children, newBranch ) ;

   return 0 ;
}

/* this function redistributes (splits and combines) and/and, or/or block sequences */
BITMAP4 * bitmap4redistribute( BITMAP4 *parent, BITMAP4 *map, const char doShrink )
{
   BITMAP4 *childMap, *childOn, *parent2map ;
   char split ;

   if ( map->branch == 0 )
      return map ;

   /* first combine all the children of this map */
   childOn = childMap = (BITMAP4 *)l4first( &map->children ) ;
   for( ;; )
   {
      if ( childOn == 0 )
         break ;
      childOn = bitmap4redistribute( map, childOn, 0 ) ;
      childOn = (BITMAP4 *)l4next( &map->children, childOn ) ;
   }

   /* now combine all leaf children where possible */
   if ( parent != 0 )
      if ( parent->andOr != map->andOr )  /* case where no combos possible */
         return map ;

   parent2map = 0 ;
   childMap = (BITMAP4 *)l4first( &map->children ) ;
   for( ; childMap != 0 ; )
   {
      childOn = (BITMAP4 *)l4next( &map->children, childMap ) ;
      if ( childOn == 0 )
         break ;

      split = 0 ;
      if ( childOn->tag != childMap->tag || childOn->andOr != childMap->andOr )
        split = 1 ;
      else
      {
        if ( map != 0 )
           if ( map->andOr != childOn->andOr )
              split = 1 ;
      }

      if ( split == 1 )
      {
         if ( parent2map == 0 )
         {
            parent2map = bitmap4create( map->log, map->relate, map->andOr, 1 ) ;
            if ( parent2map == 0 )  /* must handle by freeing... */
               return 0 ;
            if ( parent == 0 )
            {
               parent = bitmap4create( map->log, map->relate, map->andOr, 1 ) ;
               if ( parent == 0 )  /* must handle by freeing... */
                  return 0 ;
               l4add( &parent->children, map ) ;
            }
            l4add( &parent->children, parent2map ) ;
         }
         l4remove( &map->children, childOn ) ;
         l4add( &parent2map->children, childOn ) ;
      }
      else
      {
         childMap = bitmap4combineLeafs( map, childMap, childOn ) ;
         if ( error4code( map->log->codeBase ) < 0 )
            return 0 ;
      }
   }

   if ( parent2map != 0 )
   {
      #ifdef E4ANALYZE
         if ( parent == 0 )
         {
            error4( map->log->codeBase, e4info, E93701 ) ;
            return 0 ;
         }
      #endif
      bitmap4redistribute( parent, parent2map, 1 ) ;
   }

   if ( doShrink )
   {
      if ( map->children.nLink == 1 )   /* just a child, so remove myself */
      {
         childMap = (BITMAP4 *)l4first( &map->children ) ;
         l4remove( &map->children, childMap ) ;
         if ( parent != 0 )
         {
            #ifdef E4ANALYZE
               if ( childMap->tag == 0 && childMap->children.nLink == 0 )
               {
                  error4( childMap->log->codeBase, e4info, E93701 ) ;
                  return 0 ;
               }
            #endif
            if ( parent->tag == 0 && childMap->tag != 0 )
               parent->tag = childMap->tag ;
            l4addAfter( &parent->children, map, childMap ) ;
            l4remove( &parent->children, map ) ;
         }
         bitmap4destroy( map ) ;
         map = childMap ;
      }
   }

   if ( parent2map != 0 && parent != 0 )
      return parent ;

   return map ;
}

/* this function redistributes the input maps by breaking the one up into constants and creating maps for each */
BITMAP4 *bitmap4redistributeLeaf( BITMAP4 *parent, BITMAP4 *map1, BITMAP4 *map2 )
{
   BITMAP4 *newBranch, *orMap, *place, *andMap, *temp ;
   CONST4 *cOn ;

   newBranch = bitmap4create( parent->log, parent->relate, 1, 1 ) ;
   if ( newBranch == 0 )
      return 0 ;

   place = bitmap4create( parent->log, parent->relate, 0, 0 ) ;
   if ( place == 0 )
      return 0 ;
   l4addAfter( &parent->children, map1, place ) ;

   l4remove( &parent->children, map1 ) ;
   l4remove( &parent->children, map2 ) ;

   if ( map1->andOr == 1 )
   {
      andMap = map1 ;
      orMap = map2 ;
   }
   else
   {
      andMap = map2 ;
      orMap = map1 ;
   }

   bitmap4constantCombine( newBranch, andMap, &orMap->lt, 1 ) ;
   bitmap4constantCombine( newBranch, andMap, &orMap->le, 2 ) ;
   bitmap4constantCombine( newBranch, andMap, &orMap->gt, 3 ) ;
   bitmap4constantCombine( newBranch, andMap, &orMap->ge, 4 ) ;
   bitmap4constantCombine( newBranch, andMap, &orMap->eq, 5 ) ;
   for( ;; )
   {
      cOn = (CONST4 *)l4first( &orMap->ne ) ;
      if ( cOn == 0 )
         break ;
      bitmap4constantCombine( newBranch, andMap, cOn, 6 ) ;
   }

   if ( error4code( parent->log->codeBase ) == e4memory )
      return 0 ;

   if ( newBranch->children.nLink == 0 )   /* collapsed */
   {
      if ( parent->tag == 0 && andMap->tag != 0 )
         parent->tag = andMap->tag ;
      bitmap4destroy( newBranch ) ;
      newBranch = 0 ;
   }
   else
   {
      while( newBranch->branch == 1 && newBranch->children.nLink == 1 )
      {
         temp = (BITMAP4 *)l4first( &newBranch->children ) ;
         bitmap4destroy( newBranch ) ;
         newBranch = temp ;
      }
      l4addAfter( &parent->children, place, newBranch ) ;
   }

   l4remove( &parent->children, place ) ;
   bitmap4destroy( place ) ;
   bitmap4destroy( orMap ) ;
   bitmap4destroy( andMap ) ;

   return newBranch ;
}

/* this function splits and combines and/or, or/and block sequences */
/* all bitmaps must be in standard bitmap4redistribute format prior to call */
BITMAP4 * bitmap4redistributeBranch( BITMAP4 *parent, BITMAP4 *map )
{
   BITMAP4 *childOn2, *childOn, *childNext2 ;

   if ( map->branch == 0 )
      return map ;

   childOn = (BITMAP4 *)l4first( &map->children ) ;

   for( ;; )
   {
      if ( childOn == 0 )
         break ;
      if ( childOn->branch )
      {
         childOn = bitmap4redistributeBranch( map, childOn ) ;
         if ( childOn == 0 && error4code( parent->log->codeBase ) == e4memory )
            return 0 ;
      }
      if ( childOn->branch == 0 )
      {
         childOn2 = (BITMAP4 *)l4next( &map->children, childOn ) ;
         while( childOn2 != 0 )
         {
            if ( childOn2->branch )
            {
               childOn2 = bitmap4redistributeBranch( map, childOn2 ) ;
               if ( childOn2 == 0 && error4code( parent->log->codeBase ) == e4memory )
                  return 0 ;
            }
            childNext2 = (BITMAP4 *)l4next( &map->children, childOn2 ) ;
            if ( childOn->branch == 0 && map->andOr == 1 && childOn->tag == childOn2->tag &&  childOn->andOr != childOn2->andOr )
            {
               childOn = bitmap4redistributeLeaf( map, childOn, childOn2 ) ;
               if ( childOn == 0 && error4code( parent->log->codeBase ) == e4memory )
                  return 0 ;
            }
            childOn2 = childNext2 ;
         }
      }
      childOn = (BITMAP4 *)l4next( &map->children, childOn ) ;
   }

   if ( map->branch == 1 )
   {
      if ( map->children.nLink == 0 )   /* mark ourselves as a leaf with no match */
      {
         map->branch = 0 ;
         map->noMatch = 1 ;
      }
      else
         if ( map->children.nLink == 1 )   /* just a child, so remove myself */
         {
            childOn = (BITMAP4 *)l4first( &map->children ) ;
            l4remove( &map->children, childOn ) ;
            if ( parent != 0 )
            {
               l4addAfter( &parent->children, map, childOn ) ;
               l4remove( &parent->children, map ) ;
            }
            bitmap4destroy( map ) ;
            map = childOn ;
         }
   }

   return map ;
}

/* location = 0 if seek_before, 1 if seek 1st, 2 if seek last, 3 if seek_after,  */
/* add 10 if it is to be an approximate seek */
/* returns record number */
#ifdef S4HAS_DESCENDING
long bitmap4seek( BITMAP4 *map, const CONST4 *con, const char location, const long check, const int doCheck )
{
   int len, rc ;
   TAG4FILE *tag ;
   char *result ;
   #ifdef S4CLIPPER
      int oldDec ;
      char holdResult[20] ;  /* enough space for a numerical key */
   #endif

   #ifdef S4VFP_KEY
      char buf[I4MAX_KEY_SIZE] ;
   #endif

   tag = map->tag ;
   result = (char *)const4return( map->log, con ) ;

   /* must convert to a proper key */
   if ( map->type != r4str )
   {
      #ifdef S4CLIPPER
         {
            oldDec = tag->codeBase->decimals ;
            tag->codeBase->decimals = tag->header.keyDec ;
            memcpy( holdResult, result, con->len ) ;
            result = holdResult ;
      #endif
      #ifdef E4ANALYZE
         if ( expr4len( tag->expr ) == -1 )
            return error4( map->log->codeBase, e4info, E83701 ) ;
      #endif
      len = expr4keyConvert( tag->expr, (char **)&result, con->len, map->type ) ;
      #ifdef S4CLIPPER
            tag->codeBase->decimals = oldDec ;
         }
      #endif
   }
   else
   {
      len = con->len ;
      #ifdef S4VFP_KEY
      if ( tfile4vfpKey( tag ) )
      {
         if ( len*2 > sizeof(buf) )
            return error4( map->log->codeBase, e4info, E82102 ) ;
         len = t4strToVFPKey( buf, result, len, len*2, &tag->vfpInfo ) ;
         if ( len < 0 )
            return error4( map->log->codeBase, e4info, E85404 ) ;
         result = buf ;
      }
      #endif
   }

   if ( location > 1 )
      tfile4descending( tag, 1 ) ;
   else
      tfile4descending( tag, 0 ) ;
   tfile4seek( tag, result, len ) ;
   tfile4descending( tag, 0 ) ;

   if ( !tfile4eof( tag ) )
      if ( doCheck == 1 )
        if ( check == tfile4recNo( tag ) )
           return -1 ;

   switch ( location )
   {
      case 0:
         if ( tfile4skip( tag, -1L ) != -1L )   /* at top already */
            return -1 ;
         break ;
      case 1:
         if ( tfile4eof( tag ) )
            return -1 ;
         break ;
      case 2:
         if ( !tfile4eof( tag ) )
         #ifdef S4FOX
            if( u4keycmp( tfile4keyData(tag)->value, result, (unsigned int)len, (unsigned int)tag->header.keyLen, 0, &tag->vfpInfo ) != 0 )
          #else
            if( (*tag->cmp)( tfile4keyData(tag)->value, result, (unsigned int)len ) != 0 )  /* last one is too far, go back one for a closure */
         #endif
         {
            if ( doCheck == 1 )
               if ( check == tfile4recNo( tag ) )   /* case where none belong, so break now */
                  return -1 ;
         }
         break ;
      case 3:
         if ( tfile4eof( tag ) )
         {
            rc = tfile4top( tag ) ;
            if ( rc != 0 )  /* no records */
               return -1 ;
         }
         else
         {
            rc = (int)tfile4skip( tag, 1L ) ;
            if ( rc == 0L )
               return -1 ;
         }
         break ;
      default:
         return error4( map->log->codeBase, e4info, E93701 ) ;
   }

   return tfile4recNo( tag ) ;
}
#endif
#ifdef S4NDX
long bitmap4seek( BITMAP4 *map, CONST4 *con, char location, long check, int doCheck )
{
   int len, rc ;
   TAG4FILE *tag ;
   char *result ;
   char didSkip ;
   int seekRc ;

   tag = map->tag ;
   result = (char *)const4return( map->log, con ) ;

   if ( map->type != r4str )   /* must convert to a proper key */
   {
      #ifdef E4ANALYZE
         if ( expr4len( tag->expr ) == -1 )
            return error4( map->log->codeBase, e4info, 83701 ) ;
      #endif
      len = expr4keyConvert( tag->expr, (char **)&result, con->len, map->type ) ;
   }
   else
      len = con->len ;

   seekRc = tfile4seek( tag, result, len ) ;

   if ( !tfile4eof( tag ) )
      if ( doCheck && location < 2 )
        if ( check == tfile4recNo( tag ) )
           return -1 ;

   switch ( location )
   {
      case 0:
         if ( tfile4skip( tag, -1L ) != -1L )   /* at top already */
           return -1 ;
         break ;
      case 1:
         if ( tfile4eof( tag ) )
            return -1 ;
         break ;
      case 2:
         if( (*tag->cmp)( tfile4keyData(tag)->value, result, len ) != 0 )  /* last one is too far, go back one for a closure */
         {
            if ( !tfile4eof( tag ) )
               if ( check == tfile4recNo( tag ) )   /* case where none belong, so break now */
                  return -1 ;
            if ( tfile4skip( tag, -1L ) != -1L )
               return -1 ;
         }
      case 3:
         didSkip = 0 ;

         for(; (*tag->cmp)( tfile4keyData(tag)->value, result, len ) == 0; )
         {
            rc = (int)tfile4skip( tag, 1L ) ;
            if ( rc < 0 )
               return -1 ;
            if ( rc != 1 )
            {
               if ( location == 2 )   /* on last record, but it still belongs, so don't skip back */
                  didSkip = 0 ;
               if ( location == 3 )   /* on last record not far enough, so none match */
                  return -1 ;
               break ;
            }
            didSkip = 1 ;
         }

         if ( location == 3 )
         {
            if ( didSkip == 0 && seekRc != 2 )
               if ( tfile4skip( tag, 1L ) != 1L )
                  return -1 ;
         }
         else
            if ( didSkip == 1 )
               if ( tfile4skip( tag, -1L ) != -1L )
                  return -1 ;
        break ;
      default:
         return error4( map->log->codeBase, e4info, E93701 ) ;
   }

   return tfile4recNo( tag ) ;
}
#endif
#ifdef S4MDX
long bitmap4seek( BITMAP4 *map, const CONST4 *con, const char location, const long check, const int doCheck )
{
   int len, rc, seekRc, isDesc ;
   TAG4FILE *tag ;
   char *result ;
   char didSkip ;

   tag = map->tag ;
   result = (char *)const4return( map->log, con ) ;
   isDesc = ( tag->header.typeCode & 8 ) ? 1 : 0 ;

   if ( map->type != r4str )   /* must convert to a proper key */
   {
      #ifdef E4ANALYZE
         if ( expr4len( tag->expr ) == -1 )
            return error4( map->log->codeBase, e4info, E83701 ) ;
      #endif
      len = expr4keyConvert( tag->expr, (char **)&result, con->len, map->type ) ;
   }
   else
      len = con->len ;

   seekRc = tfile4seek( tag, result, len ) ;

   if ( !tfile4eof( tag ) )
      if ( doCheck && location < 2 )
         if ( check == tfile4recNo( tag ) )
            return -1 ;

   switch ( location )
   {
      case 0:
         if ( isDesc )
         {
            if ( tfile4eof( tag ) )
               return -1 ;
            for(; (*tag->cmp)( tfile4keyData(tag)->value, result, len ) == 0; )
            {
               rc = (int)tfile4skip( tag, 1L ) ;
               if ( rc < 0 )
                 return -1 ;
               if ( rc != 1 )
               {
                 if ( rc == 0 )
                    return -1 ;
                 break ;
               }
            }
         }
         else
            if ( tfile4skip( tag, -1L ) != -1L )   /* at top already */
               return -1 ;
         break ;
       case 1:
         if ( isDesc )
         {
            if ( seekRc == 2 )
            {
               if ( !tfile4eof( tag ) )
                 if ( check == tfile4recNo( tag ) )   /* case where none belong, so break now */
                    return -1 ;
               if ( tfile4skip( tag, -1L ) != -1L )
                 return -1 ;
            }
            else
            {
               rc = -1 ;
               for(; (*tag->cmp)( tfile4keyData(tag)->value, result, len ) == 0; )
               {
                  rc = (int)tfile4skip( tag, 1L ) ;
                  if ( rc < 0 )
                     return -1 ;
                  if ( rc != 1 )
                     break ;
               }
               if ( rc == 0 )
                  tfile4bottom( tag ) ;
               else
                  tfile4skip( tag, -1L ) ;
            }
         }
         else
         {
            if ( tfile4eof( tag ) )
               return -1 ;
         }
         break ;
      case 2:
         if ( isDesc )
         {
            if ( tfile4eof( tag ) )
               return -1 ;
            if ( seekRc == 2 )
               if ( check == tfile4recNo( tag ) )   /* case where none belong, so break now */
                  return -1 ;
            break ;
         }
         else
         {
            if( (*tag->cmp)( tfile4keyData(tag)->value, result, len ) != 0 )  /* last one is too far, go back one for a closure */
            {
               if ( !tfile4eof( tag ) )
                  if ( check == tfile4recNo( tag ) )   /* case where none belong, so break now */
                     return -1 ;
               if ( tfile4skip( tag, -1L ) != -1L )
                  return -1 ;
            }
         }
      case 3:
         if ( isDesc )
         {
            if ( tfile4skip( tag, -1L ) != -1L )   /* at top already */
               return -1 ;
         }
         else
         {
            didSkip = 0 ;

            for(; (*tag->cmp)( tfile4keyData(tag)->value, result, len ) == 0; )
            {
               rc = (int)tfile4skip( tag, 1L ) ;
               if ( rc < 0 )
                  return -1 ;
               if ( rc != 1 )
               {
                  if ( location == 2 )   /* on last record, but it still belongs, so don't skip back */
                     didSkip = 0 ;
                  if ( location == 3 )   /* on last record not far enough, so none match */
                     return -1 ;
                  break ;
               }
               didSkip = 1 ;
            }

            if ( location == 3 )
            {
               if ( didSkip == 0 && seekRc != 2 )
                  if ( tfile4skip( tag, 1L ) != 1L )
                     return -1 ;
            }
            else
               if ( didSkip == 1 )
                 if ( tfile4skip( tag, -1L ) != -1L )
                     return -1 ;
         }
         break ;
      default:
         return error4( map->log->codeBase, e4info, E93701 ) ;
   }

   return tfile4recNo( tag ) ;
}
#endif

/* returns a pointer to the constant value */
void *const4return( L4LOGICAL *log, const CONST4 *c1 )
{
   return (void *)( log->buf + c1->offset ) ;
}

/* updates the log's constant memory buffer, re-allocating memory if required */
int const4memAlloc( L4LOGICAL *log, const unsigned len )
{
   if ( ( log->bufPos + len ) > log->bufLen )
   {
      #ifdef E4ANALYZE
         if ( (long)len + (long)log->bufLen != (long)(len + log->bufLen) )
            return error4( log->codeBase, e4memory, E83702 ) ;
      #endif
      if ( u4allocAgain( log->codeBase, &log->buf, &log->bufLen, log->bufPos + len ) != 0 )
         return error4( log->codeBase, e4memory, E93704 ) ;
   }
   log->bufPos += len ;
   return 0 ;
}

/* duplicate an existing constant */
int const4duplicate( CONST4 *to, const CONST4 *from, L4LOGICAL *log )
{
   unsigned int len ;

   len = (unsigned int)from->len ;

   if ( len == 0 )
      memset( (void *)to, 0, (unsigned int)sizeof( CONST4 ) ) ;
   else
   {
      if ( const4memAlloc( log, len ) < 0 )
         return -1 ;
      memcpy( log->buf + log->bufPos - len, const4return( log, from ), len ) ;
      to->offset = log->bufLen - len ;
      to->len = len ;
   }

   return 0 ;
}

/* get a constant from an expr. info structure */
int const4get( CONST4 *con, BITMAP4 *map, L4LOGICAL *log, const int pos )
{
   unsigned int len ;
   char *result ;
   int rc ;

   if ( expr4execute( log->expr, pos, (void **)&result ) < 0 )
      return -1 ;
   len = (unsigned int)log->expr->info[pos].len ;

   #ifdef E4ANALYZE
      if ( map->type != 0 && map->type != v4functions[log->expr->info[pos].functionI].returnType )
         return error4( map->log->codeBase, e4info, E83703 ) ;
   #endif

   rc = const4memAlloc( log, len ) ;
   if ( rc < 0 )
      return error4stack( map->log->codeBase, rc, E93704 ) ;

   memcpy( log->buf + log->bufPos - len, result, len ) ;
   map->type = v4functions[log->expr->info[pos].functionI].returnType ;
   con->offset = log->bufLen - len ;
   con->len = len ;

   return 0 ;
}

int const4less( CONST4 *p1, CONST4 *p2, BITMAP4 *map )
{
   switch( map->type )
   {
      case r4numDoub:
      case r4dateDoub:
         #ifdef E4ANALYZE
            if ( p1->len != p2->len )
               return error4( map->log->codeBase, e4struct, E93704 ) ;
         #endif
         if ( *(double *)const4return( map->log, p1 ) < *(double *)const4return( map->log, p2 ) )
            return 1 ;
         break ;
      case r4num:
      case r4str:
         if ( p1->len < p2->len )
         {
            if ( c4memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), (unsigned int)p1->len ) <= 0 )
               return 1 ;
         }
         else
            if ( c4memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), (unsigned int)p2->len ) < 0 )
               return 1 ;
         break ;
      default:
         return error4( map->log->codeBase, e4info, E93704 ) ;
   }

   return 0 ;
}

int const4eq( CONST4 *p1, CONST4 *p2, BITMAP4 *map )
{
   if ( p1->len < p2->len )
   {
      #ifdef E4ANALYZE
         if ( map->type == r4numDoub || map->type == r4dateDoub )
            return error4( map->log->codeBase, e4struct, E93704 ) ;
      #endif
      return 0 ;
   }

   #ifdef E4ANALYZE
      switch( map->type )
      {
         case r4numDoub:
         case r4dateDoub:
         case r4num:
         case r4str:
         case r4log:
            break ;
         default:
            return error4( map->log->codeBase, e4info, E93704 ) ;
      }
   #endif

   if ( c4memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), (unsigned int)p1->len ) == 0 )
      return 1 ;

   return 0 ;
}

int const4lessEq( CONST4 *p1, CONST4 *p2, BITMAP4 *map )
{
   switch( map->type )
   {
      case r4numDoub:
      case r4dateDoub:
         #ifdef E4ANALYZE
            if ( p1->len != p2->len )
               return error4( map->log->codeBase, e4struct, E93704 ) ;
         #endif
         if ( *(double *)const4return( map->log, p1 ) <= *(double *)const4return( map->log, p2 ) )
            return 1 ;
         break ;
      case r4num:
      case r4str:
         if ( p1->len <= p2->len )
         {
            if ( c4memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), (unsigned int)p1->len ) <= 0 )
               return 1 ;
         }
         else
            if ( c4memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), (unsigned int)p2->len ) < 0 )
               return 1 ;
         break ;
      default:
         return error4( map->log->codeBase, e4info, E93704 ) ;
   }

   return 0 ;
}

void const4addNe( BITMAP4 *map, CONST4 *con )
{
   CONST4 *cOn ;

   cOn = (CONST4 *)l4first( &map->ne ) ;
   while ( cOn != 0 )
   {
      if ( const4eq( con, cOn, map ) )  /* ne already exists, so ignore */
         return ;
      cOn = (CONST4 *)l4next( &map->ne, cOn ) ;
   }
   cOn = (CONST4 *) u4alloc( (long)sizeof( CONST4 ) ) ;
   if ( cOn == 0 )
      return ;
   memcpy( (void *)cOn, (void *)con, (unsigned int)sizeof( CONST4 ) ) ;
   l4add( &map->ne, cOn ) ;
   memset( (void *)con, 0, (unsigned int)sizeof( CONST4 ) ) ;
}

void const4deleteNe( LIST4 *list, CONST4 *con )
{
   l4remove( list, con ) ;
   u4free( con ) ;
}

#endif   /* S4INDEX_OFF */
#endif   /* S4CLIENT */