Files
harbour-core/harbour/source/rdd/dbfntx/dbfntx1.c

2912 lines
87 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* DBFNTX RDD
*
* Copyright 1999 Bruno Cantero <bruno@issnet.net>
* www - http://www.harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version, with one exception:
*
* The exception is that if you link the Harbour Runtime Library (HRL)
* and/or the Harbour Virtual Machine (HVM) with other files to produce
* an executable, this does not by itself cause the resulting executable
* to be covered by the GNU General Public License. Your use of that
* executable is in no way restricted on account of linking the HRL
* and/or HVM code into it.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
* their web site at http://www.gnu.org/).
*
*/
#include "hbapi.h"
#include "hbinit.h"
#include "hbapiitm.h"
#include "hbvm.h"
#include "hbstack.h"
#include "rddsys.ch"
#include "hbapierr.h"
#include "hbapilng.h"
#include "hbrddntx.h"
HB_FUNC( _DBFNTX );
HB_FUNC( DBFNTX_GETFUNCTABLE );
HB_INIT_SYMBOLS_BEGIN( dbfntx1__InitSymbols )
{ "_DBFNTX", HB_FS_PUBLIC, HB_FUNCNAME( _DBFNTX ), 0 },
{ "DBFNTX_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME( DBFNTX_GETFUNCTABLE) , 0 }
HB_INIT_SYMBOLS_END( dbfntx1__InitSymbols )
#if defined(_MSC_VER)
#if _MSC_VER >= 1010
#pragma data_seg( ".CRT$XIY" )
#pragma comment( linker, "/Merge:.CRT=.data" )
#else
#pragma data_seg( "XIY" )
#endif
static HB_$INITSYM hb_vm_auto_dbfntx1__InitSymbols = dbfntx1__InitSymbols;
#pragma data_seg()
#elif ! defined(__GNUC__)
#pragma startup dbfntx1__InitSymbols
#endif
static RDDFUNCS ntxSuper = { 0 };
static USHORT maxPagesPerTag = 20;
static int maxLevel = 0;
/* Internal functions */
static LPKEYINFO hb_ntxKeyNew( LPKEYINFO pKeyFrom );
static void hb_ntxKeyFree( LPKEYINFO pKey );
static LONG hb_ntxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey );
static int hb_ntxTagFindCurrentKey( LPPAGEINFO pPage, LONG lBlock, LPKEYINFO pKey, BOOL bExact, BOOL lSeek, int level );
static USHORT hb_ntxPageFindCurrentKey( LPPAGEINFO pPage, ULONG ulRecno );
static void hb_ntxGetCurrentKey( LPTAGINFO pTag, LPKEYINFO pKey );
static BOOL hb_ntxFindNextKey( LPTAGINFO pTag );
static BOOL hb_ntxPageReadNextKey( LPTAGINFO pTag );
static BOOL hb_ntxFindPrevKey( LPTAGINFO pTag );
static BOOL hb_ntxPageReadPrevKey( LPTAGINFO pTag );
static BOOL hb_ntxPageReadTopKey( LPPAGEINFO pPage, ULONG ulOffset );
static BOOL hb_ntxPageReadBottomKey( LPPAGEINFO pPage, ULONG ulOffset );
static LPPAGEINFO hb_ntxPageFind( LPNTXINDEX pIndex ,LONG ulOffset );
static LPPAGEINFO hb_ntxPageLast( LPNTXINDEX pIndex );
static ERRCODE hb_ntxHeaderLoad( LPNTXINDEX pIndex , char * ITN );
/* Load NTX header an fill structures pIndex */
static void hb_ntxHeaderSave( LPNTXINDEX pIndex );
/* Save NTX header */
static LPNTXINDEX hb_ntxIndexNew( NTXAREAP pArea );
/* Allocate space for information about Index and find free ID */
static void hb_ntxIndexFree( LPNTXINDEX pIndex );
/* Release all resources associated with index */
static ERRCODE hb_ntxIndexCreate( LPNTXINDEX pIndex );
/* Create index from database */
static LPTAGINFO hb_ntxTagNew( LPNTXINDEX PIF, char * ITN, char *szKeyExpr,
PHB_ITEM pKeyExpr, BYTE bKeyType, USHORT uiKeyLen, USHORT uiKeyDec, char *szForExp,
PHB_ITEM pForExp, BOOL fAscendKey, BOOL fUnique );
/* Create Compound Tag with information about index */
static LPPAGEINFO hb_ntxPageNew(LPTAGINFO pParentTag );
/* Allocate space for new page */
static void hb_ntxPageRelease( LPPAGEINFO pPage );
static void hb_ntxPageFree( LPPAGEINFO pPage, BOOL lFreeChild );
/* Release memory allocated for page. If page was modified save it */
static void hb_ntxPageSave( LPPAGEINFO pPage );
/* Save page */
static LPPAGEINFO hb_ntxPageLoad( ULONG ulOffset );
/* Load page from disk */
static LPKEYINFO hb_ntxPageKeyDel( LPPAGEINFO pPage, SHORT pos, USHORT level );
/* Delete key from page */
static int hb_ntxPageKeyAdd( LPPAGEINFO pPage, PHB_ITEM pKey, int level, BOOL isFreePlace );
/* Add key to page */
static ERRCODE hb_ntxPageKeyInsert( LPPAGEINFO pPage, PHB_ITEM pKey, int pos );
/* Insert page in position pos */
static int hb_ntxItemCompare( PHB_ITEM pKey1, PHB_ITEM pKey2, BOOL Exact );
/* Compare 2 Keys (They must be keys !!! */
static ERRCODE hb_ntxPageAddPageKeyAdd( LPPAGEINFO pPage, PHB_ITEM pKey, int level, int pos );
static void backcpy( BYTE* dest, BYTE* src, long mlen )
{
long i;
for( dest = dest + mlen - 1,src = src + mlen - 1, i = 0; i < mlen; i++, dest--,src-- )
*dest = *src;
}
static char * numToStr( PHB_ITEM pItem, char* szBuffer, USHORT length, USHORT dec )
{
if( HB_IS_DOUBLE( pItem ) )
{
if( dec == 0 )
{
if( length > 9 )
sprintf( szBuffer, "%0*.0f", length,
hb_numRound( hb_itemGetND( pItem ), 0 ) );
else
sprintf( szBuffer, "%0*li", length,
( LONG ) hb_numRound( hb_itemGetND( pItem ), 0 ) );
}
else
sprintf( szBuffer, "%0*.*f", length,
dec, hb_numRound( hb_itemGetND( pItem ),
dec ) );
}
else
{
if( dec == 0 )
sprintf( szBuffer, "%0*li", length, hb_itemGetNL( pItem ) );
else
sprintf( szBuffer, "%0*.*f", length,
dec, hb_itemGetND( pItem ) );
}
szBuffer[ length ] = 0;
return szBuffer;
}
/* Implementation of internal functions */
static LPKEYINFO hb_ntxKeyNew( LPKEYINFO pKeyFrom )
{
LPKEYINFO pKey;
pKey = ( LPKEYINFO ) hb_xgrab( sizeof( KEYINFO ) );
if( pKeyFrom )
{
pKey->pItem = hb_itemNew( pKeyFrom->pItem );
pKey->Tag = pKeyFrom->Tag;
pKey->Xtra = pKeyFrom->Xtra;
}
else
{
pKey->pItem = hb_itemNew( NULL );
pKey->Tag = pKey->Xtra = 0;
}
return pKey;
}
static void hb_ntxKeyFree( LPKEYINFO pKey )
{
hb_itemRelease( pKey->pItem );
hb_xfree( pKey );
}
static LONG hb_ntxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey )
{
int K;
pTag->CurKeyInfo->Tag = 0;
pTag->TagBOF = pTag->TagEOF = FALSE;
K = hb_ntxTagFindCurrentKey( hb_ntxPageLoad( 0 ), pKey->Tag, pKey, FALSE, TRUE, 1 );
if( K == 0 )
{
if( pTag->pForItem == NULL )
{
K = pKey->Xtra;
return K;
}
else
/* TODO: test for expression */
pTag->TagEOF = TRUE;
}
else if( K < 0 )
{
if( pTag->pForItem != NULL )
/* TODO: test for expression */
pTag->TagEOF = TRUE;
}
else
pTag->TagEOF = TRUE;
return 0;
}
static int hb_ntxTagFindCurrentKey( LPPAGEINFO pPage, LONG lBlock, LPKEYINFO pKey, BOOL bExact, BOOL lSeek, int level )
{
int k = 1, kChild;
LPKEYINFO p;
LPPAGEINFO pChildPage;
if( level > maxLevel ) /* for debugging purposes only */
{
maxLevel = level;
/* printf( "\n\rLevel: %d\n\r",maxLevel ); */
}
bExact = ( bExact || pPage->TagParent->KeyType != 'C' );
pPage->CurKey = 0;
// if( pPage->uiKeys > 0 )
// {
while( k > 0 && pPage->CurKey <= pPage->uiKeys )
{
p = pPage->pKeys + pPage->CurKey;
if( pPage->CurKey == pPage->uiKeys )
{
if( !p->Tag )
break;
k = -1;
}
else
{
k = hb_ntxItemCompare( pKey->pItem, p->pItem, bExact );
/* k > 0 : pKey->pItem > p->pItem */
if( !pPage->TagParent->AscendKey )
k = -k;
if( k == 0 && lBlock == NTX_MAX_REC_NUM )
k = 1;
if( k == 0 && lBlock != NTX_IGNORE_REC_NUM )
{
if( lBlock > p->Xtra )
k = 1;
else if( lBlock < p->Xtra )
k = -1;
}
}
if( k <= 0 )
/* pKey <= p */
{
if( k == 0 && !lSeek && (ULONG)p->Xtra != pPage->TagParent->Owner->Owner->ulRecNo )
k = 1;
if( k == 0 )
{
pKey->Xtra = p->Xtra;
pPage->TagParent->CurKeyInfo->Xtra = pKey->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
}
if( p->Tag && (ULONG)p->Xtra != pPage->TagParent->Owner->Owner->ulRecNo )
{
LONG blockPrev, blockNext;
SHORT keyPrev, keyNext;
blockPrev = pPage->TagParent->blockPrev;
blockNext = pPage->TagParent->blockNext;
keyPrev = pPage->TagParent->keyPrev;
keyNext = pPage->TagParent->keyNext;
if( pPage->CurKey > 0 )
{
pPage->TagParent->blockPrev = pPage->Page;
pPage->TagParent->keyPrev = pPage->CurKey - 1;
}
if( pPage->CurKey < pPage->uiKeys )
{
pPage->TagParent->blockNext = pPage->Page;
pPage->TagParent->keyNext = pPage->CurKey;
}
pChildPage = hb_ntxPageLoad( p->Tag );
kChild = hb_ntxTagFindCurrentKey( pChildPage, lBlock, pKey, bExact, lSeek, level + 1 );
if( k != 0 || kChild == 0 )
k = kChild;
if( k > 0 )
{
pPage->TagParent->blockPrev = blockPrev;
pPage->TagParent->blockNext = blockNext;
pPage->TagParent->keyPrev = keyPrev;
pPage->TagParent->keyNext = keyNext;
}
}
else if( k == 0 && lBlock != NTX_IGNORE_REC_NUM )
{
if( lBlock > p->Tag )
k = 1;
else if( lBlock < p->Tag )
k = -1;
}
}
if( k > 0 )
pPage->CurKey++;
}
// }
hb_ntxPageRelease( pPage );
return k;
}
static USHORT hb_ntxPageFindCurrentKey( LPPAGEINFO pPage, ULONG ulRecno )
{
int i;
for( i=0; i < pPage->uiKeys; i++ )
if( (ULONG)( pPage->pKeys+i )->Xtra == ulRecno )
return ( i+1 );
return 0;
}
static void hb_ntxGetCurrentKey( LPTAGINFO pTag, LPKEYINFO pKey )
{
char szBuffer[ NTX_MAX_KEY ];
/* printf( "\n\rhb_ntxGetCurrentKey - 0: |%s|",pTag->KeyExpr ); */
if( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK )
{
hb_vmPushSymbol( &hb_symEval );
hb_vmPush( pTag->pKeyItem );
hb_vmDo( 0 );
switch( hb_itemType( &hb_stack.Return ) )
{
case HB_IT_STRING:
hb_itemCopy( pKey->pItem, &hb_stack.Return );
break;
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
hb_itemPutC( pKey->pItem, numToStr( &hb_stack.Return, szBuffer, pTag->KeyLength, pTag->KeyDec ) );
break;
case HB_IT_DATE:
hb_itemGetDS( &hb_stack.Return, szBuffer );
hb_itemPutC( pKey->pItem,szBuffer );
break;
}
}
else
{
HB_MACRO_PTR pMacro;
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem );
hb_macroRun( pMacro );
switch( hb_itemType( hb_stackItemFromTop( - 1 ) ) )
{
case HB_IT_STRING:
hb_itemCopy( pKey->pItem, hb_stackItemFromTop( - 1 ) );
break;
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
hb_itemPutC( pKey->pItem, numToStr( hb_stackItemFromTop( - 1 ), szBuffer, pTag->KeyLength, pTag->KeyDec ) );
break;
case HB_IT_DATE:
hb_itemGetDS( hb_stackItemFromTop( - 1 ), szBuffer );
hb_itemPutC( pKey->pItem,szBuffer );
break;
}
hb_stackPop();
}
/* printf( "\n\rhb_ntxGetCurrentKey - 3: |%s|",(pKey->pItem)->item.asString.value ); */
pKey->Tag = 0;
pKey->Xtra = 0;
}
static BOOL hb_ntxFindNextKey( LPTAGINFO pTag )
{
int seekRes;
LPKEYINFO pKey;
LPPAGEINFO pPage;
pKey = hb_ntxKeyNew( NULL );
hb_ntxGetCurrentKey( pTag,pKey );
pKey->Tag = NTX_IGNORE_REC_NUM;
pTag->blockNext = 0; pTag->keyNext = 0;
seekRes = hb_ntxTagFindCurrentKey( hb_ntxPageLoad( 0 ), pKey->Tag, pKey, FALSE, FALSE, 1 );
hb_ntxKeyFree( pKey );
if( seekRes )
printf( "\n\rhb_ntxFindNextKey: Cannot find current key:" );
else
{
/* printf( "\n\rhb_ntxFindNextKey - 1" ); */
pPage = hb_ntxPageLoad( pTag->CurKeyInfo->Tag );
pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->Owner->Owner->ulRecNo );
if( pPage->CurKey < pPage->uiKeys )
{
/* printf( "\n\rhb_ntxFindNextKey - 2" ); */
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
/* printf( "\n\rhb_ntxFindNextKey - 3 : %ld",blockNext ); */
if( pTag->blockNext )
{
pPage = hb_ntxPageLoad( pTag->blockNext );
pPage->CurKey = pTag->keyNext;
/* printf( "\n\rhb_ntxFindNextKey - 4 ( %d %d %ld)",pPage->CurKey, pPage->uiKeys,pTag->CurKeyInfo->Xtra ); */
if( pPage->CurKey < pPage->uiKeys )
{
/*
while( ( pPage->pKeys+pPage->CurKey )->Tag )
{
pChildPage = hb_ntxPageLoad( ( pPage->pKeys+pPage->CurKey )->Tag );
hb_ntxPageRelease( pPage );
pPage = pChildPage;
pPage->CurKey = 0;
}
*/
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
return FALSE;
}
}
else
return FALSE;
}
}
return FALSE;
}
static BOOL hb_ntxPageReadNextKey( LPTAGINFO pTag )
{
LPPAGEINFO pPage, pChildPage;
if( pTag->CurKeyInfo->Tag )
{
pPage = hb_ntxPageLoad( pTag->CurKeyInfo->Tag );
pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra );
if( pPage->CurKey )
{
if( pPage->CurKey < pPage->uiKeys ||
( pPage->CurKey == pPage->uiKeys && ( pPage->pKeys+pPage->CurKey )->Tag ) )
{
while( ( pPage->pKeys+pPage->CurKey )->Tag )
{
pChildPage = hb_ntxPageLoad( ( pPage->pKeys+pPage->CurKey )->Tag );
hb_ntxPageRelease( pPage );
pPage = pChildPage;
pPage->CurKey = 0;
}
hb_itemCopy( pPage->TagParent->CurKeyInfo->pItem, ( pPage->pKeys+pPage->CurKey )->pItem );
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
return hb_ntxFindNextKey( pTag );
}
}
else
{
hb_ntxPageRelease( pPage );
return hb_ntxFindNextKey( pTag );
}
}
else
return hb_ntxFindNextKey( pTag );
}
static BOOL hb_ntxFindPrevKey( LPTAGINFO pTag )
{
int seekRes;
LPKEYINFO pKey;
LPPAGEINFO pPage, pChildPage;
pKey = hb_ntxKeyNew( NULL );
hb_ntxGetCurrentKey( pTag, pKey );
pKey->Tag = NTX_IGNORE_REC_NUM;
pTag->blockPrev = 0; pTag->keyPrev = 0;
seekRes = hb_ntxTagFindCurrentKey( hb_ntxPageLoad( 0 ), pKey->Tag, pKey, FALSE, FALSE, 1 );
hb_ntxKeyFree( pKey );
if( seekRes )
printf( "\n\rhb_ntxFindPrevKey: Cannot find current key: |%ld %s|",pTag->Owner->Owner->ulRecNo,pKey->pItem->item.asString.value );
else
{
/* printf( "\n\rhb_ntxFindPrevKey - 1" ); */
pPage = hb_ntxPageLoad( pTag->CurKeyInfo->Tag );
pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->Owner->Owner->ulRecNo );
pPage->CurKey--;
if( ( pPage->pKeys+pPage->CurKey )->Tag )
{
do
{
pChildPage = hb_ntxPageLoad( ( pPage->pKeys+pPage->CurKey )->Tag );
hb_ntxPageRelease( pPage );
pPage = pChildPage;
pPage->CurKey = pPage->uiKeys;
}
while( ( pPage->pKeys+pPage->CurKey )->Tag );
pPage->CurKey--;
}
else
pPage->CurKey--;
if( pPage->CurKey >= 0 )
{
/* printf( "\n\rhb_ntxFindPrevKey - 2" ); */
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
/* printf( "\n\rhb_ntxFindPrevKey - 3 : %ld",blockPrev ); */
if( pTag->blockPrev )
{
pPage = hb_ntxPageLoad( pTag->blockPrev );
pPage->CurKey = pTag->keyPrev;
/* printf( "\n\rhb_ntxFindPrevKey - 4 ( %d %d %ld)",pPage->CurKey, pPage->uiKeys,pTag->CurKeyInfo->Xtra ); */
if( pPage->CurKey < pPage->uiKeys )
{
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
return FALSE;
}
}
else
return FALSE;
}
}
return FALSE;
}
static BOOL hb_ntxPageReadPrevKey( LPTAGINFO pTag )
{
LPPAGEINFO pPage, pChildPage;
if( pTag->CurKeyInfo->Tag )
{
pPage = hb_ntxPageLoad( pTag->CurKeyInfo->Tag );
pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra );
if( pPage->CurKey )
{
pPage->CurKey--;
if( ( pPage->pKeys+pPage->CurKey )->Tag )
{
do
{
pChildPage = hb_ntxPageLoad( ( pPage->pKeys+pPage->CurKey )->Tag );
hb_ntxPageRelease( pPage );
pPage = pChildPage;
pPage->CurKey = pPage->uiKeys;
}
while( ( pPage->pKeys+pPage->CurKey )->Tag );
pPage->CurKey--;
}
else
pPage->CurKey--;
if( pPage->CurKey >= 0 )
{
pPage->TagParent->CurKeyInfo->Xtra = ( pPage->pKeys+pPage->CurKey )->Xtra;
pPage->TagParent->CurKeyInfo->Tag = pPage->Page;
hb_ntxPageRelease( pPage );
return TRUE;
}
else
{
hb_ntxPageRelease( pPage );
return hb_ntxFindPrevKey( pTag );
}
}
else
{
hb_ntxPageRelease( pPage );
return hb_ntxFindPrevKey( pTag );
}
}
else
return hb_ntxFindPrevKey( pTag );
}
static BOOL hb_ntxPageReadTopKey( LPPAGEINFO pPage, ULONG ulOffset )
{
LPPAGEINFO pChildPage;
LPKEYINFO pKey;
pChildPage = hb_ntxPageLoad( ulOffset );
if( pPage )
{
hb_ntxPageRelease( pPage );
}
if( pChildPage != NULL )
{
pKey = pChildPage->pKeys;
ulOffset = pKey->Tag;
if( ulOffset )
{
return hb_ntxPageReadTopKey( pChildPage,ulOffset );
}
else
{
hb_itemCopy( pChildPage->TagParent->CurKeyInfo->pItem, pKey->pItem );
pChildPage->TagParent->CurKeyInfo->Xtra = pKey->Xtra;
pChildPage->TagParent->CurKeyInfo->Tag = pChildPage->Page;
hb_ntxPageRelease( pChildPage );
return TRUE;
}
}
else
return FALSE;
}
static BOOL hb_ntxPageReadBottomKey( LPPAGEINFO pPage, ULONG ulOffset )
{
LPPAGEINFO pChildPage;
LPKEYINFO pKey;
pChildPage = hb_ntxPageLoad( ulOffset );
if( pPage )
hb_ntxPageRelease( pPage );
if( pChildPage != NULL )
{
pKey = pChildPage->pKeys + pChildPage->uiKeys;
ulOffset = pKey->Tag;
if( ulOffset )
return hb_ntxPageReadBottomKey( pChildPage,ulOffset );
else
{
pKey -= 1;
hb_itemCopy( pChildPage->TagParent->CurKeyInfo->pItem, pKey->pItem );
pChildPage->TagParent->CurKeyInfo->Xtra = pKey->Xtra;
pChildPage->TagParent->CurKeyInfo->Tag = pChildPage->Page;
hb_ntxPageRelease( pChildPage );
return TRUE;
}
}
else
return FALSE;
}
static void hb_ntxTagKeyRead( LPTAGINFO pTag, BYTE bTypRead )
{
if( !pTag->AscendKey )
{
switch( bTypRead )
{
case TOP_RECORD:
bTypRead = BTTM_RECORD;
break;
case BTTM_RECORD:
bTypRead = TOP_RECORD;
break;
case NEXT_RECORD:
bTypRead = PREV_RECORD;
break;
case PREV_RECORD:
bTypRead = NEXT_RECORD;
break;
}
}
pTag->TagBOF = pTag->TagEOF = FALSE;
if( pTag->Owner->Owner->fShared )
while( !hb_fsLock( pTag->Owner->DiskFile, 0, 512, FL_LOCK ) );
switch( bTypRead )
{
case TOP_RECORD:
if( pTag->pForItem != NULL )
printf( "hb_ntxTagKeyRead()" );
else
pTag->TagBOF = !hb_ntxPageReadTopKey( NULL,0 );
if( pTag->pForItem != NULL )
printf( "hb_ntxTagTestRange()" );
if( pTag->TagEOF )
pTag->TagBOF = TRUE;
pTag->TagEOF = pTag->TagBOF;
break;
case BTTM_RECORD:
if( pTag->pForItem != NULL )
printf( "hb_ntxTagKeyRead()" );
else
pTag->TagEOF = !hb_ntxPageReadBottomKey( NULL,0 );
if( pTag->pForItem != NULL )
printf( "hb_ntxTagTestRange()" );
if( pTag->TagBOF )
pTag->TagEOF = TRUE;
pTag->TagBOF = pTag->TagEOF;
break;
case NEXT_RECORD:
while( TRUE )
{
pTag->TagEOF = !hb_ntxPageReadNextKey( pTag );
if( pTag->pForItem != NULL )
printf( "hb_ntxTagKeyRead()" );
else
break;
}
break;
case PREV_RECORD:
while( TRUE )
{
pTag->TagBOF = !hb_ntxPageReadPrevKey( pTag );
if( pTag->pForItem != NULL )
printf( "hb_ntxTagKeyRead()" );
else
break;
}
break;
}
if( pTag->Owner->Owner->fShared )
{
hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
hb_fsLock( pTag->Owner->DiskFile, 0, 512, FL_UNLOCK );
}
if( pTag->TagBOF || pTag->TagEOF )
{
if( !pTag->AscendKey )
{
pTag->CurKeyInfo->Xtra = pTag->TagEOF;
pTag->TagEOF = pTag->TagBOF;
pTag->TagBOF = ( BOOL ) pTag->CurKeyInfo->Xtra;
}
pTag->CurKeyInfo->Xtra = 0;
}
}
static int hb_ntxItemCompare( PHB_ITEM pKey1, PHB_ITEM pKey2, BOOL Exact )
{
int iLimit, iResult, i;
if( pKey2 == NULL || pKey2->item.asString.length == 0 )
return 1;
if( pKey1 == NULL || pKey1->item.asString.length == 0 )
return ( pKey2->item.asString.length == 0 ) ? 0 : -1;
switch( hb_itemType( pKey1 ) )
{
case HB_IT_STRING:
iLimit = ( pKey1->item.asString.length >
pKey2->item.asString.length ) ?
pKey2->item.asString.length : pKey1->item.asString.length;
if( ( iResult = memcmp( pKey1->item.asString.value,
pKey2->item.asString.value, iLimit ) ) != 0 )
break;
else
{
if( ( iResult = pKey1->item.asString.length -
pKey2->item.asString.length ) != 0 )
{
if( iResult > 0 )
{
i = pKey1->item.asString.length;
while( i > iLimit &&
pKey1->item.asString.value[ i - 1 ] == ' ' )
i--;
}
else
{
i = pKey2->item.asString.length;
while( i > iLimit &&
pKey2->item.asString.value[ i - 1 ] == ' ' )
i--;
}
if( i == iLimit )
iResult = 0;
}
}
if( iResult < 0 && !Exact )
iResult = 0;
break;
/*
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
iResult = hb_itemGetND( pKey1 ) - hb_itemGetND( pKey2 );
break;
case HB_IT_DATE:
iResult = hb_itemGetDL( pKey1 ) - hb_itemGetDL( pKey2 );
break;
*/
default:
iResult = 0;
printf( "hb_ntxKeyCompare()" );
}
if( iResult < 0 )
return -1;
else if( iResult > 0 )
return 1;
else
return 0;
}
static void hb_ntxPageSave( LPPAGEINFO pPage )
{
char buffer[NTXBLOCKSIZE+1];
int i;
LPNTXBUFFER itemlist;
LPNTXITEM item;
LPKEYINFO pKey;
memset( buffer, 0, NTXBLOCKSIZE+1 );
pKey = pPage->pKeys;
itemlist = ( LPNTXBUFFER ) buffer;
itemlist->item_count = pPage->uiKeys;
for( i = 0; i < pPage->uiKeys; i++ )
{
itemlist->item_offset[i] = 2 + 2 * ( pPage->TagParent->MaxKeys + 1 ) +
i * ( pPage->TagParent->KeyLength + 8 );
item=(NTXITEM *)(buffer+itemlist->item_offset[i]);
item->page = pKey[i].Tag;
item->rec_no = pKey[i].Xtra;
strcpy(item->key, pKey[i].pItem->item.asString.value);
}
itemlist->item_offset[i] = 2 + 2 * ( pPage->TagParent->MaxKeys + 1 ) +
i * ( pPage->TagParent->KeyLength + 8 );
item=(NTXITEM *)(buffer+itemlist->item_offset[i]);
item->page = pKey[i].Tag;
i++;
for( ; i < pPage->TagParent->MaxKeys + 1; i++ )
itemlist->item_offset[i] = 2 + 2 * ( pPage->TagParent->MaxKeys + 1 ) +
i * ( pPage->TagParent->KeyLength + 8 );
hb_fsSeek( pPage->TagParent->Owner->DiskFile, pPage->Page, FS_SET );
hb_fsWrite( pPage->TagParent->Owner->DiskFile, (BYTE *) buffer, NTXBLOCKSIZE );
pPage->Changed = FALSE;
}
static LPPAGEINFO hb_ntxPageLoad( ULONG ulOffset )
{
char buffer[NTXBLOCKSIZE];
int i;
NTXAREAP pArea;
LPNTXINDEX pIndex;
LPNTXBUFFER itemlist;
LPNTXITEM item;
LPPAGEINFO pPage;
BOOL bReplace = FALSE;
USHORT uiKeysBefore;
pArea = (NTXAREAP) hb_rddGetCurrentWorkAreaPointer();
pIndex = pArea->lpCurIndex;
pPage = hb_ntxPageFind( pIndex, (ulOffset)? ulOffset:pIndex->CompoundTag->RootBlock );
if( pPage )
{
pPage->lBusy = TRUE;
return pPage;
}
if( pIndex->CompoundTag->uiPages > maxPagesPerTag )
{
pPage = pIndex->CompoundTag->RootPage;
while( pPage )
{
if( !pPage->lBusy )
break;
pPage = pPage->pNext;
}
if( pPage )
bReplace = TRUE;
}
hb_fsSeek( pIndex->DiskFile, ( ulOffset )? ulOffset:pIndex->CompoundTag->RootBlock, FS_SET );
if( hb_fsRead( pIndex->DiskFile, ( BYTE * ) buffer, NTXBLOCKSIZE )
!= NTXBLOCKSIZE )
return NULL;
if( !bReplace )
{
LPPAGEINFO pLastPage;
pPage = ( LPPAGEINFO ) hb_xgrab( sizeof( HB_PAGEINFO ) );
memset( pPage , 0 ,sizeof( HB_PAGEINFO ) );
pPage->TagParent = pIndex->CompoundTag;
pPage->Page = ( ulOffset )? ulOffset:pIndex->CompoundTag->RootBlock;
pLastPage = hb_ntxPageLast( pIndex );
pPage->pPrev = pLastPage;
if( pLastPage )
pLastPage->pNext = pPage;
else
pIndex->CompoundTag->RootPage = pPage;
pPage->pKeys = ( LPKEYINFO ) hb_xgrab( sizeof( KEYINFO ) * ( pPage->TagParent->MaxKeys + 1 ) );
memset( pPage->pKeys, 0, sizeof( KEYINFO ) * ( pPage->TagParent->MaxKeys + 1 ) );
pPage->pNext = NULL;
pPage->TagParent->uiPages ++;
}
else
pPage->Page = ( !ulOffset )? pIndex->CompoundTag->RootBlock:ulOffset;
pPage->CurKey = -1;
pPage->lBusy = TRUE;
itemlist = ( LPNTXBUFFER ) buffer;
if( bReplace )
{
uiKeysBefore = pPage->uiKeys;
for( i = itemlist->item_count; i< pPage->uiKeys; i++)
hb_itemRelease( pPage->pKeys[i].pItem );
}
pPage->uiKeys = itemlist->item_count ;
for( i = 0; i < itemlist->item_count; i++ )
{
item=(NTXITEM *)(buffer+itemlist->item_offset[i]);
pPage->pKeys[i].Xtra = item->rec_no;
pPage->pKeys[i].Tag = item->page;
if( !bReplace || i >= uiKeysBefore )
pPage->pKeys[i].pItem = hb_itemNew( NULL );
hb_itemPutCL( pPage->pKeys[i].pItem, item->key, pPage->TagParent->KeyLength );
}
item=(NTXITEM *)(buffer+itemlist->item_offset[i]);
pPage->pKeys[i].Tag = item->page;
return pPage;
}
static void hb_ntxPageRelease( LPPAGEINFO pPage )
{
pPage->lBusy = FALSE;
if( pPage->Changed )
hb_ntxPageSave( pPage );
if( pPage->NewRoot )
{
pPage->TagParent->RootBlock = pPage->Page;
hb_ntxHeaderSave( pPage->TagParent->Owner );
}
}
static void hb_ntxPageFree( LPPAGEINFO pPage, BOOL lFreeChild )
{
int i;
/* printf( "\n ntxPageFree - 0 ( %5lx %5lx )",pPage,pPage->pNext ); */
if( lFreeChild && pPage->pNext )
{
hb_ntxPageFree( pPage->pNext,TRUE );
}
if( pPage->Changed )
hb_ntxPageSave( pPage );
if( pPage->NewRoot )
{
pPage->TagParent->RootBlock = pPage->Page;
hb_ntxHeaderSave( pPage->TagParent->Owner );
}
if( lFreeChild )
{
if( pPage->pPrev )
pPage->pPrev->pNext = NULL;
pPage->pNext = NULL;
}
else
{
if( pPage->pPrev )
{
pPage->pPrev->pNext = pPage->pNext;
if( pPage->pNext )
pPage->pNext->pPrev = pPage->pPrev;
}
else
{
pPage->TagParent->RootPage = pPage->pNext;
if( pPage->pNext )
pPage->pNext->pPrev = NULL;
}
pPage->pNext = NULL;
}
if( pPage->pKeys )
{
for( i = 0; i< pPage->uiKeys; i++)
hb_itemRelease( pPage->pKeys[i].pItem );
pPage->TagParent->uiPages --;
hb_xfree( pPage->pKeys );
pPage->pKeys = NULL;
hb_xfree( pPage );
}
}
static LPPAGEINFO hb_ntxPageNew(LPTAGINFO pParentTag )
{
LPPAGEINFO pPage, pLastPage;
if( pParentTag->Owner->NextAvail > 0 )
{
/* Handling of a pool of empty pages.
Some sources says that this address is in the first 4 bytes of
a page ( http://www.e-bachmann.dk/docs/xbase.htm ).
But as I understood, studying dumps of Clipper ntx'es, address of the
next available page is in the address field of a first key item
in the page - it is done here now in such a way.
= Alexander Kresin =
*/
pPage = hb_ntxPageLoad( pParentTag->Owner->NextAvail );
pPage->Page = pParentTag->Owner->NextAvail;
pParentTag->Owner->NextAvail = pPage->pKeys->Tag;
hb_ntxHeaderSave( pParentTag->Owner );
}
else
{
BOOL bReplace = FALSE;
if( pParentTag->uiPages > maxPagesPerTag )
{
pPage = pParentTag->RootPage;
while( pPage )
{
if( !pPage->lBusy )
break;
pPage = pPage->pNext;
}
if( pPage )
bReplace = TRUE;
}
if( bReplace )
{
int i;
for( i = 0; i< pPage->uiKeys; i++)
hb_itemRelease( pPage->pKeys[i].pItem );
pPage->uiKeys = 0;
}
else
{
pPage = ( LPPAGEINFO ) hb_xgrab( sizeof( HB_PAGEINFO ) );
memset( pPage, 0, sizeof( HB_PAGEINFO ) );
pPage->TagParent = pParentTag;
pLastPage = hb_ntxPageLast( pParentTag->Owner );
if( pLastPage )
{
pPage->pPrev = pLastPage;
pLastPage->pNext = pPage;
}
else
{
pPage->pPrev = NULL;
pParentTag->RootPage = pPage;
}
pParentTag->uiPages ++;
pPage->pKeys = ( LPKEYINFO ) hb_xgrab( sizeof( KEYINFO ) * ( pParentTag->MaxKeys + 1 ) );
}
memset( pPage->pKeys, 0, sizeof( KEYINFO ) * ( pParentTag->MaxKeys + 1 ) );
pParentTag->TagBlock += 1024;
pPage->Page = pParentTag->TagBlock;
pPage->CurKey = -1;
pPage->lBusy = TRUE;
}
return pPage;
}
static ERRCODE hb_ntxPageAddPageKeyAdd( LPPAGEINFO pPage, PHB_ITEM pKey, int level, int pos )
{
int nBegin, nEnd;
int nNewPos;
int MaxKeys = pPage->TagParent->MaxKeys;
int nCount, nMaxCount = MaxKeys / 5;
LPPAGEINFO pNewPage;
/*
int i;
for( i = 0; i < pPage->uiKeys; i++ )
printf( "\n --- ( %d %5lx %s )", i,pPage->pKeys[i].Tag,hb_itemGetCPtr( pPage->pKeys[i].pItem ) );
*/
/* printf( "\nntxPageAddPageKeyAdd - 0 ( %d )",level ); */
pNewPage = hb_ntxPageNew( pPage->TagParent );
if( pNewPage == NULL )
return FAILURE;
if( pos > pPage->TagParent->MaxKeys )
{
/* printf( "\nntxPageAddPageKeyAdd - 1( %s %d )", hb_itemGetCPtr( pKey ),pPage->uiKeys ); */
nBegin = pPage->uiKeys - 1;
while( ( nBegin > 0 ) && ( pPage->pKeys[ nBegin ].Tag == 0 ) )
nBegin--;
if( nBegin < pPage->uiKeys - 1 )
{
nBegin ++;
nNewPos = pPage->uiKeys - nBegin;
memmove( pNewPage->pKeys, pPage->pKeys + nBegin, nNewPos * sizeof( KEYINFO ));
pNewPage->uiKeys = nNewPos;
pNewPage->pKeys[nNewPos+1].Tag = 0;
pPage->pKeys[nBegin].Tag = pNewPage->Page;
pPage->pKeys[nBegin].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pPage->pKeys[nBegin].pItem = hb_itemNew( pKey );
pPage->uiKeys -= nNewPos-1;
pPage->pKeys[nBegin+1].Tag = 0;
}
else
{
pNewPage->pKeys[0].Tag = 0;
pNewPage->pKeys[0].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pNewPage->pKeys[0].pItem = hb_itemNew( pKey );
pNewPage->pKeys[1].Tag = 0;
pNewPage->uiKeys = 1;
pPage->pKeys[pPage->uiKeys].Tag = pNewPage->Page;
}
/*
nEnd = pPage->uiKeys/2;
while( ( nEnd < pPage->uiKeys ) && ( pPage->pKeys[ nEnd ].Tag != 0 ) )
nEnd++;
if( nEnd == pPage->uiKeys )
{
memmove( pNewPage->pKeys , pPage->pKeys,
( pPage->uiKeys + 1 ) * sizeof( KEYINFO ) );
pNewPage->uiKeys = pPage->uiKeys;
pPage->uiKeys = 1;
pPage->pKeys[0].Tag = pNewPage->Page;
pPage->pKeys[0].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pPage->pKeys[0].pItem = hb_itemNew( pKey );
}
else
{
memmove( pNewPage->pKeys , pPage->pKeys,
( nEnd ) * sizeof( KEYINFO ) );
pNewPage->uiKeys = nEnd;
memmove( pPage->pKeys , pPage->pKeys+nEnd,
( pPage->uiKeys+1-nEnd ) * sizeof( KEYINFO ) );
pPage->uiKeys = pPage->uiKeys - nEnd;
pPage->pKeys[0].Tag = pNewPage->Page;
pPage->pKeys[pPage->uiKeys].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pPage->pKeys[pPage->uiKeys].pItem = hb_itemNew( pKey );
pPage->uiKeys ++;
}
pPage->pKeys[pPage->uiKeys].Tag = 0;
*/
/* printf( "\nntxPageAddPageKeyAdd - 2( %s %d )", hb_itemGetCPtr( pKey ),pPage->uiKeys ); */
}
else
{
nBegin = pos;
nCount = 0;
while( ( nCount < nMaxCount ) && ( nBegin > 0 ) && ( pPage->pKeys[ nBegin - 1 ].Tag == 0 ) )
{
nBegin--;
nCount++;
}
nEnd = pos;
while( ( nCount < nMaxCount ) && ( nEnd < pPage->uiKeys - 1 ) && ( pPage->pKeys[ nEnd + 1 ].Tag == 0 ) )
{
nEnd++;
nCount++;
}
nNewPos = pos - nBegin ;
if( nNewPos > 0 )
memmove( pNewPage->pKeys, pPage->pKeys + nBegin, nNewPos * sizeof( KEYINFO ));
pNewPage->pKeys[nNewPos].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pNewPage->pKeys[nNewPos].pItem = hb_itemNew( pKey );
/* printf( "\nntxPageAddPageKeyAdd - 1( %s %d %d ) %d %d %d %d", hb_itemGetCPtr( pKey ),level,pos,nBegin,nNewPos,nEnd,pPage->uiKeys ); */
if( nEnd > pos )
memmove( pNewPage->pKeys + nNewPos + 1, pPage->pKeys + pos, ( nEnd - pos ) * sizeof( KEYINFO ));
pPage->pKeys[nEnd].Tag = pNewPage->Page;
memmove( pPage->pKeys + nBegin , pPage->pKeys + nEnd,
( pPage->uiKeys - nEnd + 1) * sizeof( KEYINFO ) );
pPage->uiKeys -= nCount;
pNewPage->uiKeys = nCount + 1;
}
pPage->Changed = TRUE;
pNewPage->Changed = TRUE;
hb_ntxPageRelease( pNewPage );
HB_SYMBOL_UNUSED( level );
return SUCCESS;
}
static ERRCODE hb_ntxPageKeyInsert( LPPAGEINFO pPage, PHB_ITEM pKey, int pos )
{
/* printf( "\nntxPageKeyInsert ( %d %s )", pos,hb_itemGetCPtr( pKey ) ); */
backcpy( (BYTE*)(pPage->pKeys + pos + 1) , (BYTE*)(pPage->pKeys + pos) ,
( pPage->uiKeys - pos + 1 ) * sizeof( KEYINFO ) );
pPage->uiKeys++;
pPage->Changed = TRUE;
pPage->pKeys[pos].Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pPage->pKeys[pos].pItem = hb_itemNew( pKey );
pPage->pKeys[pos].Tag = 0;
return SUCCESS;
}
static LPKEYINFO hb_ntxPageKeyDel( LPPAGEINFO pPage, SHORT pos, USHORT level )
{
LPKEYINFO pKey = NULL;
if( pPage->pKeys[pos].Tag )
{
LPPAGEINFO pPageChild = hb_ntxPageLoad( pPage->pKeys[pos].Tag );
LPKEYINFO pKeyNew = NULL;
pKey = hb_ntxPageKeyDel( pPageChild, pPageChild->uiKeys - 1, level + 1 );
hb_ntxPageRelease( pPageChild );
if( level > 1 )
{
pKeyNew = hb_ntxKeyNew( &(pPage->pKeys[pos]) );
pKeyNew->Tag = pPage->Page;
}
hb_itemCopy( pPage->pKeys[pos].pItem, pKey->pItem );
pPage->pKeys[pos].Tag = pKey->Tag;
pPage->pKeys[pos].Xtra = pKey->Xtra;
pPage->Changed = TRUE;
hb_ntxKeyFree( pKey );
return pKeyNew;
}
else
{
if( level > 1 )
{
pKey = hb_ntxKeyNew( &(pPage->pKeys[pos]) );
pKey->Tag = pPage->Page;
}
hb_itemRelease( pPage->pKeys[pos].pItem );
memmove( pPage->pKeys + pos , pPage->pKeys + pos + 1,
( pPage->uiKeys - pos + 1) * sizeof( KEYINFO ) );
pPage->uiKeys--;
pPage->Changed = TRUE;
if( !pPage->uiKeys )
{
pPage->pKeys->Tag = pPage->TagParent->Owner->NextAvail;
pPage->TagParent->Owner->NextAvail = pPage->Page;
hb_ntxHeaderSave( pPage->TagParent->Owner );
}
return pKey;
}
}
static int hb_ntxPageKeyAdd( LPPAGEINFO pPage, PHB_ITEM pKey, int level, BOOL isFreePlace )
{
int i = -1, cmp = -1, nBegin;
LONG Tag;
LPPAGEINFO pLoadedPage;
/* printf( "\nntxPageKeyAdd - 0 ( %d / %d )",level,pPage->TagParent->uiPages ); */
if( pPage->uiKeys == 0 )
{
pPage->uiKeys=1;
pPage->Changed = TRUE;
pPage->pKeys->Xtra = pPage->TagParent->Owner->Owner->ulRecNo;
pPage->pKeys->pItem = hb_itemNew( pKey );
return 1;
}
if( pPage->uiKeys > 3 )
{
nBegin = pPage->uiKeys / 2;
cmp = hb_ntxItemCompare( pPage->pKeys[ nBegin ].pItem , pKey, TRUE );
if( cmp > 0 )
cmp = -1;
else
i = nBegin;
}
while( TRUE )
{
if( cmp > 0 )
{
if( pPage->uiKeys == pPage->TagParent->MaxKeys && pPage->pKeys[i].Tag == 0 )
{
hb_ntxPageAddPageKeyAdd(pPage, pKey, level, i );
}
else if( pPage->pKeys[i].Tag != 0 )
{
pLoadedPage = hb_ntxPageLoad( pPage->pKeys[i].Tag );
if( pLoadedPage == NULL )
{
/* TODO : Error recovery ??? */
return -1;
}
if( hb_ntxPageKeyAdd( pLoadedPage, pKey, level+1,
pPage->uiKeys < pPage->TagParent->MaxKeys ) == 0 )
{
Tag = pPage->pKeys[i].Tag;
pPage->pKeys[i].Tag = 0;
hb_ntxPageKeyInsert( pPage, pKey, i );
pPage->pKeys[i].Tag = Tag;
}
hb_ntxPageRelease( pLoadedPage );
}
else
{
hb_ntxPageKeyInsert( pPage, pKey, i );
}
return 1;
}
i++;
if( i == pPage->uiKeys )
break;
cmp = hb_ntxItemCompare( pPage->pKeys[ i ].pItem , pKey, TRUE );
}
/* printf( "\nntxPageKeyAdd - 1" ); */
if( pPage->pKeys[i].Tag != 0 )
{
pLoadedPage = hb_ntxPageLoad( pPage->pKeys[i].Tag );
if( pLoadedPage == NULL )
{
/* TODO : Error recovery ??? */
return -1;
}
if( hb_ntxPageKeyAdd( pLoadedPage, pKey, level+1,
pPage->uiKeys < pPage->TagParent->MaxKeys ) == 0 )
{
Tag = pPage->pKeys[i].Tag;
pPage->pKeys[i].Tag = 0;
hb_ntxPageKeyInsert( pPage, pKey, i );
pPage->pKeys[i].Tag = Tag;
}
hb_ntxPageRelease( pLoadedPage );
}
else if( pPage->uiKeys == pPage->TagParent->MaxKeys )
{
if( isFreePlace )
return 0;
else
hb_ntxPageAddPageKeyAdd( pPage, pKey, level, pPage->uiKeys+1 );
}
else
{
hb_ntxPageKeyInsert( pPage, pKey, i );
}
return 1;
}
/*
static ERRCODE hb_ntxTagKeyAdd( LPTAGINFO pTag, PHB_ITEM pKey)
{
LPPAGEINFO pPage;
if( pTag->RootPage )
{
return hb_ntxPageKeyAdd( pTag->RootPage, pKey, 0, FALSE );
}
else
{
pPage = hb_ntxPageNew( pTag );
pPage->Changed = TRUE;
pPage->NewRoot = TRUE;
pPage->uiKeys = 1;
pPage->pKeys[0].Xtra = pTag->Owner->Owner->ulRecNo;
pPage->pKeys[0].pItem = hb_itemNew( pKey );
pTag->RootPage = pPage;
}
return SUCCESS;
}
*/
/*
typedef struct _SORTITEM
{
ULONG rec_no;
char key[ 1 ];
} SORTITEM;
*/
struct _SORTITEM;
typedef struct _SORTITEM
{
struct _SORTITEM * pNext;
ULONG rec_no;
char key[ 1 ];
} SORTITEM;
typedef SORTITEM * LPSORTITEM;
typedef struct _NTXSORTINFO
{
ULONG Tag;
USHORT itemLength;
USHORT nItems;
BYTE * sortBuffer;
LPSORTITEM pKeyFirst;
LPSORTITEM pKey1;
LPSORTITEM pKey2;
char** pageBuffers;
} NTXSORTINFO;
typedef NTXSORTINFO * LPNTXSORTINFO;
static void hb_ntxSortKeyAdd( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, char* szkey )
{
LPSORTITEM pKeyNew, pKey, pKeyTmp, pKeyLast = NULL, pKeyPrev;
/*
LPSORTITEM* aKeys = (LPSORTITEM*) sortBuffer;
pKeyNew = (LPSORTITEM) ( sortBuffer +
sizeof( LPSORTITEM ) * pTag->Owner->Owner->ulRecCount +
( sizeof( ULONG ) + pTag->KeyLength ) * ( pTag->Owner->Owner->ulRecNo - 1 ) );
aKeys[ pTag->Owner->Owner->ulRecNo - 1 ] = pKeyNew;
*/
/* printf( "\n\rhb_ntxSortKeyAdd - 0 ( %s )",szkey ); */
pKeyNew = (LPSORTITEM) ( pSortInfo->sortBuffer +
pSortInfo->itemLength * ( pTag->Owner->Owner->ulRecNo - 1 ) );
pKeyNew->rec_no = pTag->Owner->Owner->ulRecNo;
pKeyNew->pNext = NULL;
memcpy( pKeyNew->key, szkey, pTag->KeyLength );
if( ++(pSortInfo->nItems) < 2 && pKeyNew->rec_no < pTag->Owner->Owner->ulRecCount )
return;
if( pSortInfo->nItems == 2 )
{
pKeyTmp = (LPSORTITEM) ( pSortInfo->sortBuffer +
pSortInfo->itemLength * ( pTag->Owner->Owner->ulRecNo - 2 ) );
if( memcmp( pKeyNew->key, pKeyTmp->key, pTag->KeyLength ) < 0 )
pKeyNew->pNext = pKeyTmp;
else
{
pKeyTmp->pNext = pKeyNew;
pKeyNew = pKeyTmp;
}
}
if( pTag->Owner->Owner->ulRecNo < 3 )
{
pSortInfo->pKeyFirst = pKeyNew;
pSortInfo->nItems = 0;
return;
}
while( pSortInfo->nItems )
{
pKeyPrev = NULL;
pKeyTmp = pKeyNew->pNext;
pKeyNew->pNext = NULL;
if( pKeyLast )
{
pKeyPrev = pKeyLast;
pKey = pKeyLast->pNext;
}
else if( pSortInfo->pKey1 &&
( memcmp( pKeyNew->key, pSortInfo->pKey1->key, pTag->KeyLength ) >= 0 ) )
{
pKeyPrev = pSortInfo->pKey1;
pKey = pSortInfo->pKey1->pNext;
}
else
pKey = pSortInfo->pKeyFirst;
while( pKey )
{
if( memcmp( pKeyNew->key, pKey->key, pTag->KeyLength ) < 0 )
{
pKeyNew->pNext = pKey;
if( pKeyPrev )
{
pKeyPrev->pNext = pKeyNew;
pSortInfo->pKey1 = pKeyNew;
}
else
pSortInfo->pKeyFirst = pKeyNew;
break;
}
pKeyPrev = pKey;
pKey = pKey->pNext;
}
if( !pKey )
{
pKeyPrev->pNext = pKeyNew;
pSortInfo->pKey1 = pKeyNew;
}
pKeyLast = pKeyNew;
pKeyNew = pKeyTmp;
( pSortInfo->nItems ) --;
}
/*
{
int i = 0;
char ctmp[30];
ctmp[ pTag->KeyLength ] = 0;
printf( "\n\r------------------" );
for( pKey = pSortInfo->pKeyFirst; pKey ; pKey = pKey->pNext,i++ )
{
memcpy( ctmp,pKey->key,pTag->KeyLength );
printf( "\n\r%d %s",i,ctmp );
}
}
*/
}
static void hb_ntxRootPage( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, LPSORTITEM pKey, USHORT level )
{
USHORT i, maxKeys = pTag->MaxKeys*2/3;
LPNTXBUFFER itemlist;
LPNTXITEM item;
if( !pSortInfo->pageBuffers[ level ] )
{
if( !pKey )
return;
pSortInfo->pageBuffers[ level ] = (char*) hb_xgrab( NTXBLOCKSIZE );
memset( pSortInfo->pageBuffers[ level ], 0, NTXBLOCKSIZE );
itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ level ];
for( i = 0; i < maxKeys + 1; i++ )
itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) +
i * ( pTag->KeyLength + 8 );
}
else
itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ level ];
/* printf( "\nhb_ntxRootPage - 1( itemlist->item_count=%d %d",itemlist->item_count,itemlist->item_offset[itemlist->item_count] ); */
item = (NTXITEM *)( pSortInfo->pageBuffers[ level ] + itemlist->item_offset[itemlist->item_count] );
item->page = pSortInfo->Tag;
if( itemlist->item_count < maxKeys && pKey )
{
item->rec_no = pKey->rec_no;
memcpy( item->key, pKey->key, pTag->KeyLength );
itemlist->item_count++;
}
else
{
if( pKey || itemlist->item_count > 0 )
{
pSortInfo->Tag += NTXBLOCKSIZE;
hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) pSortInfo->pageBuffers[ level ], NTXBLOCKSIZE );
itemlist->item_count = 0;
memset( pSortInfo->pageBuffers[ level ] + 4 + 2 * ( pTag->MaxKeys + 1 ),
0, NTXBLOCKSIZE - 6 - 2 * ( pTag->MaxKeys + 1 ) );
}
if( !pKey )
pTag->RootBlock = pSortInfo->Tag;
hb_ntxRootPage( pTag, pSortInfo, pKey, level+1 );
}
}
static void hb_ntxBufferSave( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo )
{
USHORT i, maxKeys = pTag->MaxKeys*2/3;
LPNTXBUFFER itemlist;
LPNTXITEM item;
ULONG numKey = 0;
LPSORTITEM pKey = pSortInfo->pKeyFirst;
char* buffer;
BOOL lSave = FALSE;
pSortInfo->Tag = 0;
pSortInfo->pageBuffers = (char**) hb_xgrab( sizeof( char* ) * 10 );
for( i = 0; i < 10; i++ )
pSortInfo->pageBuffers[i] = NULL;
pSortInfo->pageBuffers[0] = (char*) hb_xgrab( NTXBLOCKSIZE );
memset( pSortInfo->pageBuffers[0], 0, NTXBLOCKSIZE );
itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[0];
for( i = 0; i < maxKeys + 1; i++ )
itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) +
i * ( pTag->KeyLength + 8 );
buffer = pSortInfo->pageBuffers[0];
/* printf( "\nhb_ntxBufferSave - 1 ( maxKeys=%d )",maxKeys ); */
while( pKey )
{
for( i = 0; i < maxKeys && pKey > 0; i++, numKey++, pKey = pKey->pNext )
{
/* printf( "\nhb_ntxBufferSave - 2 ( i=%d maxKeys=%d )",i,maxKeys ); */
item = (NTXITEM *)( buffer + itemlist->item_offset[i] );
item->page = 0;
item->rec_no = pKey->rec_no;
memcpy( item->key, pKey->key, pTag->KeyLength );
}
itemlist->item_count = i;
pSortInfo->Tag += NTXBLOCKSIZE;
hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) buffer, NTXBLOCKSIZE );
/* printf( "\nhb_ntxBufferSave - 5 ( numKey=%d )",numKey ); */
hb_ntxRootPage( pTag, pSortInfo, pKey, 1 );
numKey ++;
if( pKey )
pKey = pKey->pNext;
}
hb_xfree( pSortInfo->pageBuffers[ 0 ] );
for( i = 1; i < 10; i++ )
if( pSortInfo->pageBuffers[ i ] )
{
itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ i ];
if( itemlist->item_count )
{
if( lSave )
{
item = (NTXITEM *)( pSortInfo->pageBuffers[ i ] + itemlist->item_offset[itemlist->item_count] );
item->page = pSortInfo->Tag;
}
lSave = TRUE;
pSortInfo->Tag += NTXBLOCKSIZE;
hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) pSortInfo->pageBuffers[ i ], NTXBLOCKSIZE );
pTag->RootBlock = pSortInfo->Tag;
}
hb_xfree( pSortInfo->pageBuffers[ i ] );
}
hb_xfree( pSortInfo->pageBuffers );
if( !pTag->RootBlock )
pTag->RootBlock = 1024;
}
static void hb_ntxReadBuf( NTXAREAP pArea, BYTE* readBuffer, USHORT* numRecinBuf )
{
if( *numRecinBuf == 10 )
*numRecinBuf = 0;
if( *numRecinBuf == 0 )
hb_fsReadLarge( pArea->hDataFile, readBuffer, pArea->uiRecordLen * 10 );
pArea->pRecord = readBuffer + (*numRecinBuf) * pArea->uiRecordLen;
(*numRecinBuf) ++;
}
/* DJGPP can sprintf a float that is almost 320 digits long */
#define HB_MAX_DOUBLE_LENGTH 320
static ERRCODE hb_ntxIndexCreate( LPNTXINDEX pIndex )
{
ULONG ulRecNo, ulRecCount;
USHORT uiCurLen;
char szBuffer[ HB_MAX_DOUBLE_LENGTH + 1 ];
NTXAREAP pArea;
LPTAGINFO pTag;
HB_MACRO_PTR pMacro;
PHB_ITEM pItem;
BOOL bWhileOk;
NTXSORTINFO sortInfo;
BYTE* readBuffer;
USHORT numRecinBuf = 0;
BYTE * pRecordTmp;
ulRecCount = pIndex->Owner->ulRecCount;
pArea = pIndex->Owner;
pTag = pIndex->CompoundTag;
pItem = hb_itemNew( NULL );
readBuffer = (BYTE*) hb_xgrab( pArea->uiRecordLen * 10 );
/* itemLength = sizeof( LPSORTITEM ) + sizeof( ULONG ) + pTag->KeyLength; */
sortInfo.itemLength = sizeof( LPSORTITEM ) + sizeof( ULONG ) + pTag->KeyLength;
sortInfo.nItems = 0;
sortInfo.pKey1 = sortInfo.pKey2 = NULL;
sortInfo.sortBuffer = (BYTE*) hb_xalloc( ulRecCount * sortInfo.itemLength );
if( !sortInfo.sortBuffer )
{
/* TODO: handling of few reduced buffers */
printf( "\r\nhb_ntxIndexCreate: Not enough room for index buffer !" );
return FAILURE;
}
pRecordTmp = pArea->pRecord;
hb_fsSeek( pArea->hDataFile, pArea->uiHeaderLen, FS_SET );
for( ulRecNo = 1; ulRecNo <= ulRecCount; ulRecNo++)
{
hb_ntxReadBuf( pArea, readBuffer, &numRecinBuf );
pArea->ulRecNo = ulRecNo;
if( pTag->pForItem != NULL )
/* TODO: test for expression */
bWhileOk = TRUE;
else
bWhileOk = TRUE;
if( bWhileOk )
{
if( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK )
{
hb_vmPushSymbol( &hb_symEval );
hb_vmPush( pTag->pKeyItem );
hb_vmDo( 0 );
hb_itemCopy( pItem, &hb_stack.Return );
}
else
{
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem );
hb_macroRun( pMacro );
hb_itemCopy( pItem, hb_stackItemFromTop( - 1 ) );
hb_stackPop();
}
switch( hb_itemType( pItem ) )
{
case HB_IT_STRING:
uiCurLen = hb_itemGetCLen( pItem );
if(uiCurLen > NTX_MAX_KEY )
uiCurLen = NTX_MAX_KEY ;
if( pTag->KeyLength != uiCurLen )
{
hb_itemRelease( pItem );
return FAILURE;
}
// hb_ntxTagKeyAdd( pTag, pItem );
hb_ntxSortKeyAdd( pTag, &sortInfo, pItem->item.asString.value );
break;
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
numToStr( pItem, szBuffer, pTag->KeyLength, pTag->KeyDec );
hb_ntxSortKeyAdd( pTag, &sortInfo,szBuffer );
break;
case HB_IT_DATE:
hb_itemGetDS( pItem, szBuffer );
hb_ntxSortKeyAdd( pTag, &sortInfo, szBuffer );
break;
default:
printf( "ntxCreateOrder" );
}
}
}
pArea->pRecord = pRecordTmp;
hb_fsSeek( pTag->Owner->DiskFile, 1024, FS_SET );
hb_ntxBufferSave( pTag, &sortInfo );
hb_xfree( sortInfo.sortBuffer );
hb_xfree( readBuffer );
hb_itemRelease( pItem );
// hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
/* printf( "\nntxIndexCreate - 10" ); */
return SUCCESS;
}
static void hb_ntxHeaderSave( LPNTXINDEX pIndex )
{
NTXHEADER Header;
memset( (void*) &Header, 0, sizeof( NTXHEADER ) );
Header.type = 15;
Header.version = 1;
Header.root = pIndex->CompoundTag->RootBlock;
Header.next_page = pIndex->NextAvail;
Header.item_size = pIndex->CompoundTag->KeyLength+8;
Header.key_size = pIndex->CompoundTag->KeyLength;
Header.key_dec = pIndex->CompoundTag->KeyDec;
Header.max_item = pIndex->CompoundTag->MaxKeys;
Header.half_page = Header.max_item/2;
strcpy( Header.key_expr , pIndex->CompoundTag->KeyExpr );
Header.unique = pIndex->CompoundTag->UniqueKey;
hb_fsSeek( pIndex->DiskFile , 0 , 0 );
hb_fsWrite( pIndex->DiskFile,(BYTE*)&Header,sizeof(NTXHEADER));
if( pIndex->CompoundTag->RootPage )
pIndex->CompoundTag->RootPage->NewRoot = FALSE;
}
static LPTAGINFO hb_ntxTagNew( LPNTXINDEX PIF, char * ITN, char *szKeyExpr, PHB_ITEM pKeyExpr, BYTE bKeyType, USHORT uiKeyLen, USHORT uiKeyDec, char *szForExp, PHB_ITEM pForExp, BOOL fAscendKey, BOOL fUnique )
{
LPTAGINFO pTag;
pTag = ( LPTAGINFO ) hb_xgrab( sizeof( TAGINFO ) );
memset( pTag, 0, sizeof( TAGINFO ) );
/*
pTag->TagName = (char *) hb_xgrab( strlen( ITN ) + 1 );
hb_strncpyUpper( pTag->TagName, ITN, strlen( ITN ) + 1 );
*/
pTag->TagName = ITN;
if( szKeyExpr )
{
pTag->KeyExpr = (char *) hb_xgrab( NTX_MAX_KEY );
strcpy( pTag->KeyExpr, szKeyExpr );
}
if( szForExp )
{
pTag->ForExpr = (char *) hb_xgrab( NTX_MAX_KEY );
strcpy( pTag->ForExpr, szForExp );
}
pTag->pKeyItem = pKeyExpr;
pTag->pForItem = pForExp;
pTag->AscendKey = fAscendKey;
pTag->UniqueKey = fUnique;
pTag->KeyType = bKeyType;
pTag->KeyLength = uiKeyLen;
pTag->KeyDec = uiKeyDec;
pTag->Owner = PIF;
pTag->MaxKeys = (NTXBLOCKSIZE-6)/(uiKeyLen+10) - 1;
pTag->CurKeyInfo = hb_ntxKeyNew( NULL );
pTag->uiPages = 0;
return pTag;
}
static LPNTXINDEX hb_ntxIndexNew( NTXAREAP pArea )
{
LPNTXINDEX pIndex;
pIndex = ( LPNTXINDEX ) hb_xgrab( sizeof( NTXINDEX ) );
memset( pIndex, 0, sizeof( NTXINDEX ) );
pIndex->DiskFile = FS_ERROR;
pIndex->Owner = pArea;
pIndex->NextAvail = 0;
pIndex->TagRoot = 1;
return pIndex;
}
static void hb_ntxIndexFree( LPNTXINDEX pIndex )
{
LPTAGINFO pTag;
pTag = pIndex->CompoundTag;
if( pTag->RootPage > 0 )
hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
hb_fsClose( pIndex->DiskFile );
hb_xfree( pTag->TagName );
if( pTag->KeyExpr != NULL )
hb_xfree( pTag->KeyExpr );
if( pTag->ForExpr != NULL )
hb_xfree( pTag->ForExpr );
if( pTag->pKeyItem != NULL )
{
if( hb_itemType( pTag->pKeyItem ) != HB_IT_BLOCK )
hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) );
hb_itemRelease( pTag->pKeyItem );
}
if( pTag->pForItem != NULL )
{
hb_itemRelease( pTag->pForItem );
}
hb_ntxKeyFree( pTag->CurKeyInfo );
hb_xfree( pTag );
hb_xfree( pIndex->IndexName );
hb_xfree( pIndex );
}
static ERRCODE hb_ntxHeaderLoad( LPNTXINDEX pIndex , char *ITN)
{
NTXHEADER Header;
LPTAGINFO pTag;
PHB_ITEM pExpr, pKeyExp;
ULONG ulPos;
ulPos = hb_fsSeek( pIndex->DiskFile, 0, SEEK_END );
hb_fsSeek( pIndex->DiskFile , 0 , 0 );
if( hb_fsRead( pIndex->DiskFile,(BYTE*)&Header,sizeof(NTXHEADER)) != sizeof(NTXHEADER) )
return FAILURE;
if( SELF_COMPILE( ( AREAP ) pIndex->Owner, (BYTE*)Header.key_expr ) == FAILURE )
return FAILURE;
pExpr = pIndex->Owner->valResult;
pKeyExp = hb_itemNew( NULL );
hb_itemCopy( pKeyExp, pExpr );
pTag = ( LPTAGINFO ) hb_xgrab( sizeof( TAGINFO ) );
memset( pTag, 0, sizeof( TAGINFO ) );
pIndex->CompoundTag = pTag;
pIndex->NextAvail = Header.next_page;
pTag->TagBlock = ulPos - 1024;
pTag->RootBlock = Header.root;
pTag->TagName = (char *) hb_xgrab( strlen( ITN ) + 1 );
hb_strncpyUpper( pTag->TagName, ITN, strlen( ITN ) );
pTag->KeyExpr = (char *) hb_xgrab( NTX_MAX_KEY );
strcpy( pTag->KeyExpr, Header.key_expr );
pTag->pKeyItem = pKeyExp;
pTag->AscendKey = 1; /* fAscendKey; */
pTag->UniqueKey = Header.unique;
pTag->KeyType = 'C'; /* bKeyType; */
pTag->KeyLength = Header.key_size;
pTag->KeyDec = Header.key_dec;
pTag->Owner = pIndex;
pTag->MaxKeys = Header.max_item;
pTag->CurKeyInfo = hb_ntxKeyNew( NULL );
return SUCCESS;
}
static LPPAGEINFO hb_ntxPageFind( LPNTXINDEX pIndex, LONG ulOffset )
{
LPPAGEINFO pPage = pIndex->CompoundTag->RootPage;
/* printf( "\nntxPageFind - 0 ( %5lx %5lx %d )",pIndex,pPage,ulOffset ); */
while( pPage )
{
if( pPage->Page == ulOffset )
break;
pPage = pPage->pNext;
}
return pPage;
}
static LPPAGEINFO hb_ntxPageLast( LPNTXINDEX pIndex )
{
LPPAGEINFO pPage = pIndex->CompoundTag->RootPage;
if( pPage )
{
while( pPage->pNext )
{
pPage = pPage->pNext;
}
}
return pPage;
}
static LPNTXINDEX ntxFindIndex( NTXAREAP pArea , PHB_ITEM lpOrder )
{
LPNTXINDEX start, current;
start = pArea->lpNtxIndex;
current = start;
if( !lpOrder )
return pArea->lpCurIndex;
else if( hb_itemType( lpOrder ) == HB_IT_STRING )
{
do
{
if( !strcmp( current->CompoundTag->TagName , hb_itemGetCPtr( lpOrder ) ) )
return current;
current = current->pNext;
} while( current );
}
else
{
do
{
if( current->TagRoot == hb_itemGetNI( lpOrder ) )
return current;
current = current->pNext;
} while( current );
}
return NULL;
}
/* Implementation of exported functions */
static ERRCODE ntxGoBottom( NTXAREAP pArea )
{
HB_TRACE(HB_TR_DEBUG, ("ntxGoBottom(%p)", pArea));
if ( !pArea->lpCurIndex || !pArea->lpNtxIndex )
SUPER_GOBOTTOM( ( AREAP ) pArea );
else
{
LPTAGINFO pTag;
pTag = pArea->lpCurIndex->CompoundTag;
hb_ntxTagKeyRead( pTag, BTTM_RECORD );
SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra );
}
return SELF_SKIPFILTER( ( AREAP ) pArea, 1 );
}
static ERRCODE ntxGoTo( NTXAREAP pArea, ULONG ulRecNo )
{
HB_TRACE(HB_TR_DEBUG, ("ntxGoTo(%p, %lu)", pArea, ulRecNo));
if( pArea->lpCurIndex &&
(ULONG)pArea->lpCurIndex->CompoundTag->CurKeyInfo->Xtra != ulRecNo )
pArea->lpCurIndex->CompoundTag->CurKeyInfo->Tag = 0;
return SUPER_GOTO( ( AREAP ) pArea,ulRecNo );
}
static ERRCODE ntxGoTop( NTXAREAP pArea )
{
HB_TRACE(HB_TR_DEBUG, ("ntxGoTop(%p)", pArea));
if ( !pArea->lpCurIndex || !pArea->lpNtxIndex )
SUPER_GOTOP( ( AREAP ) pArea );
else
{
LPTAGINFO pTag;
pTag = pArea->lpCurIndex->CompoundTag;
hb_ntxTagKeyRead( pTag, TOP_RECORD );
SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra );
}
return SELF_SKIPFILTER( ( AREAP ) pArea, 1 );
}
static ERRCODE ntxSeek( NTXAREAP pArea, BOOL bSoftSeek, PHB_ITEM pKey, BOOL bFindLast )
{
PHB_ITEM pError;
ERRCODE retvalue;
HB_TRACE(HB_TR_DEBUG, ("ntxSeek(%p, %d, %p, %d)", pArea, bSoftSeek, pKey, bFindLast));
if ( ! pArea->lpCurIndex )
{
pError = hb_errNew();
hb_errPutGenCode( pError, EG_NOORDER );
hb_errPutSubCode( pError, 1020 );
hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_NOORDER ) );
hb_errPutFlags( pError, EF_CANDEFAULT );
SELF_ERROR( ( AREAP ) pArea, pError );
hb_errRelease( pError );
return FAILURE;
}
else
{
LONG lRecno;
LPKEYINFO pKey2;
LPTAGINFO pTag;
LPNTXINDEX lpCurIndex;
char szBuffer[ NTX_MAX_KEY ];
pTag = pArea->lpCurIndex->CompoundTag;
pKey2 = hb_ntxKeyNew( NULL );
switch( hb_itemType( pKey ) )
{
case HB_IT_STRING:
hb_itemCopy( pKey2->pItem, pKey );
break;
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
hb_itemPutC( pKey2->pItem, numToStr( pKey, szBuffer, pTag->KeyLength, pTag->KeyDec ) );
break;
case HB_IT_DATE:
hb_itemGetDS( pKey, szBuffer );
hb_itemPutC( pKey2->pItem,szBuffer );
break;
}
/* hb_itemCopy( pKey2->pItem, pKey ); */
if ( bFindLast )
pKey2->Tag = NTX_MAX_REC_NUM;
else
pKey2->Tag = NTX_IGNORE_REC_NUM;
pKey2->Xtra = 0;
if( pArea->fShared )
while( !hb_fsLock( pArea->lpCurIndex->DiskFile, 0, 512, FL_LOCK ) );
lRecno = hb_ntxTagKeyFind( pTag, pKey2 );
if( pArea->fShared )
{
hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
hb_fsLock( pArea->lpCurIndex->DiskFile, 0, 512, FL_UNLOCK );
}
pArea->fEof = pTag->TagEOF;
pArea->fBof = pTag->TagBOF;
hb_ntxKeyFree( pKey2 );
if ( lRecno > 0 )
{
retvalue = SELF_GOTO( ( AREAP ) pArea, lRecno );
pArea->fFound = TRUE;
return retvalue;
}
else
{
pArea->fFound = FALSE;
if ( bSoftSeek && !pTag->TagEOF )
{
return SELF_GOTO( ( AREAP ) pArea, lRecno );
}
else
{
lpCurIndex = pArea->lpCurIndex;
pArea->lpCurIndex = NULL;
SELF_GOBOTTOM( ( AREAP ) pArea );
retvalue = SELF_SKIPRAW( ( AREAP ) pArea, 1 );
pArea->lpCurIndex = lpCurIndex;
return retvalue;
}
}
}
}
static ERRCODE ntxSkipRaw( NTXAREAP pArea, LONG lToSkip )
{
HB_TRACE(HB_TR_DEBUG, ("ntxSkipRaw(%p, %ld)", pArea, lToSkip));
if ( ! pArea->lpCurIndex )
SUPER_SKIPRAW( ( AREAP ) pArea, lToSkip );
else
{
LPTAGINFO pTag = pArea->lpCurIndex->CompoundTag;
if ( pArea->fBof )
SELF_GOTOP( ( AREAP ) pArea );
if ( lToSkip == 0 )
SUPER_SKIPRAW( ( AREAP ) pArea, 0 );
else if ( lToSkip > 0 )
{
if ( !pArea->fEof )
{
while ( !pTag->TagEOF && lToSkip-- > 0 )
hb_ntxTagKeyRead( pTag, NEXT_RECORD );
if ( !pTag->TagEOF )
SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra );
else
{
SUPER_GOBOTTOM( ( AREAP ) pArea );
SUPER_SKIPRAW( ( AREAP ) pArea, 1 );
pArea->fEof = pTag->TagEOF = TRUE;
}
}
}
else /* ( lToSkip < 0 ) */
{
if ( pArea->fEof )
{
SELF_GOBOTTOM( ( AREAP ) pArea );
lToSkip++;
}
pTag->TagBOF = FALSE;
while ( !pTag->TagBOF && lToSkip++ < 0 )
hb_ntxTagKeyRead( pTag, PREV_RECORD );
if ( !pTag->TagBOF )
SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra );
else
{
pTag->TagBOF = FALSE;
SELF_GOTOP( ( AREAP ) pArea );
pArea->fBof = pTag->TagBOF = TRUE;
}
}
}
return SUCCESS;
}
static ERRCODE ntxAppend( NTXAREAP pArea, BOOL bUnLockAll )
{
HB_TRACE(HB_TR_DEBUG, ("ntxAppend(%p, %d)", pArea, bUnLockAll ));
if( SUPER_APPEND( ( AREAP ) pArea, bUnLockAll ) == SUCCESS )
{
LPNTXINDEX lpIndex, lpIndexTmp;
LPTAGINFO pTag;
lpIndex = pArea->lpNtxIndex;
lpIndexTmp = pArea->lpCurIndex;
while( lpIndex )
{
pArea->lpCurIndex = lpIndex;
pTag = lpIndex->CompoundTag;
hb_ntxGetCurrentKey( pTag, pTag->CurKeyInfo );
if( pArea->fShared )
while( !hb_fsLock( lpIndex->DiskFile, 0, 512, FL_LOCK ) );
hb_ntxPageKeyAdd( hb_ntxPageLoad( 0 ), pTag->CurKeyInfo->pItem, 0, FALSE );
if( pArea->fShared )
{
hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
hb_fsLock( lpIndex->DiskFile, 0, 512, FL_UNLOCK );
}
lpIndex = lpIndex->pNext;
}
pArea->lpCurIndex = lpIndexTmp;
return SUCCESS;
}
else
return FAILURE;
}
static ERRCODE ntxPutValue( NTXAREAP pArea, USHORT uiIndex, PHB_ITEM pItem )
{
LPNTXINDEX lpIndex, lpIndexTmp;
LPKEYINFO pKey, pKeyOld;
LPTAGINFO pTag;
LPPAGEINFO pPage;
PHB_ITEM pItemNew;
HB_TRACE(HB_TR_DEBUG, ("ntxPutValue(%p, %hu, %p)", pArea, uiIndex, pItem));
pItemNew = hb_itemNew( pItem );
hb_itemClear( pItem );
lpIndex = pArea->lpNtxIndex;
lpIndexTmp = pArea->lpCurIndex;
while( lpIndex )
{
pTag = lpIndex->CompoundTag;
hb_ntxGetCurrentKey( pTag, pTag->CurKeyInfo );
lpIndex = lpIndex->pNext;
}
/* printf( "\n\rntxPutValue - 1: |%s|",pItemNew->item.asString.value ); */
SUPER_PUTVALUE( ( AREAP ) pArea, uiIndex, pItemNew);
hb_itemRelease( pItemNew );
pKey = hb_ntxKeyNew( NULL );
pKeyOld = hb_ntxKeyNew( NULL );
lpIndex = pArea->lpNtxIndex;
while( lpIndex )
{
pTag = lpIndex->CompoundTag;
hb_ntxGetCurrentKey( pTag, pKey );
if( hb_ntxItemCompare( pKey->pItem, pTag->CurKeyInfo->pItem, TRUE ) )
{
pArea->lpCurIndex = lpIndex;
hb_itemCopy( pKeyOld->pItem, pTag->CurKeyInfo->pItem );
pKeyOld->Xtra = pTag->CurKeyInfo->Xtra;
pKeyOld->Tag = NTX_IGNORE_REC_NUM;
if( pArea->fShared )
while( !hb_fsLock( lpIndex->DiskFile, 0, 512, FL_LOCK ) );
if( hb_ntxTagFindCurrentKey( hb_ntxPageLoad( 0 ), pKeyOld->Tag, pKeyOld, FALSE, FALSE, 1 ) )
{
printf( "\n\rntxPutValue: Cannot find current key:" );
lpIndex = lpIndex->pNext;
continue;
}
pPage = hb_ntxPageLoad( pTag->CurKeyInfo->Tag );
pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ) - 1;
hb_ntxPageKeyDel( pPage, pPage->CurKey, 1 );
hb_ntxPageKeyAdd( hb_ntxPageLoad( 0 ), pKey->pItem, 0, FALSE );
if( pArea->fShared )
{
hb_ntxPageFree( pTag->RootPage,TRUE );
pTag->RootPage = NULL;
hb_fsLock( lpIndex->DiskFile, 0, 512, FL_UNLOCK );
}
}
lpIndex = lpIndex->pNext;
}
hb_ntxKeyFree( pKeyOld );
hb_ntxKeyFree( pKey );
pArea->lpCurIndex = lpIndexTmp;
return SUCCESS;
}
/*
* Retrieve the size of the WorkArea structure.
*/
static ERRCODE ntxStructSize( NTXAREAP pArea, USHORT * uiSize )
{
HB_TRACE(HB_TR_DEBUG, ("ntxStrucSize(%p, %p)", pArea, uiSize));
HB_SYMBOL_UNUSED( pArea );
* uiSize = sizeof( NTXAREA );
return SUCCESS;
}
static ERRCODE ntxPack( NTXAREAP pArea )
{
HB_TRACE(HB_TR_DEBUG, ("ntxPack(%p)", pArea ));
if( SUPER_PACK( ( AREAP ) pArea ) == SUCCESS )
return ntxOrderListRebuild( pArea );
else
return FAILURE;
}
static ERRCODE ntxZap( NTXAREAP pArea )
{
HB_TRACE(HB_TR_DEBUG, ("ntxZap(%p)", pArea ));
if( SUPER_ZAP( ( AREAP ) pArea ) == SUCCESS )
{
LPNTXINDEX lpIndex, lpIndexTmp;
LPTAGINFO pTag;
char* buffer;
USHORT i, maxKeys;
LPNTXBUFFER itemlist;
buffer = (char*) hb_xgrab( NTXBLOCKSIZE );
lpIndex = pArea->lpNtxIndex;
lpIndexTmp = pArea->lpCurIndex;
while( lpIndex )
{
lpIndex->CompoundTag->RootBlock = NTXBLOCKSIZE;
hb_ntxHeaderSave( lpIndex );
pTag = lpIndex->CompoundTag;
maxKeys = pTag->MaxKeys*2/3;
memset( buffer, 0, NTXBLOCKSIZE );
itemlist = ( LPNTXBUFFER ) buffer;
itemlist->item_count = 0;
for( i = 0; i < maxKeys + 1; i++ )
itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) +
i * ( pTag->KeyLength + 8 );
hb_fsSeek( lpIndex->DiskFile, NTXBLOCKSIZE, FS_SET );
hb_fsWrite( lpIndex->DiskFile, (BYTE *) buffer, NTXBLOCKSIZE );
hb_fsWrite( lpIndex->DiskFile, NULL, 0 );
lpIndex = lpIndex->pNext;
}
pArea->lpCurIndex = lpIndexTmp;
hb_xfree( buffer );
return SELF_GOTOP( ( AREAP ) pArea );
}
else
return FAILURE;
}
static ERRCODE ntxOrderCreate( NTXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo )
{
PHB_ITEM pExpr, pResult, pError;
PHB_ITEM pKeyExp, pForExp;
HB_MACRO_PTR pExpMacro, pForMacro;
USHORT uiType;
int uiLen, uiDec;
char * szFileName, * szTagName;
LPNTXINDEX pIndex;
LPTAGINFO pTag;
PHB_FNAME pFileName;
DBORDERINFO pExtInfo;
BYTE bType;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderCreate(%p, %p)", pArea, pOrderInfo));
SELF_ORDLSTCLEAR( ( AREAP ) pArea );
if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE )
return FAILURE;
/* If we have a codeblock for the expression, use it */
if( pOrderInfo->itmCobExpr )
pExpr = pOrderInfo->itmCobExpr;
else /* Otherwise, try compiling the key expression string */
{
if( SELF_COMPILE( ( AREAP ) pArea, ( BYTE * ) pOrderInfo->abExpr->item.asString.value ) == FAILURE )
return FAILURE;
pExpr = pArea->valResult;
// pArea->valResult = NULL;
}
/* Save for later use */
pKeyExp = hb_itemNew( NULL );
hb_itemCopy( pKeyExp, pExpr );
/* Get a blank record before testing expression */
SELF_GOBOTTOM( ( AREAP ) pArea );
SELF_SKIP( ( AREAP ) pArea, 1 );
pExpMacro = pForMacro = NULL;
if( hb_itemType( pExpr ) == HB_IT_BLOCK )
{
if( SELF_EVALBLOCK( ( AREAP ) pArea, pExpr ) == FAILURE )
{
hb_itemRelease( pKeyExp );
return FAILURE;
}
pResult = pArea->valResult;
// pArea->valResult = NULL;
}
else
{
pExpMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr );
hb_macroRun( pExpMacro );
pResult = pExpr;
hb_itemCopy( pResult, &hb_stack.Return );
}
uiType = hb_itemType( pResult );
uiLen = uiDec = 0;
bType = '\0';
switch( uiType )
{
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
bType = 'N';
hb_itemGetNLen( pResult, (int*) &uiLen, (int*) &uiDec );
if( uiDec )
uiLen += uiDec + 1;
/* printf( "\nLength: %d %d",uiLen,uiDec ); */
break;
case HB_IT_DATE:
bType = 'D';
uiLen = 8;
break;
case HB_IT_LOGICAL:
bType = 'C';
uiLen = 1;
break;
case HB_IT_STRING:
bType = 'C';
uiLen = pResult->item.asString.length > NTX_MAX_KEY ? NTX_MAX_KEY :
pResult->item.asString.length ;
break;
}
/* hb_itemRelease( pResult ); */
/* Make sure uiLen is not 0 */
if( !uiLen )
{
hb_itemRelease( pKeyExp );
pError = hb_errNew();
hb_errPutGenCode( pError, EG_DATAWIDTH );
hb_errPutSubCode( pError, 1026 );
hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATAWIDTH ) );
SELF_ERROR( ( AREAP ) pArea, pError );
hb_errRelease( pError );
if( pExpMacro != NULL )
hb_macroDelete( pExpMacro );
return FAILURE;
}
/* Check conditional expression */
pExpr = pForExp = NULL;
if( pArea->lpdbOrdCondInfo )
{
/* If we have a codeblock for the conditional expression, use it */
if( pArea->lpdbOrdCondInfo->itmCobFor )
pExpr = pArea->lpdbOrdCondInfo->itmCobFor;
else /* Otherwise, try compiling the conditional expression string */
{
if( SELF_COMPILE( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE )
return FAILURE;
pExpr = pArea->valResult;
// pArea->valResult = NULL;
}
/* Save for later use */
pForExp = hb_itemNew( NULL );
hb_itemCopy( pForExp, pExpr );
}
/* Test conditional expression */
if( pExpr )
{
if( hb_itemType( pExpr ) == HB_IT_BLOCK )
{
if( SELF_EVALBLOCK( ( AREAP ) pArea, pExpr ) == FAILURE )
{
hb_itemRelease( pKeyExp );
hb_itemRelease( pForExp );
if( pExpMacro != NULL )
hb_macroDelete( pExpMacro );
return FAILURE;
}
pResult = pArea->valResult;
}
else
{
pForMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr );
hb_macroRun( pForMacro );
pResult = pExpr;
hb_itemCopy( pResult, &hb_stack.Return );
}
uiType = hb_itemType( pResult );
hb_itemRelease( pResult );
if( uiType != HB_IT_LOGICAL )
{
hb_itemRelease( pKeyExp );
hb_itemRelease( pForExp );
if( pExpMacro != NULL )
hb_macroDelete( pExpMacro );
if( pForMacro != NULL )
hb_macroDelete( pForMacro );
return FAILURE;
}
}
/* Check file name */
szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
szFileName[ 0 ] = '\0';
if( strlen( ( char * ) pOrderInfo->abBagName ) == 0 )
{
pFileName = hb_fsFNameSplit( pArea->szDataFileName );
if( pFileName->szDrive )
strcat( szFileName, pFileName->szDrive );
if( pFileName->szPath )
strcat( szFileName, pFileName->szPath );
strcat( szFileName, pFileName->szName );
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) );
hb_itemRelease( pExtInfo.itmResult );
}
else
{
strcpy( szFileName, ( char * ) pOrderInfo->abBagName );
pFileName = hb_fsFNameSplit( szFileName );
if( !pFileName->szExtension )
{
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) );
hb_itemRelease( pExtInfo.itmResult );
}
}
szTagName = ( char * ) hb_xgrab( strlen( pFileName->szName ) + 1 );
hb_strncpyUpper( szTagName, pFileName->szName, strlen( pFileName->szName ) );
hb_xfree( pFileName );
pIndex = hb_ntxIndexNew( pArea );
pIndex->IndexName = szFileName;
pArea->lpNtxIndex = pIndex;
pArea->lpCurIndex = pIndex;
pTag = hb_ntxTagNew( pIndex, szTagName, pOrderInfo->abExpr->item.asString.value,
pKeyExp, bType, (USHORT) uiLen, (USHORT) uiDec, (char *) ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->abFor : NULL ),
pForExp, pArea->lpdbOrdCondInfo ? !pArea->lpdbOrdCondInfo->fDescending : TRUE,
pOrderInfo->fUnique );
pIndex->CompoundTag = pTag;
pIndex->DiskFile = hb_fsCreate( ( BYTE * ) szFileName , FC_NORMAL );
if(pIndex->DiskFile == FS_ERROR) {
hb_xfree( szFileName );
hb_itemRelease( pKeyExp );
if( pForExp != NULL )
hb_itemRelease( pForExp );
if( pExpMacro != NULL )
hb_macroDelete( pExpMacro );
if( pForMacro != NULL )
hb_macroDelete( pForMacro );
return FAILURE;
}
if( hb_ntxIndexCreate( pIndex ) == FAILURE )
{
return FAILURE;
}
hb_ntxHeaderSave( pIndex );
{
BYTE emptyBuffer[250];
memset( emptyBuffer, 0, 250 );
hb_fsWrite( pIndex->DiskFile, emptyBuffer, 250 );
}
SELF_ORDSETCOND( ( AREAP ) pArea, NULL );
return SELF_GOTOP( ( AREAP ) pArea );
}
static ERRCODE ntxOrderInfo( NTXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo )
{
LPNTXINDEX pIndex;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderInfo(%p, %hu, %p)", pArea, uiIndex, pInfo));
switch( uiIndex )
{
case DBOI_CONDITION:
if( pArea->lpNtxIndex )
{
pIndex = ntxFindIndex( pArea , pInfo->itmOrder );
if( pIndex && ( pIndex->CompoundTag->ForExpr != NULL ) )
{
hb_itemPutC( pInfo->itmResult , pIndex->CompoundTag->ForExpr );
return SUCCESS;
}
}
hb_itemPutC( pInfo->itmResult, "" );
break;
case DBOI_EXPRESSION:
if( pArea->lpNtxIndex )
{
pIndex = ntxFindIndex( pArea , pInfo->itmOrder );
if( pIndex )
{
hb_itemPutC( pInfo->itmResult , pIndex->CompoundTag->KeyExpr );
return SUCCESS;
}
}
hb_itemPutC( pInfo->itmResult, "" );
break;
case DBOI_NUMBER:
if( pArea->lpNtxIndex )
{
pIndex = ntxFindIndex( pArea , pInfo->itmOrder );
if( pIndex )
{
hb_itemPutNI( pInfo->itmResult, pIndex->TagRoot );
return SUCCESS;
}
}
/* TODO: Raise recoverable error */
break;
case DBOI_BAGNAME:
if( pArea->lpNtxIndex )
{
pIndex = ntxFindIndex( pArea , pInfo->itmOrder );
if( pIndex )
{
hb_itemPutC( pInfo->itmResult, pIndex->IndexName );
return SUCCESS;
}
}
hb_itemPutC( pInfo->itmResult, "" );
break;
case DBOI_BAGEXT:
hb_itemPutC( pInfo->itmResult, ".ntx" );
break;
}
return SUCCESS;
}
static ERRCODE ntxOrderListAdd( NTXAREAP pArea, LPDBORDERINFO pOrderInfo )
{
USHORT uiFlags;
char * szFileName;
PHB_FNAME pFileName;
DBORDERINFO pExtInfo;
LPNTXINDEX pIndex, pIndexNext;
PHB_ITEM pError = NULL;
BOOL bRetry;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderListAdd(%p, %p)", pArea, pOrderInfo));
szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
szFileName[ 0 ] = '\0';
strcpy( szFileName, hb_itemGetCPtr( pOrderInfo->atomBagName ) );
if( strlen( szFileName ) == 0 )
{
hb_xfree( szFileName );
return FAILURE;
}
pFileName = hb_fsFNameSplit( szFileName );
if( !pFileName->szExtension )
{
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) );
hb_itemRelease( pExtInfo.itmResult );
}
pIndex = hb_ntxIndexNew( pArea );
uiFlags = pArea->fReadonly ? FO_READ : FO_READWRITE;
uiFlags |= pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE;
do
{
pIndex->DiskFile = hb_fsOpen( ( BYTE * ) szFileName, uiFlags );
if( pIndex->DiskFile == FS_ERROR )
{
if( !pError )
{
pError = hb_errNew();
hb_errPutGenCode( pError, EG_OPEN );
hb_errPutSubCode( pError, 1003 );
hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) );
hb_errPutFileName( pError, szFileName );
hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT );
}
bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY );
}
else
bRetry = FALSE;
} while( bRetry );
if( pError )
hb_errRelease( pError );
if( pIndex->DiskFile == FS_ERROR )
{
ntxOrderListClear( pArea );
hb_xfree( szFileName );
return FAILURE;
}
if( hb_ntxHeaderLoad( pIndex, pFileName->szName ) == FAILURE )
{
hb_xfree( pIndex );
hb_xfree( szFileName );
hb_xfree( pFileName );
hb_fsClose( pIndex->DiskFile );
return FAILURE;
}
pIndex->IndexName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 );
strncpy( pIndex->IndexName, szFileName, _POSIX_PATH_MAX );
if( pArea->lpNtxIndex )
{
pIndex->TagRoot++;
pIndexNext = pArea->lpNtxIndex;
while( pIndexNext->pNext )
{
pIndex->TagRoot++;
pIndexNext = pIndexNext->pNext;
}
pIndexNext->pNext = pIndex;
}
else
{
pArea->lpNtxIndex = pIndex;
}
if( !pArea->lpCurIndex )
pArea->lpCurIndex = pIndex;
hb_xfree( szFileName );
hb_xfree( pFileName );
return SUCCESS;
}
static ERRCODE ntxOrderListClear( NTXAREAP pArea )
{
LPNTXINDEX pIndex, pIndexNext;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderListClear(%p)", pArea));
pIndex = pArea->lpNtxIndex;
while( pIndex )
{
pIndexNext = pIndex->pNext;
hb_ntxIndexFree( pIndex );
pIndex = pIndexNext;
}
pArea->lpNtxIndex = NULL;
pArea->lpCurIndex = NULL;
return SUCCESS;
}
static ERRCODE ntxOrderListFocus( NTXAREAP pArea, LPDBORDERINFO pOrderInfo )
{
LPNTXINDEX pIndex;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderListFocus(%p, %p)", pArea, pOrderInfo));
hb_itemPutNI( pOrderInfo->itmResult, (pArea->lpCurIndex)? pArea->lpCurIndex->TagRoot:0 );
if( hb_itemType( pOrderInfo->itmOrder ) != HB_IT_STRING &&
hb_itemGetNI( pOrderInfo->itmOrder ) == 0 )
pArea->lpCurIndex = NULL;
else
{
pIndex = ntxFindIndex( pArea, pOrderInfo->itmOrder );
if( pIndex )
pArea->lpCurIndex = pIndex;
}
return SUCCESS;
}
static ERRCODE ntxOrderListRebuild( NTXAREAP pArea )
{
LPNTXINDEX lpIndex, lpIndexTmp;
HB_TRACE(HB_TR_DEBUG, ("ntxOrderListRebuild(%p)", pArea));
lpIndex = pArea->lpNtxIndex;
lpIndexTmp = pArea->lpCurIndex;
pArea->fValidBuffer = TRUE;
while( lpIndex )
{
hb_fsSeek( lpIndex->DiskFile, NTXBLOCKSIZE, FS_SET );
hb_fsWrite( lpIndex->DiskFile, NULL, 0 );
hb_ntxIndexCreate( lpIndex );
hb_fsSeek( lpIndex->DiskFile , 0 , 0 );
lpIndex->CompoundTag->TagBlock =
hb_fsSeek( lpIndex->DiskFile, 0, SEEK_END ) - 1024;
lpIndex = lpIndex->pNext;
}
pArea->lpCurIndex = lpIndexTmp;
return SELF_GOTOP( ( AREAP ) pArea );
}
static ERRCODE ntxClose( NTXAREAP pArea )
{
HB_TRACE(HB_TR_DEBUG, ("ntxClose(%p)", pArea));
ntxOrderListClear( pArea );
return SUPER_CLOSE( ( AREAP ) pArea );
}
static ERRCODE ntxLock( NTXAREAP pArea, LPDBLOCKINFO pLockInfo )
{
HB_TRACE(HB_TR_DEBUG, ("ntxLock(%p, %p)", pArea, pLockInfo));
if( SUPER_LOCK( ( AREAP ) pArea, pLockInfo ) )
{
LPNTXINDEX lpIndex;
if( pLockInfo->uiMethod == DBLM_FILE )
{
lpIndex = pArea->lpNtxIndex;
while( lpIndex )
{
pArea->lpCurIndex = lpIndex;
/* First 512 bytes of index file are blocked.
I don't sure, is it right - should be checked.
= Alexander Kresin =
*/
if( !hb_fsLock( lpIndex->DiskFile, 0, 512, FL_LOCK ) )
{
ntxUnLock( pArea,0 );
return FAILURE;
}
lpIndex = lpIndex->pNext;
}
}
return SUCCESS;
}
else
return FAILURE;
}
static ERRCODE ntxUnLock( NTXAREAP pArea, ULONG ulRecNo )
{
BOOL fFLocked;
HB_TRACE(HB_TR_DEBUG, ("ntxUnLock(%p, %lu)", pArea, ulRecNo));
fFLocked = pArea->fFLocked;
if( SUPER_UNLOCK( ( AREAP ) pArea, ulRecNo ) )
{
LPNTXINDEX lpIndex;
if( fFLocked )
{
lpIndex = pArea->lpNtxIndex;
while( lpIndex )
{
pArea->lpCurIndex = lpIndex;
hb_fsLock( lpIndex->DiskFile, 0, 512, FL_UNLOCK );
lpIndex = lpIndex->pNext;
}
}
return SUCCESS;
}
else
return FAILURE;
}
static RDDFUNCS ntxTable = { ntxBof,
ntxEof,
ntxFound,
( DBENTRYP_V ) ntxGoBottom,
( DBENTRYP_UL ) ntxGoTo,
ntxGoToId,
( DBENTRYP_V ) ntxGoTop,
( DBENTRYP_BIB ) ntxSeek,
ntxSkip,
ntxSkipFilter,
( DBENTRYP_L ) ntxSkipRaw,
ntxAddField,
( DBENTRYP_B ) ntxAppend,
ntxCreateFields,
ntxDeleteRec,
ntxDeleted,
ntxFieldCount,
ntxFieldDisplay,
ntxFieldInfo,
ntxFieldName,
ntxFlush,
ntxGetRec,
ntxGetValue,
ntxGetVarLen,
ntxGoCold,
ntxGoHot,
ntxPutRec,
( DBENTRYP_SI ) ntxPutValue,
ntxRecall,
ntxRecCount,
ntxRecInfo,
ntxRecNo,
ntxSetFieldsExtent,
ntxAlias,
( DBENTRYP_V ) ntxClose,
ntxCreate,
ntxInfo,
ntxNewArea,
ntxOpen,
ntxRelease,
( DBENTRYP_SP ) ntxStructSize,
ntxSysName,
ntxEval,
( DBENTRYP_V ) ntxPack,
ntPackRec,
ntxSort,
ntxTrans,
ntxTransRec,
( DBENTRYP_V ) ntxZap,
ntxchildEnd,
ntxchildStart,
ntxchildSync,
ntxsyncChildren,
ntxclearRel,
ntxforceRel,
ntxrelArea,
ntxrelEval,
ntxrelText,
ntxsetRel,
( DBENTRYP_OI ) ntxOrderListAdd,
( DBENTRYP_V ) ntxOrderListClear,
ntxOrderListDelete,
( DBENTRYP_OI ) ntxOrderListFocus,
( DBENTRYP_V ) ntxOrderListRebuild,
ntxOrderCondition,
( DBENTRYP_VOC ) ntxOrderCreate,
ntxOrderDestroy,
( DBENTRYP_OII ) ntxOrderInfo,
ntxClearFilter,
ntxClearLocate,
ntxClearScope,
ntxCountScope,
ntxFilterText,
ntxScopeInfo,
ntxSetFilter,
ntxSetLocate,
ntxSetScope,
ntxSkipScope,
ntxCompile,
ntxError,
ntxEvalBlock,
ntxRawLock,
( DBENTRYP_VL ) ntxLock,
( DBENTRYP_UL ) ntxUnLock,
ntxCloseMemFile,
ntxCreateMemFile,
ntxGetValueFile,
ntxOpenMemFile,
ntxPutValueFile,
ntxReadDBHeader,
ntxWriteDBHeader,
ntxWhoCares
};
HB_FUNC(_DBFNTX )
{
}
HB_FUNC( DBFNTX_GETFUNCTABLE )
{
RDDFUNCS * pTable;
USHORT * uiCount;
uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) );
* uiCount = RDDFUNCSCOUNT;
pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) );
if( pTable )
hb_retni( hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBF" ) );
else
hb_retni( FAILURE );
}