hsx

Top  Previous  Next

c:\harbour\source\rdd\hsx
cftsfunc.c
TypeFunctionSourceLine
HB_FUNCCFTSADD(void)
HB_FUNC( CFTSADD )
{
   HB_FUNC_EXEC( HS_ADD );
}
cftsfunc.c76
HB_FUNCCFTSCLOSE(void)
HB_FUNC( CFTSCLOSE )
{
   HB_FUNC_EXEC( HS_CLOSE );
}
cftsfunc.c81
HB_FUNCCFTSCREA(void)
HB_FUNC( CFTSCREA )
{
   HB_FUNC_EXEC( HS_CREATE );
}
cftsfunc.c86
HB_FUNCCFTSDELETE(void)
HB_FUNC( CFTSDELETE )
{
   HB_FUNC_EXEC( HS_DELETE );
}
cftsfunc.c91
HB_FUNCCFTSIFDEL(void)
HB_FUNC( CFTSIFDEL )
{
   HB_FUNC_EXEC( HS_IFDEL );
}
cftsfunc.c96
HB_FUNCCFTSNEXT(void)
HB_FUNC( CFTSNEXT )
{
   HB_FUNC_EXEC( HS_NEXT );
}
cftsfunc.c101
HB_FUNCCFTSOPEN(void)
HB_FUNC( CFTSOPEN )
{
   HB_FUNC_EXEC( HS_OPEN );
}
cftsfunc.c106
HB_FUNCCFTSRECN(void)
HB_FUNC( CFTSRECN )
{
   HB_FUNC_EXEC( HS_KEYCOUNT );
}
cftsfunc.c111
HB_FUNCCFTSREPLAC(void)
HB_FUNC( CFTSREPLAC )
{
   HB_FUNC_EXEC( HS_REPLACE );
}
cftsfunc.c116
HB_FUNCCFTSSET(void)
HB_FUNC( CFTSSET )
{
   HB_FUNC_EXEC( HS_SET );
}
cftsfunc.c121
HB_FUNCCFTSUNDEL(void)
HB_FUNC( CFTSUNDEL )
{
   HB_FUNC_EXEC( HS_UNDELETE );
}
cftsfunc.c126
HB_FUNCCFTSVERI(void)
HB_FUNC( CFTSVERI )
{
   HB_FUNC_EXEC( HS_VERIFY );
}
cftsfunc.c131
HB_FUNCCFTSVERS(void)
HB_FUNC( CFTSVERS )
{
   HB_FUNC_EXEC( HS_VERSION );
}
cftsfunc.c136
hsx.c
TypeFunctionSourceLine
STATIC INThb_hsxHashVal( int c1, int c2, int iKeyBits, BOOL fNoCase, int iFilter, BOOL fUseHash )
static int hb_hsxHashVal( int c1, int c2, int iKeyBits,
                          BOOL fNoCase, int iFilter, BOOL fUseHash )
{
   int iBitNum;

   if ( fNoCase )
   {
#ifndef HB_CDP_SUPPORT_OFF
      if ( iFilter == 3 && hb_cdp_page->nChars )
      {
         c1 = ( BYTE ) hb_cdp_page->s_upper[ c1 ];
         c2 = ( BYTE ) hb_cdp_page->s_upper[ c2 ];
      }
      else
#endif
      {
         if ( c1 >= 'a' && c1 <= 'z' )
            c1 -= 'a' - 'A';
         if ( c2 >= 'a' && c2 <= 'z' )
            c2 -= 'a' - 'A';
      }
   }
   if ( iFilter == 1 )
   {
      c1 &= 0x7F;
      if ( c1 < 0x20 || c1 == 0x7f ) c1 = ' ';
      c2 &= 0x7F;
      if ( c2 < 0x20 || c2 == 0x7f ) c2 = ' ';
   }

   if ( c1 == ' ' || c2 == ' ' || c1 == 0 || c2 == 0 )
      iBitNum = 0;
   else if ( fUseHash && c1 >= 'A' && c1 <= 'Z' && c2 >= 'A' && c2 <= 'Z' )
   {
      iBitNum = hb_hsxHashArray[ ( c1 - 'A' ) * 26 + ( c2 - 'A' ) ] + 1;
   }
   else
   {
      iBitNum = ( c1 + c2 * 78 ) % ( iKeyBits - 1 ) + 1;
      if ( iBitNum == 1 )
         iBitNum++;
   }
   return iBitNum;
}
hsx.c380
STATIC VOIDhb_hsxHashStr( BYTE * pStr, ULONG ulLen, BYTE * pKey, int iKeySize, BOOL fNoCase, int iFilter, BOOL fUseHash )
static void hb_hsxHashStr( BYTE * pStr, ULONG ulLen, BYTE * pKey, int iKeySize,
                           BOOL fNoCase, int iFilter, BOOL fUseHash )
{
   int c1, c2, iBitNum, iKeyBits = iKeySize << 3;

   memset( pKey, '\0', iKeySize );
#if 0
/* This code keeps the strict CFTS behavior which stops string
   manipulating at first chr(0) character */
   if ( pStr && ulLen-- && ( c1 = *pStr++ ) != 0 )
   {
      while ( ulLen-- && ( c2 = *pStr++ ) != 0 )
      {
#else 
   /* This version can work well with embedded 0 characters */
   if ( pStr && ulLen-- )
   {
      c1 = *pStr++;
      while ( ulLen-- )
      {
         c2 = *pStr++;
#endif
         iBitNum = hb_hsxHashVal( c1, c2, iKeyBits, fNoCase, iFilter, fUseHash );
         if ( iBitNum-- )
         {
            pKey[ iBitNum >> 3 ] |= 0x80 >> ( iBitNum & 7 );
         }
         c1 = c2;
      }
   }
}

static int hb_hsxStrCmp( BYTE * pSub, ULONG ulSub, BYTE * pStr, ULONG ulLen,
                         BOOL fNoCase, int iFilter )
{
   BOOL fResult = FALSE;
   BYTE c1, c2;
   ULONG ul;

   if ( ulSub == 0 )
      return HSX_SUCCESSFALSE;

   while ( !fResult && ulLen >= ulSub )
   {
      fResult = TRUE;
      for ( ul = 0; fResult && ul < ulSub; ul++ )
      {
         c1 = pSub[ ul ];
         c2 = pStr[ ul ];
         if ( fNoCase )
         {
#ifndef HB_CDP_SUPPORT_OFF
            if ( iFilter == 3 && hb_cdp_page->nChars )
            {
               c1 = ( BYTE ) hb_cdp_page->s_upper[ c1 ];
               c2 = ( BYTE ) hb_cdp_page->s_upper[ c2 ];
            }
            else
#endif
            {
               if ( c1 >= 'a' && c1 <= 'z' )
                  c1 -= 'a' - 'A';
               if ( c2 >= 'a' && c2 <= 'z' )
                  c2 -= 'a' - 'A';
            }
         }
#if 0
/* This code is for strict CftsVeri() behavior - uncomment if necessary
   but it's IMHO bug */
         if ( iFilter == 1 )
         {
            c1 &= 0x7F;
            if ( c1 < 0x20 || c1 == 0x7f ) c1 = ' ';
            c2 &= 0x7F;
            if ( c2 < 0x20 || c2 == 0x7f ) c2 = ' ';
         }
#elif defined( HB_CDP_SUPPORT_OFF )
         HB_SYMBOL_UNUSED( iFilter );
#endif
         fResult = ( c1 == c2 );
      }
      --ulLen;
      ++pStr;
   }

   return fResult ? HSX_SUCCESS : HSX_SUCCESSFALSE;
}

static LPHSXINFO hb_hsxGetPointer( int iHandle )
{
   return ( iHandle >=0 && iHandle < s_iHandleSize ) ?
          s_handleArray[ iHandle ] : NULL;
}

static int hb_hsxCompile( char * szExpr, PHB_ITEM * pExpr )
{
   AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();

   *pExpr = NULL;
   if ( pArea )
   {
      if ( SELF_COMPILE( pArea, ( BYTE * ) szExpr ) == FAILURE )
         return HSX_BADPARMS;
      *pExpr = pArea->valResult;
      pArea->valResult = NULL;
   }
   else
   {
      HB_MACRO_PTR pMacro = hb_macroCompile( szExpr );
      if( !pMacro )
         return HSX_BADPARMS;
      *pExpr = hb_itemPutPtr( NULL, ( void * ) pMacro );
   }
   return HSX_SUCCESS;
}

static int hb_hsxEval( int iHandle, PHB_ITEM pExpr, BYTE *pKey, BOOL *fDeleted )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iResult = HSX_SUCCESS;
   BYTE * pStr;
   ULONG ulLen;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( !pExpr )
      pExpr = pHSX->pKeyItem;

   if ( !pExpr )
      return HSX_BADPARMS;

   if ( hb_itemType( pExpr ) & HB_IT_STRING )
   {
      pStr = ( BYTE * ) hb_itemGetCPtr( pExpr );
      ulLen = hb_itemGetCLen( pExpr );
      if ( fDeleted )
         *fDeleted = FALSE;
   }
   else
   {
      int iArea = 0;
      PHB_ITEM pItem;

      if ( pHSX->iArea != 0 )
      {
         iArea = hb_rddGetCurrentWorkAreaNumber();
         if ( iArea != pHSX->iArea )
            hb_rddSelectWorkAreaNumber( pHSX->iArea );
         else
            iArea = 0;
      }
      pItem = hb_vmEvalBlockOrMacro( pExpr );
      pStr = ( BYTE * ) hb_itemGetCPtr( pItem );
      ulLen = hb_itemGetCLen( pItem );
      if ( fDeleted )
      {
         AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
         if ( !pArea )
            *fDeleted = FALSE;
         else if ( SELF_DELETED( pArea, fDeleted ) == FAILURE )
            iResult = HSX_RDDFAILURE;
      }
      if ( iArea )
         hb_rddSelectWorkAreaNumber( iArea );
      if ( hb_vmRequestQuery() )
         iResult = HSX_BADPARMS;
   }

   if ( iResult == HSX_SUCCESS )
      hb_hsxHashStr( pStr, ulLen, pKey, pHSX->uiRecordSize, pHSX->fIgnoreCase,
                     pHSX->iFilterType, pHSX->fUseHash );

   return iResult;
}

static void hb_hsxGetRecCount( LPHSXINFO pHSX )
{
   pHSX->ulRecCount = ( ULONG ) ( ( hb_fsSeekLarge( pHSX->hFile, 0, FS_END ) - 
                                    HSXHEADER_LEN ) / pHSX->uiRecordSize );
}

static int hb_hsxHdrFlush( int iHandle )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( pHSX->fHdrChanged )
   {
      BYTE headrBuf[ HSXHEADER_LEN ];
      LPHSXHEADER pHeader = ( LPHSXHEADER ) headrBuf;
      USHORT uiBits = 0, uiSize = pHSX->uiRecordSize;

      while ( uiSize >>= 1 )
         uiBits++;

      HB_PUT_LE_UINT32( pHeader->recCount,    pHSX->ulRecCount );
      HB_PUT_LE_UINT32( pHeader->recSize,     ( UINT32 ) pHSX->uiRecordSize );
      HB_PUT_LE_UINT32( pHeader->recSizeBits, ( UINT32 ) uiBits );
      HB_PUT_LE_UINT16( pHeader->ignoreCase,  pHSX->fIgnoreCase ? 1 : 0 );
      HB_PUT_LE_UINT16( pHeader->filterType,  pHSX->iFilterType );
      HB_PUT_LE_UINT32( pHeader->hashLetters, pHSX->fUseHash ? 1 : 0 );

      memset( pHeader->keyExpression, 0, HSXKEYEXP_LEN + 1 );
      if ( pHSX->szKeyExpr )
         hb_strncpy( ( char * ) pHeader->keyExpression, pHSX->szKeyExpr, HSXKEYEXP_LEN );

      if ( hb_fsSeek( pHSX->hFile, 0, FS_SET ) != 0 )
         return HSX_BADHDRWRITE;
      if ( hb_fsWrite( pHSX->hFile, headrBuf, HSXHEADER_LEN ) != HSXHEADER_LEN )
         return HSX_BADHDRWRITE;

      pHSX->fHdrChanged = FALSE;
      pHSX->fFlush = TRUE;
   }
   return HSX_SUCCESS;
}

static int hb_hsxFlush( int iHandle )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( pHSX->fChanged )
   {
      HB_FOFFSET fOffset;
      ULONG ulSize;

      fOffset = ( HB_FOFFSET ) HSXHEADER_LEN +
                ( HB_FOFFSET ) ( pHSX->ulFirstRec - 1 ) *
                ( HB_FOFFSET ) pHSX->uiRecordSize;

      if ( hb_fsSeekLarge( pHSX->hFile, fOffset, FS_SET ) != fOffset )
         return HSX_BADSEEK;

      ulSize = pHSX->ulBufRec * pHSX->uiRecordSize;

      if ( hb_fsWriteLarge( pHSX->hFile, pHSX->pBuffer, ulSize ) != ulSize )
         return HSX_BADWRITE;

      pHSX->fChanged = FALSE;
      pHSX->fFlush = TRUE;
   }
   return HSX_SUCCESS;
}

static int hb_hsxFlushAll( int iHandle )
{
   int iRetVal;

   iRetVal = hb_hsxFlush( iHandle );
   if ( iRetVal == HSX_SUCCESS )
      iRetVal = hb_hsxHdrFlush( iHandle );

   return iRetVal;
}

static int hb_hsxHdrRead( int iHandle )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   BYTE headrBuf[ HSXHEADER_LEN ];
   LPHSXHEADER pHeader = ( LPHSXHEADER ) headrBuf;
   int iResult = HSX_SUCCESS;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( hb_fsSeek( pHSX->hFile, 0, FS_SET ) != 0 )
      return HSX_BADREAD;
   if ( hb_fsRead( pHSX->hFile, headrBuf, HSXHEADER_LEN ) != HSXHEADER_LEN )
      return HSX_BADREAD;

   pHSX->ulRecCount = HB_GET_LE_UINT32( pHeader->recCount );
   pHSX->uiRecordSize = HB_GET_LE_UINT32( pHeader->recSize );
   pHSX->fIgnoreCase = HB_GET_LE_UINT16( pHeader->ignoreCase ) != 0;
   pHSX->iFilterType = HB_GET_LE_UINT16( pHeader->filterType );
   pHSX->fUseHash = HB_GET_LE_UINT32( pHeader->hashLetters ) != 0;

   if ( pHeader->keyExpression[0] >= ' ' )
   {
      headrBuf[ HSXHEADER_LEN - 1 ] = '\0';
      pHSX->szKeyExpr = hb_strdup( ( char * ) pHeader->keyExpression );
      iResult = hb_hsxCompile( pHSX->szKeyExpr, &pHSX->pKeyItem );
   }

   /* update the record counter */
   hb_hsxGetRecCount( pHSX );

   return iResult;
}

static int hb_hsxRead( int iHandle, ULONG ulRecord, BYTE ** pRecPtr )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   BOOL fCount = pHSX->fShared;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( ulRecord > pHSX->ulRecCount && fCount )
   {
      hb_hsxGetRecCount( pHSX );
      fCount = FALSE;
   }

   if ( ulRecord == 0 || ulRecord > pHSX->ulRecCount )
      return HSX_RECBOUND;

   if ( pHSX->ulFirstRec == 0 || ulRecord < pHSX->ulFirstRec ||
        ulRecord >= pHSX->ulFirstRec + pHSX->ulBufRec )
   {
      HB_FOFFSET fOffset;
      ULONG ulSize, ulFirst;
      int iRetVal;

      if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS )
         return iRetVal;

      ulFirst = ulRecord;
      if ( pHSX->fWrLocked && pHSX->fShared )
         pHSX->ulBufRec = 1;
      else if ( ulFirst + pHSX->ulBufSize - 1 <= pHSX->ulRecCount )
         pHSX->ulBufRec = pHSX->ulBufSize;
      else
      {
         if ( fCount )
            hb_hsxGetRecCount( pHSX );
         pHSX->ulBufRec = HB_MIN( pHSX->ulBufSize, pHSX->ulRecCount - ulFirst + 1 );
      }

      fOffset = ( HB_FOFFSET ) HSXHEADER_LEN +
                ( HB_FOFFSET ) ( ulFirst - 1 ) *
                ( HB_FOFFSET ) pHSX->uiRecordSize;
      ulSize = pHSX->ulBufRec * pHSX->uiRecordSize;

      if ( hb_fsSeekLarge( pHSX->hFile, fOffset, FS_SET ) != fOffset )
      {
         pHSX->ulFirstRec = pHSX->ulBufRec = 0;
         return HSX_BADREAD;
      }
      if ( hb_fsReadLarge( pHSX->hFile, pHSX->pBuffer, ulSize ) != ulSize )
      {
         pHSX->ulFirstRec = pHSX->ulBufRec = 0;
         return HSX_BADREAD;
      }
      pHSX->ulFirstRec = ulFirst;
   }

   *pRecPtr = pHSX->pBuffer + ( ulRecord - pHSX->ulFirstRec ) * pHSX->uiRecordSize;

   return HSX_SUCCESS;
}

static int hb_hsxAppend( int iHandle, ULONG * pulRecNo, BYTE **pRecPtr )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( pHSX->ulFirstRec == 0 || pHSX->ulBufRec == pHSX->ulBufSize ||
        pHSX->ulFirstRec + pHSX->ulBufRec != pHSX->ulRecCount + 1 )
   {
      int iRetVal;

      if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS )
         return iRetVal;

      *pulRecNo = pHSX->ulFirstRec = ++pHSX->ulRecCount;
      pHSX->ulBufRec = 1;
   }
   else
   {
      pHSX->ulBufRec++;
      *pulRecNo = ++pHSX->ulRecCount;
   }
   *pRecPtr = pHSX->pBuffer + ( pHSX->ulBufRec - 1 ) * pHSX->uiRecordSize;
   pHSX->fHdrChanged = TRUE;

   return HSX_SUCCESS;
}

static int hb_hsxUpdate( int iHandle, ULONG ulRecord, BYTE **pRecPtr )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( ulRecord > pHSX->ulRecCount )
   {
      /* this is intentional - when HSX index is bound with workarea
       * then all updates should be synced by WA locks and it should
       * be save to use REPLACE called from GOCOLD() method instead of
       * ADD for newly appended records */
      if ( pHSX->iArea != 0 )
         pHSX->ulRecCount = ulRecord;
      else if ( pHSX->fShared )
         hb_hsxGetRecCount( pHSX );
   }

   if ( ulRecord == 0 || ulRecord > pHSX->ulRecCount )
      return HSX_RECBOUND;

   if ( pHSX->ulFirstRec == 0 || ulRecord < pHSX->ulFirstRec ||
        ulRecord >= pHSX->ulFirstRec + pHSX->ulBufRec )
   {
      int iRetVal;

      if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS )
         return iRetVal;

      pHSX->ulFirstRec = ulRecord;
      pHSX->ulBufRec = 1;
   }
   *pRecPtr = pHSX->pBuffer + ( ulRecord - pHSX->ulFirstRec ) * pHSX->uiRecordSize;

   return HSX_SUCCESS;
}

static int hb_hsxLock( int iHandle, int iAction, ULONG ulRecord )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal = HSX_SUCCESS, iRet;
   BOOL fResult;

   HB_SYMBOL_UNUSED( ulRecord );

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( pHSX->fReadonly )
   {
      switch ( iAction )
      {
         case HSX_WRITELOCK:
         case HSX_UPDATELOCK:
         case HSX_APPENDLOCK:
         case HSX_HDRWRITELOCK:
            return HSX_LOCKFAILED;
      }
   }

   /*
    * When HSX is bound with with workarea it should be synced
    * by WA locks to not cause additional overhead with repeated
    * operations. hb_hsxAdd() should be called when WA APPEND_LOCK
    * is set and hb_hsxReplace() inside GOCOLD() method
    */
   if ( pHSX->fShared && pHSX->iArea == 0 )
   {
      switch ( iAction )
      {
         case HSX_READLOCK:
            break;

         case HSX_WRITELOCK:
         case HSX_UPDATELOCK:
         case HSX_APPENDLOCK:
            do
            {
               fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE,
                                         FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT );
            } while ( !fResult );
            if ( iRetVal == HSX_SUCCESS )
            {
               /* discrad buffers in shared mode */
               pHSX->ulFirstRec = pHSX->ulBufRec = 0;
               if ( iAction == HSX_APPENDLOCK )
                  hb_hsxGetRecCount( pHSX );
               else if ( iAction == HSX_WRITELOCK )
                  pHSX->fWrLocked = TRUE;
            }
            break;

         case HSX_HDRREADLOCK:
            do
            {
               fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE,
                                         FL_LOCK | FLX_SHARED | FLX_WAIT );
            } while ( !fResult );
            break;

         case HSX_HDRWRITELOCK:
            do
            {
               fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE,
                                         FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT );
            } while ( !fResult );
            break;

         case HSX_READUNLOCK:
            break;

         case HSX_WRITEUNLOCK:
         case HSX_UPDATEUNLOCK:
         case HSX_APPENDUNLOCK:
            iRetVal = hb_hsxFlush( iHandle );
            if ( iAction == HSX_APPENDLOCK )
               pHSX->fWrLocked = FALSE;
         case HSX_HDRWRITEUNLOCK:
            iRet = hb_hsxHdrFlush( iHandle );
            if ( iRetVal == HSX_SUCCESS )
               iRetVal = iRet;
         case HSX_HDRREADUNLOCK:
            if ( ! hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE,
                                   FL_UNLOCK ) )
            {
               if ( iRetVal == HSX_SUCCESS )
                  iRetVal = HSX_CANNOTUNLOCK;
            }
            break;
      }
   }

   return iRetVal;
}

static int hb_hsxIfDel( int iHandle, ULONG ulRecord )
{
   BYTE *pRecPtr;
   int iRetVal, iRet;

   iRetVal = hb_hsxLock( iHandle, HSX_READLOCK, ulRecord );

   if ( iRetVal == HSX_SUCCESS )
   {
      iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = *pRecPtr & 0x80 ? HSX_SUCCESS : HSX_SUCCESSFALSE;
   }
   iRet = hb_hsxLock( iHandle, HSX_READUNLOCK, ulRecord );
   if ( iRet != HSX_SUCCESS )
      iRetVal = iRet;
   return iRetVal;
}

static int hb_hsxDelete( int iHandle, ULONG ulRecord )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal, iRet;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   iRetVal = hb_hsxLock( iHandle, HSX_UPDATELOCK, ulRecord );
   if ( iRetVal == HSX_SUCCESS )
   {
      BYTE *pRecPtr;

      iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr );
      if ( iRetVal == HSX_SUCCESS )
      {
         if ( *pRecPtr & 0x80 )
            iRetVal = HSX_ISDELETED;
         else
         {
            *pRecPtr |= 0x80;
            pHSX->fChanged = TRUE;
            iRetVal = HSX_SUCCESS;
         }
      }
      iRet = hb_hsxLock( iHandle, HSX_UPDATEUNLOCK, ulRecord );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }
   return iRetVal;
}

static int hb_hsxUnDelete( int iHandle, ULONG ulRecord )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal, iRet;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   iRetVal = hb_hsxLock( iHandle, HSX_UPDATELOCK, ulRecord );
   if ( iRetVal == HSX_SUCCESS )
   {
      BYTE *pRecPtr;

      iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr );
      if ( iRetVal == HSX_SUCCESS )
      {
         if ( ( *pRecPtr & 0x80 ) == 0 )
            iRetVal = HSX_NOTDELETED;
         else
         {
            *pRecPtr &= ~0x80;
            pHSX->fChanged = TRUE;
            iRetVal = HSX_SUCCESS;
         }
      }
      iRet = hb_hsxLock( iHandle, HSX_UPDATEUNLOCK, ulRecord );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }
   return iRetVal;
}

static int hb_hsxReplace( int iHandle, ULONG ulRecord, PHB_ITEM pExpr, BOOL fDeleted )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal, iRet;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   iRetVal = hb_hsxLock( iHandle, HSX_WRITELOCK, ulRecord );
   if ( iRetVal == HSX_SUCCESS )
   {
      BYTE * pRecPtr;

      iRetVal = hb_hsxUpdate( iHandle, ulRecord, &pRecPtr );
      if ( iRetVal == HSX_SUCCESS )
      {
         iRetVal = hb_hsxEval( iHandle, pExpr, pRecPtr, pExpr ? NULL : &fDeleted );
         if ( iRetVal == HSX_SUCCESS )
         {
            if ( fDeleted )
               *pRecPtr |= 0x80;
            pHSX->fChanged = TRUE;
         }
      }
      iRet = hb_hsxLock( iHandle, HSX_WRITEUNLOCK, ulRecord );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }
   return iRetVal;
}

static int hb_hsxAdd( int iHandle, ULONG *pulRecNo, PHB_ITEM pExpr, BOOL fDeleted )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal, iRet;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   if ( !pExpr && !pHSX->pKeyItem )
      return HSX_BADPARMS;

   iRetVal = hb_hsxLock( iHandle, HSX_APPENDLOCK, 0 );
   if ( iRetVal == HSX_SUCCESS )
   {
      BYTE * pRecPtr;
      ULONG ulRecNo;

      iRetVal = hb_hsxAppend( iHandle, &ulRecNo, &pRecPtr );
      if ( iRetVal == HSX_SUCCESS )
      {
         iRetVal = hb_hsxEval( iHandle, pExpr, pRecPtr, pExpr ? NULL : &fDeleted );
         if ( iRetVal == HSX_SUCCESS )
         {
            if ( fDeleted )
               *pRecPtr |= 0x80;
            pHSX->fChanged = TRUE;
            if ( pulRecNo )
               *pulRecNo = ulRecNo;
         }
      }
      iRet = hb_hsxLock( iHandle, HSX_APPENDUNLOCK, 0 );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }

   return iRetVal;
}

static int hb_hsxSeekSet( int iHandle, BYTE * pStr, ULONG ulLen )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal;

   if ( !pHSX )
      return HSX_BADHANDLE;

   iRetVal = hb_hsxFlushAll( iHandle );
   if ( iRetVal == HSX_SUCCESS )
   {
      if ( pHSX->ulRecCount == 0 )
         iRetVal = HSX_NORECS;
      else
      {
         if ( pHSX->pSearchVal )
            hb_xfree( pHSX->pSearchVal );
         pHSX->pSearchVal = ( BYTE * ) hb_xgrab( ulLen + 1 );
         memcpy( pHSX->pSearchVal, pStr, ulLen );
         pHSX->pSearchVal[ ulLen ] = '\0';
         pHSX->ulSearch = ulLen;
         if ( ! pHSX->pSearchKey )
            pHSX->pSearchKey = ( BYTE * ) hb_xgrab( pHSX->uiRecordSize );
         hb_hsxHashStr( pStr, ulLen, pHSX->pSearchKey,
                        pHSX->uiRecordSize, pHSX->fIgnoreCase,
                        pHSX->iFilterType, pHSX->fUseHash );
         pHSX->ulCurrRec = 0;
      }
   }
   return iRetVal;
}

static int hb_hsxNext( int iHandle, ULONG * pulRecNo )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iRetVal, iRet;

   *pulRecNo = 0;

   if ( ! pHSX )
      return HSX_BADHANDLE;

   iRetVal = hb_hsxLock( iHandle, HSX_READLOCK, 0 );
   if ( iRetVal == HSX_SUCCESS )
   {
      BYTE * pRecPtr;
      int i;

      while ( pHSX->ulCurrRec < pHSX->ulRecCount )
      {
         iRetVal = hb_hsxRead( iHandle, ++pHSX->ulCurrRec, &pRecPtr );
         if ( iRetVal != HSX_SUCCESS )
            break;
         if ( ! hb_set.HB_SET_DELETED || ( *pRecPtr & 0x80 ) == 0 ) /* Not deleted */
         {
            for ( i = 0; i < pHSX->uiRecordSize; i++ )
            {
               if ( ( pRecPtr[ i ] & pHSX->pSearchKey[ i ] ) != pHSX->pSearchKey[ i ] )
                  break;
            }
            if ( i == pHSX->uiRecordSize )
            {
               *pulRecNo = pHSX->ulCurrRec;
               break;
            }
         }
      }

      iRet = hb_hsxLock( iHandle, HSX_READUNLOCK, 0 );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }
   return iRetVal;
}

static LPHSXINFO hb_hsxNew( void )
{
   LPHSXINFO pHSX;
   int iHandle = 0;

   if ( s_iHandleSize == 0 )
   {
      s_iHandleSize = HSX_HALLOC;
      s_handleArray = ( LPHSXINFO * ) hb_xgrab( sizeof( LPHSXINFO ) * HSX_HALLOC );
      memset( s_handleArray, 0, sizeof( LPHSXINFO ) * s_iHandleSize );
   }
   else
   {
      while ( iHandle < s_iHandleSize )
      {
         if ( s_handleArray[ iHandle ] == NULL )
            break;
         iHandle++;
      }
      if ( iHandle == s_iHandleSize )
      {
         s_iHandleSize += HSX_HALLOC;
         s_handleArray = ( LPHSXINFO * ) hb_xrealloc( s_handleArray, 
                                          sizeof( LPHSXINFO ) * s_iHandleSize );
         memset( &s_handleArray[ iHandle ], 0, sizeof( LPHSXINFO ) * HSX_HALLOC );
      }
   }
   s_handleArray[ iHandle ] = pHSX = ( LPHSXINFO ) hb_xgrab( sizeof( HSXINFO ) );
   s_iHandleCount++;
   memset( pHSX, 0, sizeof( HSXINFO ) );
   pHSX->iHandle = iHandle;
   pHSX->hFile = FS_ERROR;

   return pHSX;
}

static void hb_hsxExpDestroy( PHB_ITEM pItem )
{
   if ( hb_itemType( pItem ) == HB_IT_POINTER )
      hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pItem ) );
   hb_itemRelease( pItem );
}

static int hb_hsxVerify( int iHandle, BYTE * szText, ULONG ulLen,
                         BYTE * szSub, ULONG ulSub, int iType )
{
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   int iResult;

   if ( !szSub && pHSX )
   {
      szSub = pHSX->pSearchVal;
      ulSub = pHSX->ulSearch;
   }
   if ( !pHSX )
      iResult = HSX_BADHANDLE;
   else if ( !szText || !szSub )
      iResult = HSX_BADPARMS;
   else if ( ulSub > ulLen || ulSub == 0 )
      /* !ulSub -> do not accept empty substrings as $ operator at runtime */
      iResult = HSX_SUCCESSFALSE;
   else
   {
      ULONG ul, ull;

      switch ( iType )
      {
         case HSX_VERIFY_BEGIN:
            iResult = hb_hsxStrCmp( szSub, ulSub, szText, ulSub,
                                    pHSX->fIgnoreCase, pHSX->iFilterType );
            break;
         case HSX_VERIFY_END:
            iResult = hb_hsxStrCmp( szSub, ulSub, szText + ulLen - ulSub, ulSub,
                                    pHSX->fIgnoreCase, pHSX->iFilterType );
            break;
         case HSX_VERIFY_AND:
            iResult = HSX_SUCCESS;
            for ( ul = 0; ul < ulSub && iResult == HSX_SUCCESS; ul++ )
            {
               while ( szSub[ ul ] == ' ' && ul < ulSub )
                  ++ul;
               ull = ul;
               while ( szSub[ ull ] != ' ' && ull < ulSub )
                  ++ull;
               iResult = hb_hsxStrCmp( &szSub[ ul ], ull - ul, szText, ulLen,
                                       pHSX->fIgnoreCase, pHSX->iFilterType );
               ul = ull;
            }
            break;
/*
         case HSX_VERIFY_OR:
            iResult = HSX_SUCCESSFALSE;
            for ( ul = 0; ul < ulSub && iResult == HSX_SUCCESSFALSE; ul++ )
            {
               while ( szSub[ ul ] == ' ' && ul < ulSub )
                  ++ul;
               ull = ul;
               while ( szSub[ ull ] != ' ' && ull < ulSub )
                  ++ull;
               iResult = hb_hsxStrCmp( &szSub[ ul ], ull - ul, szText, ulLen,
                                       pHSX->fIgnoreCase, pHSX->iFilterType );
               ul = ull;
            }
            break;
*/
         case HSX_VERIFY_PHRASE:
         default:
            iResult = hb_hsxStrCmp( szSub, ulSub, szText, ulLen,
                                    pHSX->fIgnoreCase, pHSX->iFilterType );
      }
   }
   return iResult;
}

static int hb_hsxDestroy( int iHandle )
{
   if ( iHandle >=0 && iHandle < s_iHandleSize && s_handleArray[ iHandle ] != NULL )
   {
      LPHSXINFO pHSX = s_handleArray[ iHandle ];
      int iRetVal = HSX_SUCCESS;

      if ( pHSX->hFile != FS_ERROR )
      {
         iRetVal = hb_hsxFlushAll( iHandle );
         hb_fsClose( pHSX->hFile );
      }

      if ( pHSX->szFileName )
         hb_xfree( pHSX->szFileName );
      if ( pHSX->pSearchVal )
         hb_xfree( pHSX->pSearchVal );
      if ( pHSX->pSearchKey )
         hb_xfree( pHSX->pSearchKey );
      if ( pHSX->pBuffer )
         hb_xfree( pHSX->pBuffer );
      if ( pHSX->szKeyExpr )
         hb_xfree( pHSX->szKeyExpr );
      if ( pHSX->pKeyItem )
         hb_hsxExpDestroy( pHSX->pKeyItem );
      hb_xfree( pHSX );

      s_handleArray[ iHandle ] = NULL;
      if ( --s_iHandleCount == 0 )
      {
         hb_xfree( s_handleArray );
         s_iHandleSize = 0;
         s_handleArray = NULL;
      }
      return iRetVal;
   }
   return HSX_BADHANDLE;
}

static int hb_hsxCreate( char * szFile, int iBufSize, int iKeySize,
                         BOOL fIgnoreCase, int iFilter, PHB_ITEM pExpr )
{
   char szFileName[ _POSIX_PATH_MAX + 1 ], * szExpr = NULL;
   PHB_ITEM pKeyExpr = NULL;
   ULONG ulBufSize;
   USHORT uiRecordSize;
   LPHSXINFO pHSX;
   FHANDLE hFile;
   int iRetVal;

   if ( !szFile || ! *szFile )
      return HSX_BADPARMS;

   hb_strncpy( szFileName, szFile, _POSIX_PATH_MAX );

   if ( iKeySize < 1 || iKeySize > HSXMAXKEY_SIZE )
      iKeySize = HSXDEFKEY_SIZE;
   if ( iFilter < 1 || iFilter > 3 )
      iFilter = HSXDEFFILTER;

   ulBufSize = iBufSize * 1024;
   if ( ulBufSize == 0 )
      ulBufSize = HSXDEFBUF_LEN;
   else if ( ulBufSize < HSXMINBUF_LEN )
      ulBufSize = HSXMINBUF_LEN;
   else if ( ulBufSize > HSXMAXBUF_LEN )
      ulBufSize = HSXMAXBUF_LEN;
   uiRecordSize = ( USHORT ) 0x08 << iKeySize;
   ulBufSize /= uiRecordSize;
   if ( ulBufSize == 0 )
      ulBufSize = 1;

   if ( pExpr )
   {
      if ( hb_itemGetCLen( pExpr ) > 0 )
      {
         szExpr = hb_itemGetCPtr( pExpr );
         iRetVal = hb_hsxCompile( szExpr, &pKeyExpr );
         if ( iRetVal != HSX_SUCCESS )
            return iRetVal;
      }
      else if ( hb_itemType( pExpr ) == HB_IT_BLOCK )
         pKeyExpr = hb_itemNew( pExpr );
   }

   hFile = hb_fsExtOpen( ( BYTE * ) szFileName, ( BYTE * ) HSX_FILEEXT,
                         FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE |
                         FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME,
                         NULL, NULL );

   if( hFile == FS_ERROR )
   {
      if ( pKeyExpr )
         hb_hsxExpDestroy( pKeyExpr );
      return HSX_CREATEFAIL;
   }

   pHSX = hb_hsxNew();
   pHSX->uiRecordSize = uiRecordSize;
   pHSX->fIgnoreCase = fIgnoreCase;
   pHSX->iFilterType = iFilter;
   pHSX->fUseHash = fIgnoreCase && iKeySize == 2 && iFilter != 3;
   pHSX->hFile = hFile;
   pHSX->szFileName = hb_strdup( szFileName );
   pHSX->fShared = FALSE;
   pHSX->fReadonly = FALSE;
   if ( szExpr )
      pHSX->szKeyExpr = hb_strdup( szExpr );
   pHSX->pKeyItem = pKeyExpr;
   pHSX->pBuffer = ( BYTE * ) hb_xalloc( ulBufSize * uiRecordSize );
   if ( pHSX->pBuffer == NULL )
   {
      hb_hsxDestroy( pHSX->iHandle );
      return HSX_MEMERR;
   }
   pHSX->ulBufSize = ulBufSize;

   pHSX->fHdrChanged = TRUE;
   iRetVal = hb_hsxHdrFlush( pHSX->iHandle );
   if ( iRetVal != HSX_SUCCESS )
   {
      hb_hsxDestroy( pHSX->iHandle );
      return iRetVal;
   }

   return pHSX->iHandle;
}

static int hb_hsxOpen( char * szFile, int iBufSize, int iMode )
{
   char szFileName[ _POSIX_PATH_MAX + 1 ];
   BOOL fShared, fReadonly;
   FHANDLE hFile;
   ULONG ulBufSize;
   USHORT uiFlags;
   LPHSXINFO pHSX;
   int iRetVal, iRet;

   if ( !szFile || ! *szFile )
      return HSX_BADPARMS;

   hb_strncpy( szFileName, szFile, _POSIX_PATH_MAX );

   ulBufSize = iBufSize * 1024;
   if ( ulBufSize == 0 )
      ulBufSize = HSXDEFBUF_LEN;
   else if ( ulBufSize < HSXMINBUF_LEN )
      ulBufSize = HSXMINBUF_LEN;
   else if ( ulBufSize > HSXMAXBUF_LEN )
      ulBufSize = HSXMAXBUF_LEN;

   if ( iMode < 0 || iMode > 3 )
      iMode = HSXDEFOPENMODE;

   fReadonly = ( iMode & 0x02 ) != 0;
   fShared = ( iMode & 0x01 ) == 0;
   if( hb_set.HB_SET_AUTOSHARE == 2 )
      fShared = FALSE;
   uiFlags = ( fReadonly ? FO_READ : FO_READWRITE ) |
             ( fShared ? FO_DENYNONE : FO_EXCLUSIVE );

   hFile = hb_fsExtOpen( ( BYTE * ) szFileName, ( BYTE * ) HSX_FILEEXT,
                         uiFlags | FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME,
                         NULL, NULL );

   if ( hFile == FS_ERROR )
      return HSX_OPENERR;

   pHSX = hb_hsxNew();
   pHSX->hFile = hFile;
   pHSX->szFileName = hb_strdup( szFileName );
   pHSX->fShared = fShared;
   pHSX->fReadonly = fReadonly;
   iRetVal = hb_hsxLock( pHSX->iHandle, HSX_HDRREADLOCK, 0 );
   if ( iRetVal == HSX_SUCCESS )
   {
      iRetVal = hb_hsxHdrRead( pHSX->iHandle );
      iRet = hb_hsxLock( pHSX->iHandle, HSX_HDRREADUNLOCK, 0 );
      if ( iRetVal == HSX_SUCCESS )
         iRetVal = iRet;
   }
   if ( iRetVal != HSX_SUCCESS )
   {
      hb_hsxDestroy( pHSX->iHandle );
      return iRetVal;
   }

   ulBufSize /= pHSX->uiRecordSize;
   if ( ulBufSize == 0 )
      ulBufSize = 1;

   pHSX->pBuffer = ( BYTE * ) hb_xalloc( ulBufSize * pHSX->uiRecordSize );
   if ( pHSX->pBuffer == NULL )
   {
      hb_hsxDestroy( pHSX->iHandle );
      return HSX_MEMERR;
   }
   pHSX->ulBufSize = ulBufSize;

   return pHSX->iHandle;
}

static int hb_hsxIndex( char * szFile, PHB_ITEM pExpr, int iKeySize, int iMode,
                        int iBufSize, BOOL fIgnoreCase, int iFilter )
{
   int iRetVal = HSX_SUCCESS, iHandle;
   ULONG ulRecNo = 0, ulRecCount = 0, ulNewRec, ulRec;
   ERRCODE errCode;
   AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();

   if ( !pArea )
   {
      hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_INDEX" );
      return HSX_NOTABLE;
   }

   iHandle = hb_hsxCreate( szFile, iBufSize, iKeySize, fIgnoreCase, iFilter, pExpr );
   if ( iHandle < 0 )
      return iHandle;

   errCode = SELF_RECCOUNT( pArea, &ulRecCount );
   if ( errCode != FAILURE && ulRecCount )
   {
      errCode = SELF_RECNO( pArea, &ulRecNo );
      if ( errCode != FAILURE )
      {
         for ( ulRec = 1; ulRec <= ulRecCount; ulRec++ )
         {
            errCode = SELF_GOTO( pArea, ulRec );
            if ( errCode == FAILURE )
               break;
            iRetVal = hb_hsxAdd( iHandle, &ulNewRec, NULL, FALSE );
            if ( iRetVal != HSX_SUCCESS )
               break;
            if ( ulNewRec != ulRec )
            {
               iRetVal = HSX_RECBOUND;
               break;
            }
         }
         if ( pArea->valResult )
         {
            hb_itemRelease( pArea->valResult );
            pArea->valResult = NULL;
         }
         if ( ulRecNo )
            SELF_GOTO( pArea, ulRecNo );
      }
   }
   hb_hsxDestroy( iHandle );
   if ( iRetVal != HSX_SUCCESS )
      return iRetVal;
   if ( errCode == FAILURE )
      return HSX_RDDFAILURE;

   return hb_hsxOpen( szFile, iBufSize, iMode );
}

static int hb_hsxFilter( int iHandle, BYTE * pSeek, ULONG ulSeek,
                         PHB_ITEM pVerify, int iVerifyType )
{
   AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
   LPHSXINFO pHSX = hb_hsxGetPointer( iHandle );
   BOOL fDestroyExpr = FALSE, fValid;
   int iResult = HSX_SUCCESS;
   ERRCODE errCode;
   ULONG ulRecNo = 0, ulRec;
   PHB_ITEM pItem;

   if ( !pHSX )
      return HSX_BADHANDLE;

   if ( !pArea )
   {
      hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_FILTER" );
      return HSX_NOTABLE;
   }

   if ( ! pVerify || hb_itemType( pVerify ) == HB_IT_NIL )
      pVerify = pHSX->pKeyItem;
   else
   {
      if ( hb_itemGetCLen( pVerify ) > 0 )
      {
         iResult = hb_hsxCompile( hb_itemGetCPtr( pVerify ), &pVerify );
         if ( iResult != HSX_SUCCESS )
            return HSX_BADPARMS;
         fDestroyExpr = TRUE;
      }
      else if ( hb_itemType( pVerify ) != HB_IT_BLOCK )
      {
         pVerify = NULL;
      }
   }

   errCode = SELF_RECNO( pArea, &ulRecNo );
   if ( errCode != FAILURE )
      iResult = hb_hsxSeekSet( iHandle, pSeek, ulSeek );

   fValid = TRUE;
   pItem = hb_itemNew( NULL );
   while ( iResult == HSX_SUCCESS && errCode != FAILURE )
   {
      iResult = hb_hsxNext( iHandle, &ulRec );
      if ( iResult != HSX_SUCCESS || ulRec == 0 )
         break;
      if ( pVerify )
      {
         errCode = SELF_GOTO( pArea, ulRec );
         if ( errCode == FAILURE )
            break;
         errCode = SELF_EVALBLOCK( pArea, pVerify );
         if ( errCode == FAILURE )
            break;
         fValid = hb_hsxVerify( iHandle,
                                ( BYTE * ) hb_itemGetCPtr( pArea->valResult ),
                                hb_itemGetCLen( pArea->valResult ),
                                pSeek, ulSeek, iVerifyType ) == HSX_SUCCESS;
      }
      if ( fValid )
      {
         /* set record in WA RM filter */
         hb_itemPutNInt( pItem, ulRec );
         errCode = SELF_INFO( pArea, DBI_RM_ADD, pItem );
      }
   }
   if ( pArea->valResult )
   {
      hb_itemRelease( pArea->valResult );
      pArea->valResult = NULL;
   }
   hb_itemRelease( pItem );

   if ( ulRecNo )
      SELF_GOTO( pArea, ulRecNo );

   if ( fDestroyExpr )
      hb_hsxExpDestroy( pVerify );

   return errCode == FAILURE ? HSX_RDDFAILURE : iResult;
}


/* ************************************************************************ */
/* .prg level functions: HS_*() */
/* ************************************************************************ */

/* hs_Create( , , , , ,  )
                     -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE)
   Creates a new, empty HiPer-SEEK index file */
HB_FUNC( HS_CREATE )
{
   hb_retni( hb_hsxCreate( hb_parc( 1 ), hb_parni( 2 ), hb_parni( 3 ),
                           hb_param( 4, HB_IT_LOGICAL ) == NULL || hb_parl( 4 ),
                           hb_parni( 5 ), hb_param( 6, HB_IT_ANY ) ) );
}

/* hs_Open( , ,  )
                     -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE)
   Opens an existing HiPer-SEEK index file */
HB_FUNC( HS_OPEN )
{
   hb_retni( hb_hsxOpen( hb_parc( 1 ), hb_parni( 2 ),
             hb_param( 3, HB_IT_NUMERIC ) ? hb_parni( 3 ) : HSXDEFOPENMODE ) );
}

/* hs_Close(  ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE)
   Closes a previously opened HiPer-SEEK index file */
HB_FUNC( HS_CLOSE )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) )
      hb_retni( hb_hsxDestroy( hb_parni( 1 ) ) );
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_Index( , , , , , ,
              ) -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE)
   Creates and populates a new HiPer-SEEK index */
HB_FUNC( HS_INDEX )
{
   hb_retni( hb_hsxIndex( hb_parc( 1 ), hb_param( 2, HB_IT_ANY ), hb_parni( 3 ),
                          hb_param( 4, HB_IT_NUMERIC ) ? hb_parni( 4 ) : HSXDEFOPENMODE,
                          hb_parni( 5 ),
                          hb_param( 6, HB_IT_LOGICAL ) == NULL || hb_parl( 6 ),
                          hb_parni( 7 ) ) );
}

/* hs_Add( , [], [lDel] ) -> nVal >= 1 (RECNO), nVal < 0 (ERROR CODE)
   Adds a text string entry to a HiPer-SEEK index file */
HB_FUNC( HS_ADD )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) )
   {
      ULONG ulRecNo;
      int iRetVal;

      iRetVal = hb_hsxAdd( hb_parni( 1 ), &ulRecNo,
                           hb_param( 2, HB_IT_BLOCK | HB_IT_STRING ),
                           hb_parl( 3 ) );

      if ( iRetVal == HSX_SUCCESS )
         hb_retnint( ulRecNo );
      else
         hb_retni( iRetVal );
   }
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_Replace( , [], , [lDel] ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE)
   Replaces current HiPer-SEEK index entry with a new value */
HB_FUNC( HS_REPLACE )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 3, HB_IT_NUMERIC ) )
      hb_retni( hb_hsxReplace( hb_parni( 1 ), hb_parnl( 3 ), 
                               hb_param( 2, HB_IT_BLOCK | HB_IT_STRING ),
                               hb_parl( 4 ) ) );
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_IfDel( ,  ) -> nVal = {0|1} (DELETED), nVal < 0 (ERROR CODE)
   Determines if a HiPer-SEEK record is marked as deleted */
HB_FUNC( HS_IFDEL )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) )
      hb_retni( hb_hsxIfDel( hb_parni( 1 ), hb_parnl( 2 ) ) );
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_Delete( ,  ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE)
   Deletes specifed index record from HiPer-SEEK index file */
HB_FUNC( HS_DELETE )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) )
      hb_retni( hb_hsxDelete( hb_parni( 1 ), hb_parnl( 2 ) ) );
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_Undelete( ,  ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE)
   Unmarks the specified HiPer-SEEK record as being deleted */
HB_FUNC( HS_UNDELETE )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) )
      hb_retni( hb_hsxUnDelete( hb_parni( 1 ), hb_parnl( 2 ) ) );
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_KeyCount(  ) -> nVal >= 0 (RECCOUNT), nVal < 0 (ERROR CODE)
   Returns the number of entries in a HiPer-SEEK index */
HB_FUNC( HS_KEYCOUNT )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) )
   {
      LPHSXINFO pHSX = hb_hsxGetPointer( hb_parni( 1 ) );

      if ( pHSX )
      {
         if ( pHSX->fShared )
            hb_hsxGetRecCount( pHSX );

         hb_retnint( pHSX->ulRecCount );
      }
      else
         hb_retni( HSX_BADHANDLE );
   }
   else
      hb_retni( HSX_BADPARMS );
}

/* hs_Set( ,  ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE)
   Sets up parameters for a subsequent hs_Next() call */
HB_FUNC( HS_SET )
{
   BYTE * pStr = ( BYTE * ) hb_parc( 2 );
   int iRetVal = HSX_BADPARMS;

   if ( pStr && hb_param( 1, HB_IT_NUMERIC ) )
      iRetVal = hb_hsxSeekSet( hb_parni( 1 ), pStr, hb_parclen( 2 ) );
   hb_retni( iRetVal );
}

/* hs_Filter( , , [xRealExp], [nBufSize], [nOpenMode] ) -> nRecMatch
   Sets a WA RM filter using a HiPer-SEEK index */
HB_FUNC( HS_FILTER )
{
   BYTE * szText = ( BYTE * ) hb_parc( 2 ), * pBuff = NULL;
   ULONG ulLen = hb_parclen( 2 ), ulRecords = 0, ull, ul;
   int iHandle = -1, iResult = HSX_BADPARMS;
   BOOL fNew = FALSE, fToken = TRUE;

   if ( hb_parclen( 1 ) > 0 )
   {
      if ( ulLen > 0 )
      {
         iHandle = hb_hsxOpen( hb_parc( 1 ), hb_parni( 4 ),
               hb_param( 5, HB_IT_NUMERIC ) ? hb_parni( 5 ) : HSXDEFOPENMODE );
         if ( iHandle >= 0 )
            fNew = TRUE;
         else
            iResult = iHandle;
      }
   }
   else if ( hb_param( 1, HB_IT_NUMERIC ) )
   {
      LPHSXINFO pHSX = hb_hsxGetPointer( hb_parni( 1 ) );

      if ( ! pHSX )
         iResult = HSX_BADHANDLE;
      else
      {
         iHandle = pHSX->iHandle;
         if ( !szText )
         {
            ulLen = pHSX->ulSearch;
            if ( ulLen && pHSX->pSearchVal )
            {
               pBuff = ( BYTE * ) hb_xgrab( ulLen + 1 );
               memcpy( pBuff, pHSX->pSearchVal, ulLen );
               pBuff[ ulLen ] = '\0';
               szText = pBuff;
               fToken = FALSE;
            }
         }
      }
   }
   if ( iHandle >= 0 && ulLen > 0 )
   {
      PHB_ITEM pItem = hb_itemNew( NULL );
      AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();

      if ( !pArea )
      {
         hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_FILTER" );
         iResult = HSX_NOTABLE;
      }
      /* create empty workarea RM filter */
      else if ( SELF_INFO( pArea, DBI_RM_CREATE, pItem ) == FAILURE )
         iResult = HSX_RDDFAILURE;
      else
      {
         /* to be SIX compatible divide given text on space delimited tokens */
         if ( fToken )
         {
            iResult = HSX_SUCCESS;
            for ( ul = 0; ul < ulLen && iResult == HSX_SUCCESS; ul++ )
            {
               while ( szText[ ul ] == ' ' && ul < ulLen )
                  ++ul;
               ull = ul;
               while ( szText[ ull ] != ' ' && ull < ulLen )
                  ++ull;
               iResult = hb_hsxFilter( iHandle, &szText[ ul ], ull - ul,
                                 hb_param( 3, HB_IT_ANY ), HSX_VERIFY_PHRASE );
               ul = ull;
            }
         }
         else
         {
            iResult = hb_hsxFilter( iHandle, szText, ulLen,
                                    hb_param( 3, HB_IT_ANY ),
                                    HSX_VERIFY_PHRASE );
         }
      }
      if ( iResult == HSX_SUCCESS )
      {
         hb_itemPutNI( pItem, 0 );
         if ( SELF_INFO( pArea, DBI_RM_COUNT, pItem ) == FAILURE )
            iResult = HSX_RDDFAILURE;
         else
            ulRecords = hb_itemGetNL( pItem );
      }
      hb_itemRelease( pItem );

      if ( fNew )
         hb_hsxDestroy( iHandle );
   }
   if ( pBuff )
      hb_xfree( pBuff );

   if ( iResult != HSX_SUCCESS )
      hb_retni( iResult );
   else
      hb_retnint( ulRecords );
}

/* hs_Next(  ) -> nVal >= 0 (RECNO), nVal < 0 (ERROR CODE)
   Searches a HiPer-SEEK index file for first/next match */
HB_FUNC( HS_NEXT )
{
   ULONG ulRecNo = 0;
   int iRetVal = HSX_BADPARMS;

   if ( hb_param( 1, HB_IT_NUMERIC ) )
      iRetVal = hb_hsxNext( hb_parni( 1 ), &ulRecNo );

   if ( iRetVal == HSX_SUCCESS )
      hb_retnint( ulRecNo );
   else
      hb_retni( iRetVal );
}

/* hs_Verify( , , ,  )
          -> nVal = {0|1} (VERIFIED), nVal < 0 (ERROR CODE)
   hs_Verify( ,  ) -> lOK
   Verifies hs_Next() hit against code block expression */
HB_FUNC( HS_VERIFY )
{
   if ( hb_param( 1, HB_IT_NUMERIC ) )
   {
      int iHandle = hb_parni( 1 );
      PHB_ITEM pExpr = hb_param( 2, HB_IT_BLOCK );
      BYTE * szText = NULL;
      ULONG ulLen = 0;
      LPHSXINFO pHSX;

      pHSX = hb_hsxGetPointer( iHandle );
      if ( !pHSX )
      {
         hb_retni( HSX_BADHANDLE );
         return;
      }
      if ( pExpr )
         pExpr = hb_vmEvalBlockOrMacro( pExpr );
      else
      {
         pExpr = hb_param( 2, HB_IT_STRING );
         if ( !pExpr && pHSX->pKeyItem )
            pExpr = hb_vmEvalBlockOrMacro( pHSX->pKeyItem );
      }
      if ( pExpr )
      {
         szText = ( BYTE * ) hb_itemGetCPtr( pExpr );
         ulLen = hb_itemGetCLen( pExpr );
      }

      hb_retni( hb_hsxVerify( hb_parni( 1 ), szText, ulLen,
                              ( BYTE * ) hb_parc( 3 ), hb_parclen( 3 ),
                              hb_parni( 4 ) ) );
   }
   else
   {
      PHB_ITEM pExpr = hb_param( 1, HB_IT_BLOCK );
      BYTE * szSub = ( BYTE * ) hb_parc( 2 ), * szText = NULL;
      ULONG ulSub = hb_parclen( 2 ), ulLen = 0;
      BOOL fIgnoreCase = hb_parl( 3 );

      if ( ulSub )
      {
         pExpr = pExpr ? hb_vmEvalBlockOrMacro( pExpr ) : hb_param( 2, HB_IT_STRING );

         if ( pExpr )
         {
            szText = ( BYTE * ) hb_itemGetCPtr( pExpr );
            ulLen = hb_itemGetCLen( pExpr );
         }
      }
      hb_retl( ulLen && ulSub && hb_hsxStrCmp( szSub, ulSub, szText, ulLen,
                                               fIgnoreCase, 3 ) );
   }
}

/* hs_Version() ->  */
HB_FUNC( HS_VERSION )
{
   static const char szVer[] = "HiPer-SEEK / FTS library emulation";
   char * pszHBVersion, * pszVersion;

   pszHBVersion = hb_verHarbour();
   pszVersion = hb_xstrcat( NULL, szVer, ": ", pszHBVersion );
   hb_retclen_buffer( pszVersion, strlen( pszVersion ) );
   hb_xfree( pszHBVersion );
}
hsx.c425