diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 4704655339..74d006e5b5 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,9 +1,17 @@ +20000415-17:38 GMT+2 Maurilio Longo + + * source/rdd/dbfcdx/dbfcdx1.c + % added Bruno Contero's file (from message on Harblour list), quick and dirty hack to make it + compile (at least) lots of warnings and no tests made + * include/hbapirdd.h + % added Bruno Contero's changes to make dbfcdx1.c happy. + 20000415-15:07 GMT+1 Victor Szakats * source/rtl/net.c - + NETNAME() now works with BCC16 (and any other real mode DOS compiler for + + NETNAME() now works with BCC16 (and any other real mode DOS compiler for that matter). - - Commented out for DJGPP. I leave this for someone who has the nerve + - Commented out for DJGPP. I leave this for someone who has the nerve to tweak it for PM. * bin/bld.bat @@ -26,7 +34,7 @@ - bin/bld_b32o.bat - bin/bld_b32w.bat - Removed. Use SET CFLAGS=-tW and call bld_b32.bat for the bld_b32w.bat - functionality, if you need it. + functionality, if you need it. bld_b32o.bat was specific and not working anyway. 20000415-12:38 GMT+1 Victor Szakats @@ -68,7 +76,7 @@ * source/vm/classes.c ! __CLSINSTSUPER() fix for error recovery code path. - ! The return value of some Harbour functions made consistent on error + ! The return value of some Harbour functions made consistent on error cases (return 0 instead of NIL). 20000415-05:12 GMT+1 Victor Szakats @@ -233,10 +241,10 @@ * source/include/hbexprb.c + Added following defines: - #define HB_COMP_ERR_INVALID_JUMP 45 - #define HB_COMP_ERR_INVALID_JUMPTRUE 46 - #define HB_COMP_ERR_INVALID_JUMPFALSE 47 - #define HB_COMP_ERR_JUMP_NOT_FOUND 48 + #define HB_COMP_ERR_INVALID_JUMP 45 + #define HB_COMP_ERR_INVALID_JUMPTRUE 46 + #define HB_COMP_ERR_INVALID_JUMPFALSE 47 + #define HB_COMP_ERR_JUMP_NOT_FOUND 48 20000414-03:08 GMT+1 Victor Szakats @@ -524,14 +532,14 @@ *source/rtl/gtapi.c *hb_gtWwriteCon() fixed to correctly support LF characters in - U*nix environment (LF should move carriage return to the leftmost - column) + U*nix environment (LF should move carriage return to the leftmost + column) *source/rtl/gtcrs/gtcrs.c *updated to return multi-character keycodes that are not mapped to Clipper INKEY() keycodes - *full color support - *scrolling up-down + *full color support + *scrolling up-down 20000411-13:12 GMT+1 Victor Szakats @@ -775,7 +783,7 @@ % hb_verCompiler() some optimizations and streamlining mainly around GCC flavours. + MS "Visual" detection. - + * source/vm/fm.c * include/hbsetup.h * HB_FM_STATISTICS moved to the setup header. @@ -807,7 +815,7 @@ 20000408-20:45 GMT+1 Ryszard Glab *source/rtl/gtcrs/gtcrs.c - * added key mapping using terminfo database + * added key mapping using terminfo database 20000408-14:11 DST Paul Tucker * source/rtl/dir.c diff --git a/harbour/include/hbapirdd.h b/harbour/include/hbapirdd.h index 005d89bace..0f051d11fd 100644 --- a/harbour/include/hbapirdd.h +++ b/harbour/include/hbapirdd.h @@ -161,6 +161,8 @@ extern void hb_rddShutDown( void ); */ struct _RDDFUNCS; struct _AREA; +struct _TAGINFO; +struct _INDEXINFO; typedef struct _FILEINFO @@ -177,16 +179,93 @@ typedef struct _FILEINFO typedef FILEINFO * LPFILEINFO; +typedef struct _KEYINFO +{ + PHB_ITEM pItem; + LONG Tag; + LONG Xtra; + struct _KEYINFO * pNext; +} KEYINFO; + +typedef KEYINFO * LPKEYINFO; + + +typedef struct _PAGEINFO +{ + LONG Page; + LONG Left; + LONG Right; + BOOL Changed; + BOOL NewRoot; + BOOL LastEntry; + BOOL Reload; + BOOL ChkBOF; + BOOL ChkEOF; + BYTE PageType; + LONG RNMask; + BYTE ReqByte; + BYTE RNBits; + BYTE DCBits; + BYTE TCBits; + BYTE DCMask; + BYTE TCMask; + USHORT Space; + LPKEYINFO pKeys; + USHORT uiKeys; + SHORT CurKey; + struct _PAGEINFO * Owner; + struct _PAGEINFO * Child; + struct _TAGINFO * TagParent; +} PAGEINFO; + +typedef PAGEINFO * LPPAGEINFO; + + +typedef struct _TAGINFO +{ + char * TagName; + char * KeyExpr; + char * ForExpr; + PHB_ITEM pKeyItem; + PHB_ITEM pForItem; + BOOL AscendKey; + BOOL UniqueKey; + BOOL TagChanged; + BOOL TagBOF; + BOOL TagEOF; + BYTE KeyType; + BYTE OptFlags; + LONG TagBlock; + LONG RootBlock; + USHORT KeyLength; + USHORT MaxKeys; + LPKEYINFO CurKeyInfo; + LPPAGEINFO RootPage; + struct _INDEXINFO * Owner; + struct _TAGINFO * pNext; +} TAGINFO; + +typedef TAGINFO * LPTAGINFO; + + typedef struct _INDEXINFO { - struct _INDEXINFO * pNext; /* The next index in the list */ + char * IndexName; + BOOL Exact; + BOOL Corrupted; + LONG TagRoot; + LONG NextAvail; + struct _AREA * Owner; + FHANDLE DiskFile; + LPTAGINFO CompoundTag; + LPTAGINFO TagList; + struct _INDEXINFO * pNext; /* The next index in the list */ } INDEXINFO; typedef INDEXINFO * LPINDEXINFO; - /* * DBFIELDINFO * ----------- @@ -239,6 +318,7 @@ typedef struct BYTE * bRecord; /* Buffer of the data */ BOOL fValidBuffer; /* State of buffer */ BOOL fHasMemo; /* Work Area with Memo fields */ + BOOL fHasMDX; /* MDX or CDX indexes */ ULONG ulRecNo; /* Current record */ ULONG ulNextBlock; /* Next block for memos */ BOOL fExclusive; /* Share the file */ diff --git a/harbour/source/rdd/dbfcdx/dbfcdx1.c b/harbour/source/rdd/dbfcdx/dbfcdx1.c index 398ffb93a4..45df392756 100644 --- a/harbour/source/rdd/dbfcdx/dbfcdx1.c +++ b/harbour/source/rdd/dbfcdx/dbfcdx1.c @@ -36,14 +36,54 @@ #define SUPERTABLE ( &cdxSuper ) #include +#include #include "hbapi.h" -#include "hbinit.h" #include "hbapiitm.h" +#include "hbinit.h" #include "hbapirdd.h" #include "rddsys.ch" #include "hbapierr.h" +#include "hbdate.h" #include "hbapilng.h" +#include "hbvm.h" +/* +#define SUPERTABLE ( &cdxSuper ) + +#include +#include "extend.h" +#include "init.h" +#include "itemapi.h" +#include "rddapi.h" +#include "rddsys.ch" +#include "errorapi.h" +#include "ctoharb.h" +#include "langapi.h" +*/ + +#define LOCK_START 0x40000000L +#define LOCK_APPEND 0x7FFFFFFEL +#define LOCK_FILE 0x3FFFFFFFL +#define MEMO_BLOCK 64 +#define CDX_MAX_KEY 240 +#define CDX_MAX_TAG_NAME_LEN 10 +#define CDX_BLOCK_SIZE 512 +#define CDX_INTERNAL_SPACE 500 +#define CDX_EXTERNAL_SPACE 488 +#define CDX_MAX_REC_NUM 0x7FFFFFFFL +#define CDX_IGNORE_REC_NUM -1 +#define PAGE_ROOT 1 +#define PAGE_NODE 2 +#define PAGE_LEAF 3 +#define TOP_RECORD 1 +#define BTTM_RECORD 2 +#define PREV_RECORD 3 +#define NEXT_RECORD 4 +#define SORT_CHUNK_LIMIT 16384 +#define SORT_ACTIVE_LIST 0 +#define SORT_END_OF_KEY 1 +#define SORT_END_OF_WORD 2 +#define SORT_STACK_OF_CHAR 3 typedef struct _DBFHEADER { @@ -55,7 +95,7 @@ typedef struct _DBFHEADER USHORT uiHeaderLen; USHORT uiRecordLen; BYTE bReserved1[ 16 ]; - BYTE bHasTag; + BYTE bHasMDX; BYTE bReserved2[ 3 ]; } DBFHEADER; @@ -95,35 +135,226 @@ typedef struct _DBFMEMO typedef DBFMEMO * LPDBFMEMO; -HB_FUNC( _DBFCDX ); -HB_FUNC( DBFCDX_GETFUNCTABLE ); +typedef struct _CDXHEADER +{ + LONG Root; + LONG FreePtr; + LONG ChgFlag; + USHORT Key_Lgth; + BYTE IndexOpts; + BYTE IndexSig; + BYTE Reserve3[ 486 ]; + USHORT AscDesc; + USHORT Reserve4; + USHORT ForExpLen; + USHORT Reserve5; + USHORT KeyExpLen; + BYTE KeyPool[ CDX_BLOCK_SIZE ]; +} CDXHEADER; + +typedef CDXHEADER * LPCDXHEADER; + + +typedef struct +{ + USHORT FreeSpace; + LONG RecNumMask; + BYTE DupCntMask; + BYTE TrlCntMask; + BYTE RecNumBits; + BYTE DupCntBits; + BYTE TrlCntBits; + BYTE ShortBytes; + BYTE ExtData[ CDX_EXTERNAL_SPACE ]; +} CDXEXTERNAL; + + +typedef struct +{ + BYTE IntData[ CDX_INTERNAL_SPACE ]; +} CDXINTERNAL; + + +typedef struct _CDXDATA +{ + USHORT Node_Atr; + USHORT Entry_Ct; + LONG Left_Ptr; + LONG Rght_Ptr; + union + { + CDXEXTERNAL External; + CDXINTERNAL Internal; + } cdxu; +} CDXDATA; + +typedef CDXDATA * LPCDXDATA; + + +typedef struct +{ + char Character; + BYTE NUse; + USHORT WordArray; + USHORT Fill02; + USHORT LevelLink; +} SORT_A; + + +typedef struct +{ + BYTE Fill03[ 4 ]; + char ChrStack[ 4 ]; +} SORT_B; + + +typedef struct +{ + LONG Fill04; + LONG ChrFill; +} SORT_C; + + +typedef struct +{ + union + { + SORT_A A; + SORT_B B; + SORT_C C; + } sortu; +} SORTDATA; + +typedef SORTDATA * LPSORTDATA; + + +typedef struct +{ + LONG WordCount; + LONG RootLink; + LONG LevelPtr; + LONG PriorPtr; + LONG KeyTot; + LONG KeyCnt; + LONG LastTag; + LONG * ChunkList; + BYTE * SortBuffer; + USHORT SortChunk; + USHORT NodeLimit; + USHORT NodeMask; + USHORT NodeShift; + USHORT ChunkSize; + USHORT ChunkLimit; + USHORT ChunkCur; + USHORT NodeCur; + USHORT KeySize; + USHORT WCur; + BOOL Unique; + BOOL Ascend; + BOOL Closing; + char WPch[ 256 ]; + SORTDATA * WAdr; + LPTAGINFO CurTag; + LPCDXDATA NodeList[ 32 ]; + LPKEYINFO KeyWork; + LPKEYINFO LastKey; +} SORTINFO; + +typedef SORTINFO * LPSORTINFO; + + +HB_FUNC(_DBFCDX); +HB_FUNC(DBFCDX_GETFUNCTABLE); HB_INIT_SYMBOLS_BEGIN( dbfcdx1__InitSymbols ) -{ "_DBFCDX", HB_FS_PUBLIC, HB_FUNCNAME( _DBFCDX ), NULL }, -{ "DBFCDX_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME( DBFCDX_GETFUNCTABLE ), NULL } +{ "_DBFCDX", HB_FS_PUBLIC, HB_FUNCNAME(_DBFCDX), NULL }, +{ "DBFCDX_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME(DBFCDX_GETFUNCTABLE), NULL } HB_INIT_SYMBOLS_END( dbfcdx1__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_dbfcdx1__InitSymbols = dbfcdx1__InitSymbols; - #pragma data_seg() -#elif ! defined(__GNUC__) +#if ! defined(__GNUC__) && ! defined(_MSC_VER) #pragma startup dbfcdx1__InitSymbols #endif -#define LOCK_START 0x40000000L -#define LOCK_APPEND 0x7FFFFFFEL -#define LOCK_FILE 0x3FFFFFFFL -#define MEMO_BLOCK 64 -#define CDX_MAX_KEY 240 - static RDDFUNCS cdxSuper = { 0 }; -static BOOL hb_nltoa( LONG lValue, char * szBuffer, USHORT uiLen ) +ERRCODE cdxOrderListClear( AREAP pArea ); + +LPKEYINFO hb_cdxKeyNew( void ); +void hb_cdxKeyFree( LPKEYINFO pKey ); +int hb_cdxKeyCompare( LPKEYINFO pKey1, LPKEYINFO pKey2, USHORT * EndPos, BOOL Exact ); + +LPTAGINFO hb_cdxTagNew( LPINDEXINFO PIF, char * ITN, LONG TagHdr ); +void hb_cdxTagFree( LPTAGINFO pTag ); +void hb_cdxTagIndexTagNew( LPTAGINFO pTag, char * KeyExp, PHB_ITEM pKeyItem, + BYTE bType, USHORT uiLen, char * ForExp, + PHB_ITEM pForItem, BOOL Ascnd, BOOL Uniq ); +void hb_cdxTagDoIndex( LPTAGINFO pTag ); +void hb_cdxTagEmptyIndex( LPTAGINFO pTag ); +void hb_cdxTagTagStore( LPTAGINFO pTag ); +void hb_cdxTagTagOpen( LPTAGINFO pTag, BYTE bCode ); +void hb_cdxTagTagClose( LPTAGINFO pTag ); +LONG hb_cdxTagNewRoot( LPTAGINFO pTag ); +void hb_cdxTagPageLoad( LPTAGINFO pTag, LPPAGEINFO pPage ); +void hb_cdxTagKeyRead( LPTAGINFO pTag, BYTE bTypRead ); +void hb_cdxTagKeyAdd( LPTAGINFO pTag, LPKEYINFO pKey ); +void hb_cdxTagPageStore( LPTAGINFO pTag, LPPAGEINFO PIK ); +void hb_cdxTagExtNodeWrite( LPTAGINFO pTag, LONG PN, LPCDXDATA pData, LPPAGEINFO PIK ); +USHORT hb_cdxTagFillExternalNode( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO PIK, + USHORT kcnt, USHORT ck, LPKEYINFO * p ); +void hb_cdxTagExtNodeBuild( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO pPage ); +void hb_cdxTagTagLoad( LPTAGINFO pTag ); +void hb_cdxTagSetRoot( LPTAGINFO pTag, LPPAGEINFO PIK ); +void hb_cdxTagIntNodeWrite( LPTAGINFO pTag, LONG PN, LPCDXDATA pData, LPPAGEINFO PIK ); +USHORT hb_cdxTagFillInternalNode( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO PIK, + USHORT kcnt, USHORT ck, LPKEYINFO * p ); +void hb_cdxTagIntNodeBuild( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO pPage ); +LONG hb_cdxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey ); + +LPPAGEINFO hb_cdxPageNew( LPTAGINFO PIT, LPPAGEINFO PIK, LONG FilePosn ); +void hb_cdxPageFree( LPPAGEINFO pPage ); +BOOL hb_cdxPageReadTopKey( LPPAGEINFO pPage ); +BOOL hb_cdxPageReadBottomKey( LPPAGEINFO pPage ); +int hb_cdxPageSeekKey( LPPAGEINFO pPage, LONG lBlock, LPKEYINFO pKey, BOOL bExact ); +void hb_cdxPageInsertKey( LPPAGEINFO pPage, LPKEYINFO pKey, BOOL bAddAfter ); +void hb_cdxPagePageStore( LPPAGEINFO pPage ); +BOOL hb_cdxPageReadNextKey( LPPAGEINFO pPage ); +LPKEYINFO hb_cdxPageGetKey( LPPAGEINFO pPage, USHORT uiKey ); +void hb_cdxPagePageLoad( LPPAGEINFO pPage ); +int hb_cdxPageRetrieveKey( LPPAGEINFO pPage, LPKEYINFO pKey ); +void hb_cdxPageAddNodeKey( LPPAGEINFO pPage, LPKEYINFO pKey ); +int hb_cdxPageSeekNodeTag( LPPAGEINFO pPage, LONG Tag ); +BOOL hb_cdxPageGetChild( LPPAGEINFO pPage, LONG Tag ); +void hb_cdxPageDeleteKey( LPPAGEINFO pPage ); + +LPINDEXINFO hb_cdxIndexNew( AREAP pArea ); +void hb_cdxIndexFree( LPINDEXINFO pIndex ); +LONG hb_cdxIndexGetAvailPage( LPINDEXINFO pIndex ); +void hb_cdxIndexResetAvailPage( LPINDEXINFO pIndex ); +void hb_cdxIndexPageRead( LPINDEXINFO pIndex, LONG lPos, void * pBuffer, USHORT uiSize ); +void hb_cdxIndexPageWrite( LPINDEXINFO pIndex, LONG lPos, void * pBuffer, USHORT uiSize ); +void hb_cdxIndexAddTag( LPINDEXINFO pIndex, char * szTagName, char * szKeyExp, + PHB_ITEM pKeyItem, BYTE bType, USHORT uiLen, char * szForExp, + PHB_ITEM pForItem, BOOL bAscending, BOOL bUnique ); + +LPSORTINFO hb_cdxSortNew( LPTAGINFO pTag, BOOL bUnique ); +void hb_cdxSortFree( LPSORTINFO pSort ); +void hb_cdxSortLinkNew( LPSORTINFO pSort, LONG * NewLink ); +void hb_cdxSortGetNewChunk( LPSORTINFO pSort ); +void hb_cdxSortInsertWord( LPSORTINFO pSort, LONG Tag, char * Value ); +void hb_cdxSortStuffKey( LPSORTINFO pSort, LPSORTDATA * wx ); +void hb_cdxSortGetNode( LPSORTINFO pSort, char Character, LONG * NewLink ); +LPSORTDATA hb_cdxSortLinkGet( LPSORTINFO pSort, LONG Value ); +void hb_cdxSortDisplayWord( LPSORTINFO pSort ); +void hb_cdxSortRecurseDict( LPSORTINFO pSort, LONG WPtr, LONG WBgn ); +void hb_cdxSortSendWord( LPSORTINFO pSort, char * Value ); +void hb_cdxSortOutputWord( LPSORTINFO pSort, LONG Tag, char * Value ); +void hb_cdxSortAddToNode( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link, + LPKEYINFO Value ); +void hb_cdxSortAddExternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link, + LPKEYINFO Value ); +void hb_cdxSortAddInternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link, + LPKEYINFO Value ); + +static BOOL hb_cdxltoa( LONG lValue, char * szBuffer, USHORT uiLen ) { LONG lAbsNumber; int iCount, iPos; @@ -172,18 +403,28 @@ static BOOL hb_nltoa( LONG lValue, char * szBuffer, USHORT uiLen ) static ULONG hb_cdxSwapBytes( ULONG ulValue ) { - BYTE * pValue, pByte; + BYTE * pValue, * pNewValue; + ULONG ulNewValue; HB_TRACE(HB_TR_DEBUG, ("hb_cdxSwapBytes(%lu)", ulValue)); pValue = ( BYTE * ) &ulValue; - pByte = pValue[ 0 ]; - pValue[ 0 ] = pValue[ 3 ]; - pValue[ 3 ] = pByte; - pByte = pValue[ 1 ]; - pValue[ 1 ] = pValue[ 2 ]; - pValue[ 2 ] = pByte; - return ulValue; + pNewValue = ( BYTE * ) &ulNewValue; + pNewValue[ 0 ] = pValue[ 3 ]; + pNewValue[ 1 ] = pValue[ 2 ]; + pNewValue[ 2 ] = pValue[ 1 ]; + pNewValue[ 3 ] = pValue[ 0 ]; + return ulNewValue; +} + +static LONG hb_cdxMakeMask( BYTE bByte ) +{ + BYTE bCount; + LONG lMask; + + for( lMask = 0, bCount = 1; bCount <= bByte; bCount++, + lMask = ( lMask << 1 ) + 1 ); + return lMask; } static void hb_cdxReadMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG lMemoBlock ) @@ -203,7 +444,7 @@ static void hb_cdxReadMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG lMemoBlock ) pMemo->pData = ( BYTE * ) hb_xrealloc( pMemo->pData, ulSpaceUsed + 1 ); else pMemo->pData = ( BYTE * ) hb_xgrab( ulSpaceUsed + 1 ); - pMemo->uiLen = ( USHORT ) ulSpaceUsed; + pMemo->uiLen = ulSpaceUsed; } hb_fsRead( pArea->lpDataInfo->pNext->hFile, pMemo->pData, pMemo->uiLen ); } @@ -268,6 +509,1997 @@ static BOOL hb_cdxWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) return TRUE; } +static LPKEYINFO hb_cdxKeyNew() +{ + LPKEYINFO pKey; + + pKey = ( LPKEYINFO ) hb_xgrab( sizeof( KEYINFO ) ); + pKey->pItem = hb_itemNew( NULL ); + pKey->Tag = pKey->Xtra = 0; + pKey->pNext = NULL; + return pKey; +} + +static void hb_cdxKeyFree( LPKEYINFO pKey ) +{ + hb_itemRelease( pKey->pItem ); + hb_xfree( pKey ); +} + +static int hb_cdxKeyCompare( LPKEYINFO pKey1, LPKEYINFO pKey2, USHORT * EndPos, BOOL Exact ) +{ + int iLimit, iResult; + + * EndPos = 0; + if( pKey2 == NULL || pKey2->pItem->item.asString.length == 0 ) + return 1; + if( pKey1 == NULL || pKey1->pItem->item.asString.length == 0 ) + return ( pKey2->pItem->item.asString.length == 0 ) ? 0: -1; + switch( hb_itemType( pKey1->pItem ) ) + { + case HB_IT_STRING: + iLimit = ( pKey1->pItem->item.asString.length > + pKey2->pItem->item.asString.length ) ? + pKey2->pItem->item.asString.length : + pKey1->pItem->item.asString.length; + do + { + iResult = pKey1->pItem->item.asString.value[ * EndPos ] - + pKey2->pItem->item.asString.value[ * EndPos ]; + * EndPos += 1; + } while( iResult == 0 && * EndPos < iLimit ); + if( iResult == 0 ) + { + * EndPos += 1; + iResult = pKey1->pItem->item.asString.length - + pKey2->pItem->item.asString.length; + } + if( iResult < 0 && * EndPos > pKey1->pItem->item.asString.length && !Exact ) + iResult = 0; + break; + + default: + printf( "hb_cdxKeyCompare()" ); + } + if( iResult < 0 ) + return -1; + else if( iResult > 0 ) + return 1; + else + return 0; +} + +static LPTAGINFO hb_cdxTagNew( LPINDEXINFO PIF, char * ITN, LONG TagHdr ) +{ + LPTAGINFO pTag; + + pTag = ( LPTAGINFO ) hb_xgrab( sizeof( TAGINFO ) ); + memset( pTag, 0, sizeof( TAGINFO ) ); + pTag->TagName = ( char * ) hb_xgrab( CDX_MAX_TAG_NAME_LEN + 1 ); + hb_strncpyUpper( pTag->TagName, ITN, CDX_MAX_TAG_NAME_LEN ); + pTag->Owner = PIF; + pTag->AscendKey = TRUE; + pTag->KeyType = 'C'; + pTag->CurKeyInfo = hb_cdxKeyNew(); + if( TagHdr == -1 ) + { + pTag->TagBlock = hb_cdxIndexGetAvailPage( PIF ); + hb_cdxIndexGetAvailPage( PIF ); + pTag->TagChanged = TRUE; + } + else + { + pTag->TagBlock = TagHdr; + hb_cdxTagTagLoad( pTag ); + } + pTag->OptFlags = 0x60; + return pTag; +} + +static void hb_cdxTagFree( LPTAGINFO pTag ) +{ + if( pTag->RootPage != NULL ) + { + hb_cdxPageFree( pTag->RootPage ); + pTag->RootPage = NULL; + } + if( pTag->TagChanged ) + hb_cdxTagTagStore( pTag ); + if( pTag->TagName != NULL ) + hb_xfree( pTag->TagName ); + if( pTag->KeyExpr != NULL ) + hb_xfree( pTag->KeyExpr ); + 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->ForExpr != NULL ) + hb_xfree( pTag->ForExpr ); + if( pTag->pForItem != NULL ) + { + if( hb_itemType( pTag->pForItem ) != HB_IT_BLOCK ) + hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ) ); + hb_itemRelease( pTag->pForItem ); + } + hb_cdxKeyFree( pTag->CurKeyInfo ); + hb_xfree( pTag ); +} + +static void hb_cdxTagIndexTagNew( LPTAGINFO pTag, char * KeyExp, PHB_ITEM pKeyItem, + BYTE bType, USHORT uiLen, char * ForExp, + PHB_ITEM pForItem, BOOL Ascnd, BOOL Uniq ) +{ + CDXHEADER pHeader; + + if( KeyExp != NULL ) + { + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAX_KEY + 1 ); + hb_strncpyUpper( pTag->KeyExpr, KeyExp, CDX_MAX_KEY ); + } + pTag->pKeyItem = pKeyItem; + if( ForExp != NULL ) + { + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAX_KEY + 1 ); + hb_strncpyUpper( pTag->ForExpr, ForExp, CDX_MAX_KEY ); + } + pTag->pForItem = pForItem; + pTag->AscendKey = Ascnd; + pTag->UniqueKey = Uniq; + pTag->KeyType = bType; + pTag->KeyLength = uiLen; + pTag->MaxKeys = ( CDX_BLOCK_SIZE - 12 ) / ( uiLen + 8 ); + memset( &pHeader, 0, sizeof( CDXHEADER ) ); + hb_cdxIndexPageWrite( pTag->Owner, pTag->TagBlock, &pHeader, sizeof( CDXHEADER ) ); + hb_cdxTagDoIndex( pTag ); +} + +static void hb_cdxTagDoIndex( LPTAGINFO pTag ) +{ + ULONG ulRecNo; + BOOL bWhileOk; + LPSORTINFO pSort; + LPKEYINFO pKey; + HB_MACRO_PTR pMacro; + + if( pTag->OptFlags & 0x80 ) + hb_cdxTagEmptyIndex( pTag ); + else + { + pSort = hb_cdxSortNew( pTag, pTag->UniqueKey ); + pKey = hb_cdxKeyNew(); + for( ulRecNo = 1; ulRecNo <= pTag->Owner->Owner->lpExtendInfo->ulRecCount; ulRecNo++ ) + { + hb_fsSeek( pTag->Owner->Owner->lpDataInfo->hFile, + pTag->Owner->Owner->lpExtendInfo->uiHeaderLen + + ( ulRecNo - 1 ) * pTag->Owner->Owner->lpExtendInfo->uiRecordLen, + FS_SET ); + hb_fsRead( pTag->Owner->Owner->lpDataInfo->hFile, + pTag->Owner->Owner->lpExtendInfo->bRecord, + pTag->Owner->Owner->lpExtendInfo->uiRecordLen ); + 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 ); + } + else + { + pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); + hb_macroRun( pMacro ); + } + hb_itemCopy( pKey->pItem, &hb_stack.Return ); + switch( hb_itemType( pKey->pItem ) ) + { + case HB_IT_STRING: + hb_cdxSortInsertWord( pSort, ulRecNo, pKey->pItem->item.asString.value ); + break; + + default: + printf( "hb_cdxTagDoIndex( LPTAGINFO pTag )" ); + } + } + } + if( pSort->WordCount > 0 ) + hb_cdxSortDisplayWord( pSort ); + else + hb_cdxTagEmptyIndex( pTag ); + hb_cdxSortFree( pSort ); + hb_cdxKeyFree( pKey ); + } + pTag->TagChanged = TRUE; + hb_cdxTagTagStore( pTag ); +} + +static void hb_cdxTagEmptyIndex( LPTAGINFO pTag ) +{ + USHORT uiKeyLength, uiBitCount; + CDXDATA pData; + + pTag->RootBlock = hb_cdxIndexGetAvailPage( pTag->Owner ); + memset( &pData, 0, sizeof( CDXDATA ) ); + pData.Node_Atr = 3; + pData.Left_Ptr = pData.Rght_Ptr = -1; + uiKeyLength = pTag->KeyLength; + for( uiBitCount = 0; uiKeyLength; uiBitCount++, uiKeyLength >>= 1 ); + pData.cdxu.External.ShortBytes = 3; + pData.cdxu.External.RecNumBits = 24 - uiBitCount * 2; + pData.cdxu.External.RecNumMask = hb_cdxMakeMask( pData.cdxu.External.RecNumBits ); + pData.cdxu.External.FreeSpace = CDX_EXTERNAL_SPACE; + pData.cdxu.External.DupCntBits = pData.cdxu.External.TrlCntBits = uiBitCount; + pData.cdxu.External.DupCntMask = hb_cdxMakeMask( pData.cdxu.External.DupCntBits ); + pData.cdxu.External.TrlCntMask = hb_cdxMakeMask( pData.cdxu.External.TrlCntBits ); + hb_cdxIndexPageWrite( pTag->Owner, pTag->RootBlock, &pData, sizeof( CDXDATA ) ); +} + +static void hb_cdxTagTagStore( LPTAGINFO pTag ) +{ + USHORT uiForLen; + CDXHEADER pHeader; + + if( !pTag->TagChanged ) + return; + pTag->TagChanged = FALSE; + if( pTag->UniqueKey ) + pTag->OptFlags |= 0x01; + if( pTag->pForItem != NULL ) + pTag->OptFlags |= 0x08; + memset( &pHeader, 0, sizeof( CDXHEADER ) ); + pHeader.Root = pTag->RootBlock; + pHeader.Key_Lgth = pTag->KeyLength; + pHeader.IndexOpts = pTag->OptFlags; + pHeader.IndexSig = 1; + if( !pTag->AscendKey ) + pHeader.AscDesc = 1; + pHeader.Reserve4 = 1 + ( pTag->KeyExpr == NULL ? 0 : strlen( pTag->KeyExpr ) ); + pHeader.KeyExpLen = pHeader.Reserve4; + if( pTag->KeyExpr != NULL ) + strcpy( pHeader.KeyPool, pTag->KeyExpr ); + uiForLen = pTag->ForExpr == NULL ? 0 : strlen( pTag->ForExpr ); + if( uiForLen > 0 ) + { + pHeader.ForExpLen = uiForLen + 1; + strcpy( pHeader.KeyPool + pHeader.KeyExpLen, pTag->ForExpr ); + } + else + pHeader.ForExpLen = 1; + hb_cdxIndexPageWrite( pTag->Owner, pTag->TagBlock, &pHeader, sizeof( CDXHEADER ) ); +} + +static void hb_cdxTagTagOpen( LPTAGINFO pTag, BYTE bCode ) +{ + hb_cdxTagTagClose( pTag ); + pTag->RootBlock = hb_cdxTagNewRoot( pTag ); + pTag->RootPage = hb_cdxPageNew( pTag, NULL, pTag->RootBlock ); + if( bCode == 2 ) + return; + if( bCode == 0 ) + hb_cdxTagKeyRead( pTag, TOP_RECORD ); + else + printf( "hb_cdxTagTagOpen()" ); +} + +static void hb_cdxTagTagClose( LPTAGINFO pTag ) +{ + if( pTag->RootPage != NULL ) + { + hb_cdxPageFree( pTag->RootPage ); + pTag->RootPage = NULL; + } + if( pTag->TagChanged ) + hb_cdxTagTagStore( pTag ); +} + +static LONG hb_cdxTagNewRoot( LPTAGINFO pTag ) +{ + CDXHEADER pHeader; + + hb_cdxIndexPageRead( pTag->Owner, pTag->TagBlock, &pHeader, sizeof( CDXHEADER ) ); + return pHeader.Root; +} + +static void hb_cdxTagPageLoad( LPTAGINFO pTag, LPPAGEINFO pPage ) +{ + CDXDATA pData; + LPKEYINFO pKey; + + hb_cdxIndexPageRead( pTag->Owner, pPage->Page, &pData, sizeof( CDXDATA ) ); + if( pData.Node_Atr > 1 ) + pPage->PageType = PAGE_LEAF; + else + pPage->PageType = PAGE_NODE; + pPage->Left = pData.Left_Ptr; + pPage->Right = pData.Rght_Ptr; + if( pData.Entry_Ct > 0 ) + { + if( pPage->PageType == PAGE_LEAF ) + hb_cdxTagExtNodeBuild( pTag, &pData, pPage ); + else + hb_cdxTagIntNodeBuild( pTag, &pData, pPage ); + } + pPage->Changed = FALSE; +} + +static void hb_cdxTagKeyRead( LPTAGINFO pTag, BYTE bTypRead ) +{ + pTag->CurKeyInfo->Tag = 0; + if( pTag->RootPage == NULL ) + return; + 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; + switch( bTypRead ) + { + case TOP_RECORD: + hb_cdxTagTagOpen( pTag, 2 ); + if( pTag->pForItem != NULL ) + printf( "hb_cdxTagKeyRead()" ); + else + pTag->TagBOF = !hb_cdxPageReadTopKey( pTag->RootPage ); + if( pTag->pForItem != NULL ) + printf( "hb_cdxTagTestRange()" ); + if( pTag->TagEOF ) + pTag->TagBOF = TRUE; + pTag->TagEOF = pTag->TagBOF; + break; + + case BTTM_RECORD: + hb_cdxTagTagOpen( pTag, 2 ); + if( pTag->pForItem != NULL ) + printf( "hb_cdxTagKeyRead()" ); + else + pTag->TagEOF = !hb_cdxPageReadBottomKey( pTag->RootPage ); + if( pTag->pForItem != NULL ) + { + printf( "hb_cdxTagTestRange()" ); + } + if( pTag->TagBOF ) + pTag->TagEOF = TRUE; + pTag->TagBOF = pTag->TagEOF; + break; + + case NEXT_RECORD: + while( TRUE ) + { + pTag->TagEOF = !hb_cdxPageReadNextKey( pTag->RootPage ); + if( pTag->pForItem != NULL ) + printf( "hb_cdxTagKeyRead()" ); + else + break; + } + break; + } + if( pTag->TagBOF || pTag->TagEOF ) + { + if( !pTag->AscendKey ) + { + pTag->CurKeyInfo->Tag = pTag->TagEOF; + pTag->TagEOF = pTag->TagBOF; + pTag->TagBOF = ( BOOL ) pTag->CurKeyInfo->Tag; + } + pTag->CurKeyInfo->Tag = 0; + } +} + +static void hb_cdxTagKeyAdd( LPTAGINFO pTag, LPKEYINFO pKey ) +{ + int iSeek; + LONG lOldXtra; + LPKEYINFO pNewKey; + + lOldXtra = pKey->Xtra; + pKey->Xtra = pKey->Tag; + hb_cdxTagTagOpen( pTag, 0 ); + pNewKey = hb_cdxKeyNew(); + hb_itemCopy( pNewKey->pItem, pKey->pItem ); + pNewKey->Tag = pKey->Tag; + pNewKey->Xtra = pKey->Xtra; + if( pTag->KeyType == 'C' ) + { + while( pNewKey->pItem->item.asString.length > 0 && + pNewKey->pItem->item.asString.value[ pNewKey->pItem->item.asString.length - 1 ] == ' ' ) + pNewKey->pItem->item.asString.length--; + pNewKey->pItem->item.asString.value[ pNewKey->pItem->item.asString.length ] = NULL; + } + pTag->TagBOF = pTag->TagEOF = FALSE; + iSeek = hb_cdxPageSeekKey( pTag->RootPage, pNewKey->Tag, pNewKey, TRUE ); + if( iSeek < 1 ) + { + hb_cdxPageInsertKey( pTag->RootPage, pNewKey, FALSE ); + hb_cdxTagTagOpen( pTag, 0 ); + hb_cdxPageSeekKey( pTag->RootPage, pNewKey->Tag, pNewKey, FALSE ); + iSeek = hb_cdxPageRetrieveKey( pTag->RootPage, pTag->CurKeyInfo ); + if( !pTag->AscendKey ) + { + pTag->TagBOF = ( iSeek & 2 ); + pTag->TagEOF = ( iSeek & 1 ); + } + else + { + pTag->TagBOF = ( iSeek & 1 ); + pTag->TagEOF = ( iSeek & 2 ); + } + } + else + { + if( !pTag->AscendKey ) + printf( "hb_cdxTagKeyAdd()\n"); + else + hb_cdxTagKeyRead( pTag, BTTM_RECORD ); + hb_cdxPageInsertKey( pTag->RootPage, pNewKey, TRUE ); + hb_cdxTagTagOpen( pTag, 0 ); + if( !pTag->AscendKey ) + { + printf( "hb_cdxTagKeyAdd()\n"); + pTag->TagBOF = TRUE; + } + else + { + hb_cdxTagKeyRead( pTag, BTTM_RECORD ); + pTag->TagEOF = TRUE; + } + } + hb_cdxKeyFree( pNewKey ); + pKey->Xtra = lOldXtra; +} + +static void hb_cdxTagPageStore( LPTAGINFO pTag, LPPAGEINFO PIK ) +{ + CDXDATA pData; + + memset( &pData, 0, sizeof( CDXDATA ) ); + pData.Node_Atr = ( PIK->PageType < PAGE_LEAF ) ? 0 : 2; + if( PIK->Owner == NULL ) + pData.Node_Atr++; + pData.Left_Ptr = PIK->Left; + pData.Rght_Ptr = PIK->Right; + if( pData.Node_Atr < 2 ) + hb_cdxTagIntNodeWrite( pTag, PIK->Page, &pData, PIK ); + else + hb_cdxTagExtNodeWrite( pTag, PIK->Page, &pData, PIK ); +} + +static void hb_cdxTagExtNodeWrite( LPTAGINFO pTag, LONG PN, LPCDXDATA pData, + LPPAGEINFO PIK ) +{ + USHORT uiKeyLength, uiBitCount, cd, kcnt, lm, uiCount, ck, na; + LONG sr, rp, lp, NPN, TmpTag; + LPKEYINFO p, q; + + if( pTag->OptFlags & 0x80 ) + sr = hb_fsSeek( pTag->Owner->DiskFile, 0, FS_END ); + else + sr = pTag->Owner->Owner->lpExtendInfo->ulRecCount; + uiKeyLength = pTag->KeyLength; + for( uiBitCount = 0; uiKeyLength; uiBitCount++, uiKeyLength >>= 1 ); + PIK->ReqByte = 3; + PIK->RNBits = 24 - uiBitCount * 2; + PIK->RNMask = hb_cdxMakeMask( PIK->RNBits ); + while( sr > PIK->RNMask ) + { + PIK->ReqByte++; + PIK->RNBits += 8; + PIK->RNMask = ( PIK->RNMask << 8 ) | 0xFF; + if( PIK->RNMask < 0 ) + { + PIK->RNMask = 0x7FFFFFFF; + PIK->RNBits = 31; + } + } + PIK->Space = CDX_EXTERNAL_SPACE; + PIK->DCBits = PIK->TCBits = uiBitCount; + PIK->DCMask = hb_cdxMakeMask( PIK->DCBits ); + PIK->TCMask = hb_cdxMakeMask( PIK->TCBits ); + sr = cd = kcnt = 0; + lm = sizeof( pData->cdxu.Internal.IntData ) / 2; + q = NULL; + for( uiCount = 0; uiCount < PIK->uiKeys; uiCount++ ) + { + p = hb_cdxPageGetKey( PIK, uiCount ); + if( q != NULL ) + { + hb_cdxKeyCompare( p, q, &cd, TRUE ); + if( cd > 0 ) + cd--; + } + q = p; + /* Comprobar que las Keys son de tipo car cter. */ + cd = p->pItem->item.asString.length - cd; + sr += cd + PIK->ReqByte; + if( sr < lm ) + kcnt++; + } + if( sr < CDX_EXTERNAL_SPACE ) + kcnt = PIK->uiKeys; + ck = 0; + pData->Entry_Ct = 0; + if( kcnt < PIK->uiKeys ) + { + ck = hb_cdxTagFillExternalNode( pTag, pData, PIK, kcnt, ck, &p ); + if( pData->Node_Atr % 2 > 0 ) + pData->Node_Atr--; + na = pData->Node_Atr; + rp = pData->Rght_Ptr; + lp = pData->Left_Ptr; + pData->Rght_Ptr = PN; + pData->cdxu.External.FreeSpace = PIK->Space; + NPN = hb_cdxIndexGetAvailPage( pTag->Owner ); + TmpTag = p->Tag; + p->Tag = NPN; + hb_cdxPageAddNodeKey( PIK, p ); + p->Tag = TmpTag; + if( PIK->PageType == PAGE_ROOT ) + PIK->PageType = PAGE_NODE; + hb_cdxIndexPageWrite( pTag->Owner, NPN, pData, CDX_BLOCK_SIZE ); + if( lp > 0 ) + { + hb_cdxIndexPageRead( pTag->Owner, lp, pData, CDX_BLOCK_SIZE ); + pData->Rght_Ptr = NPN; + hb_cdxIndexPageWrite( pTag->Owner, lp, pData, CDX_BLOCK_SIZE ); + } + memset( pData, 0, CDX_BLOCK_SIZE ); + pData->Node_Atr = na; + pData->Rght_Ptr = rp; + pData->Left_Ptr = NPN; + pData->Entry_Ct = 0; + kcnt = PIK->uiKeys; + } + hb_cdxTagFillExternalNode( pTag, pData, PIK, kcnt, ck, &p ); + pData->cdxu.External.FreeSpace = PIK->Space; + hb_cdxIndexPageWrite( pTag->Owner, PN, pData, sizeof( CDXDATA ) ); +} + +static USHORT hb_cdxTagFillExternalNode( LPTAGINFO pTag, LPCDXDATA pData, + LPPAGEINFO PIK, USHORT kcnt, + USHORT ck, LPKEYINFO * p ) +{ + USHORT i, k, ct, cd, v, c; + LONG m, r; + LPKEYINFO q; + + memset( pData->cdxu.External.ExtData, 0, sizeof( pData->cdxu.External.ExtData ) ); + pData->cdxu.External.FreeSpace = PIK->Space; + pData->cdxu.External.RecNumMask = PIK->RNMask; + pData->cdxu.External.DupCntMask = PIK->DCMask; + pData->cdxu.External.TrlCntMask = PIK->TCMask; + pData->cdxu.External.RecNumBits = PIK->RNBits; + pData->cdxu.External.DupCntBits = PIK->DCBits; + pData->cdxu.External.TrlCntBits = PIK->TCBits; + pData->cdxu.External.ShortBytes = PIK->ReqByte; + m = ~PIK->RNMask; + PIK->Space = CDX_EXTERNAL_SPACE; + k = CDX_EXTERNAL_SPACE; + q = NULL; + i = 0; + while( i < kcnt && ck < PIK->uiKeys ) + { + * p = hb_cdxPageGetKey( PIK, ck ); + ct = pTag->KeyLength - ( * p )->pItem->item.asString.length; + if( q != NULL ) + { + hb_cdxKeyCompare( * p, q, &cd, TRUE ); + if( cd > 0 ) + cd--; + } + else + cd = 0; + q = * p; + PIK->Space -= pTag->KeyLength + PIK->ReqByte - cd - ct; + v = i * PIK->ReqByte; + c = ( ct << ( 16 - PIK->TCBits ) ) | ( cd << ( 16 - PIK->TCBits - PIK->DCBits ) ); + memcpy( &pData->cdxu.External.ExtData[ v + PIK->ReqByte - 2 ], &c, 2 ); + memcpy( &r, &pData->cdxu.External.ExtData[ v ], 4 ); + r &= m; + r |= ( * p )->Tag; + memcpy( &pData->cdxu.External.ExtData[ v ], &r, 4 ); + k -= pTag->KeyLength - cd - ct; + if( pTag->KeyLength - cd - ct > 0 ) + memcpy( &pData->cdxu.External.ExtData[ k ], ( * p )->pItem->item.asString.value + cd, + pTag->KeyLength - cd - ct ); + i++; + ck++; + pData->Entry_Ct++; + } + return ck; +} + +static void hb_cdxTagExtNodeBuild( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO PIK ) +{ + USHORT k, i, v, c, t, d; + LONG r; + LPKEYINFO pKey, pLastKey; + static char szBuffer[ CDX_MAX_KEY + 1 ]; + + k = CDX_EXTERNAL_SPACE; + PIK->Space = pData->cdxu.External.FreeSpace; + PIK->RNMask = pData->cdxu.External.RecNumMask; + PIK->DCMask = pData->cdxu.External.DupCntMask; + PIK->TCMask = pData->cdxu.External.TrlCntMask; + PIK->RNBits = pData->cdxu.External.RecNumBits; + PIK->DCBits = pData->cdxu.External.DupCntBits; + PIK->TCBits = pData->cdxu.External.TrlCntBits; + PIK->ReqByte = pData->cdxu.External.ShortBytes; + i = 0; + while( i < pData->Entry_Ct ) + { + v = i * PIK->ReqByte; + memcpy( &c, &pData->cdxu.External.ExtData[ v + PIK->ReqByte - 2 ], 2 ); + t = ( c >> ( 16 - PIK->TCBits ) ) & PIK->TCMask; + d = ( c >> ( 16 - PIK->TCBits - PIK->DCBits ) ) & PIK->DCMask; + memcpy( &r, &pData->cdxu.External.ExtData[ v ], 4 ); + r &= PIK->RNMask; + k -= pTag->KeyLength - d - t; + if( pTag->KeyLength - d - t > 0 ) + memcpy( &szBuffer[ d ], &pData->cdxu.External.ExtData[ k ], + pTag->KeyLength - d - t ); + szBuffer[ pTag->KeyLength - t ] = NULL; + pKey = hb_cdxKeyNew(); + pKey->Tag = r; + pKey->Xtra = r; + hb_itemPutC( pKey->pItem, szBuffer ); + if( PIK->pKeys == NULL ) + PIK->pKeys = pKey; + else + { + pLastKey = PIK->pKeys; + while( pLastKey->pNext ) + pLastKey = pLastKey->pNext; + pLastKey->pNext = pKey; + } + PIK->uiKeys++; + i++; + } +} + +static void hb_cdxTagTagLoad( LPTAGINFO pTag ) +{ + CDXHEADER pHeader; + HB_MACRO_PTR pMacro; + + hb_cdxIndexPageRead( pTag->Owner, pTag->TagBlock, &pHeader, sizeof( CDXHEADER ) ); + pTag->RootBlock = pHeader.Root; + if( pTag->RootBlock == 0 || pTag->RootBlock % CDX_BLOCK_SIZE > 0 || + pTag->RootBlock > hb_fsSeek( pTag->Owner->DiskFile, 0, FS_END ) || + pHeader.Key_Lgth > CDX_MAX_KEY ) + return; + pTag->KeyLength = pHeader.Key_Lgth; + pTag->MaxKeys = ( CDX_BLOCK_SIZE - 12 ) / ( pTag->KeyLength + 8 ); + pTag->OptFlags = pHeader.IndexOpts; + pTag->UniqueKey = ( pTag->OptFlags & 0x01 ); + pTag->AscendKey = ( pHeader.AscDesc == 0 ); + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAX_KEY + 1 ); + hb_strncpyUpper( pTag->KeyExpr, pHeader.KeyPool, CDX_MAX_KEY ); + if( pTag->OptFlags < 0x80 && pTag->KeyExpr[ 0 ] == 0 ) + return; + if( pTag->OptFlags & 0x80 ) + return; + SELF_COMPILE( pTag->Owner->Owner, pTag->KeyExpr ); + pTag->pKeyItem = pTag->Owner->Owner->valResult; + pTag->Owner->Owner->valResult = NULL; + pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); + hb_macroRun( pMacro ); + switch( hb_itemType( &hb_stack.Return ) ) + { + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + pTag->KeyType = 'N'; + pTag->KeyLength = 10; + break; + + case HB_IT_DATE: + pTag->KeyType = 'D'; + pTag->KeyLength = 8; + break; + + case HB_IT_LOGICAL: + pTag->KeyType = 'C'; + pTag->KeyLength = 1; + break; + + case HB_IT_STRING: + pTag->KeyType = 'C'; + pTag->KeyLength = hb_stack.Return.item.asString.length > CDX_MAX_KEY ? CDX_MAX_KEY : + hb_stack.Return.item.asString.length; + break; + } + + if( pHeader.KeyPool[ strlen( pTag->KeyExpr ) + 1 ] == NULL ) + return; + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAX_KEY + 1 ); + hb_strncpyUpper( pTag->ForExpr, pHeader.KeyPool + + strlen( pTag->KeyExpr ) + 1, CDX_MAX_KEY ); + SELF_COMPILE( pTag->Owner->Owner, pTag->ForExpr ); + pTag->pForItem = pTag->Owner->Owner->valResult; + pTag->Owner->Owner->valResult = NULL; + pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ); + hb_macroRun( pMacro ); + if( hb_itemType( &hb_stack.Return ) != HB_IT_LOGICAL ) + { + hb_macroDelete( pMacro ); + hb_itemRelease( pTag->pForItem ); + pTag->pForItem = NULL; + hb_xfree( pTag->ForExpr ); + pTag->ForExpr = NULL; + } +} + +static void hb_cdxTagSetRoot( LPTAGINFO pTag, LPPAGEINFO PIK ) +{ + LONG NRN, TmpTag; + LPKEYINFO p, TmpStr; + + PIK->Owner = hb_cdxPageNew( pTag, NULL, 0 ); + NRN = hb_cdxIndexGetAvailPage( pTag->Owner ); + PIK->Owner->Page = NRN; + PIK->Owner->PageType = PAGE_ROOT; + if( PIK->uiKeys > 0 ) + { + p = hb_cdxPageGetKey( PIK, PIK->uiKeys - 1 ); + TmpTag = p->Tag; + p->Tag = PIK->Page; + hb_cdxPageInsertKey( PIK->Owner, p, TRUE ); + p->Tag = TmpTag; + } + else + { + TmpStr = hb_cdxKeyNew(); + TmpStr->Tag = PIK->Page; + hb_cdxPageInsertKey( PIK->Owner, TmpStr, TRUE ); + hb_cdxKeyFree( TmpStr ); + } + PIK->Owner->Child = PIK; + pTag->RootPage = PIK->Owner; + pTag->RootBlock = NRN; + pTag->TagChanged = TRUE; +} + +static void hb_cdxTagIntNodeWrite( LPTAGINFO pTag, LONG PN, LPCDXDATA pData, LPPAGEINFO PIK ) +{ + USHORT Cnt, ck, kcnt, na; + LONG rp, lp, NPN, TmpTag; + LPKEYINFO p; + + if( PIK->uiKeys > pTag->MaxKeys ) + { + Cnt = PIK->uiKeys / 2; + Cnt = PIK->uiKeys - Cnt; + } + else + Cnt = PIK->uiKeys; + ck = 0; + kcnt = Cnt; + if( PIK->uiKeys > 0 ) + { + pData->Entry_Ct = 0; + if( kcnt < PIK->uiKeys ) + { + ck = hb_cdxTagFillInternalNode( pTag, pData, PIK, kcnt, ck, &p ); + if( pData->Node_Atr % 2 > 0 ) + pData->Node_Atr--; + na = pData->Node_Atr; + rp = pData->Rght_Ptr; + lp = pData->Left_Ptr; + pData->Rght_Ptr = PN; + NPN = hb_cdxIndexGetAvailPage( pTag->Owner ); + TmpTag = p->Tag; + p->Tag = NPN; + hb_cdxPageAddNodeKey( PIK, p ); + p->Tag = TmpTag; + if( PIK->PageType == PAGE_ROOT ) + PIK->PageType = PAGE_NODE; + hb_cdxIndexPageWrite( pTag->Owner, NPN, pData, CDX_BLOCK_SIZE ); + if( lp > 0 ) + { + hb_cdxIndexPageRead( pTag->Owner, lp, pData, CDX_BLOCK_SIZE ); + pData->Rght_Ptr = NPN; + hb_cdxIndexPageWrite( pTag->Owner, lp, pData, CDX_BLOCK_SIZE ); + } + memset( pData, 32, CDX_BLOCK_SIZE ); + pData->Node_Atr = na; + pData->Rght_Ptr = rp; + pData->Left_Ptr = NPN; + pData->Entry_Ct = 0; + kcnt = pTag->MaxKeys; + } + hb_cdxTagFillInternalNode( pTag, pData, PIK, kcnt, ck, &p ); + } + hb_cdxIndexPageWrite( pTag->Owner, PN, pData, CDX_BLOCK_SIZE ); +} + +static USHORT hb_cdxTagFillInternalNode( LPTAGINFO pTag, LPCDXDATA pData, + LPPAGEINFO PIK, USHORT kcnt, + USHORT ck, LPKEYINFO * p ) +{ + USHORT i, v; + LONG r; + + i = 0; + memset( pData->cdxu.Internal.IntData, ( pTag->KeyType == 'C' ) ? 32 : 0, + sizeof( pData->cdxu.Internal.IntData ) ); + while( i < kcnt && ck < PIK->uiKeys ) + { + * p = hb_cdxPageGetKey( PIK, ck ); + v = i * ( pTag->KeyLength + 8 ); + memcpy( &pData->cdxu.Internal.IntData[ v ], + ( * p )->pItem->item.asString.value, + ( * p )->pItem->item.asString.length ); + v += pTag->KeyLength; + r = hb_cdxSwapBytes( ( * p )->Xtra ); + memcpy( &pData->cdxu.Internal.IntData[ v ], &r, 4 ); + r = hb_cdxSwapBytes( ( * p )->Tag ); + memcpy( &pData->cdxu.Internal.IntData[ v + 4 ], &r, 4 ); + i++; + ck++; + pData->Entry_Ct++; + } + return ck; +} + +static void hb_cdxTagIntNodeBuild( LPTAGINFO pTag, LPCDXDATA pData, LPPAGEINFO pPage ) +{ + USHORT i, v; + LONG r, n; + LPKEYINFO pKey, pLastKey; + static char szBuffer[ CDX_MAX_KEY + 1 ]; + + i = 0; + while( i < pData->Entry_Ct ) + { + v = i * ( pTag->KeyLength + 8 ); + memmove( szBuffer, pData->cdxu.Internal.IntData + v, pTag->KeyLength ); + szBuffer[ pTag->KeyLength ] = NULL; + v += pTag->KeyLength; + memcpy( &r, &pData->cdxu.Internal.IntData[ v ], 4 ); + r = hb_cdxSwapBytes( r ); + memcpy( &n, &pData->cdxu.Internal.IntData[ v + 4 ], 4 ); + n = hb_cdxSwapBytes( n ); + pKey = hb_cdxKeyNew(); + if( pTag->KeyType == 'C' ) + { + v = strlen( szBuffer ); + while( v > 0 && szBuffer[ v - 1 ] == 32 ) + v--; + szBuffer[ v ] = NULL; + } + else + { + printf( "hb_cdxTagIntNodeBuild()" ); + } + hb_itemPutC( pKey->pItem, szBuffer ); + pKey->Tag = n; + pKey->Xtra = r; + if( pPage->pKeys == NULL ) + pPage->pKeys = pKey; + else + { + pLastKey = pPage->pKeys; + while( pLastKey->pNext != NULL ) + pLastKey = pLastKey->pNext; + pLastKey->pNext = pKey; + } + pPage->uiKeys++; + i++; + } +} + +static LONG hb_cdxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey ) +{ + int K; + LPKEYINFO stot; + + pTag->CurKeyInfo->Tag = 0; + hb_cdxTagTagOpen( pTag, 0 ); + if( pTag->RootPage == NULL ) + return 0; + stot = hb_cdxKeyNew(); + hb_itemCopy( stot->pItem, pKey->pItem ); + stot->Tag = pKey->Tag; + stot->Xtra = pKey->Xtra; + if( pTag->KeyType == 'C' ) + { + while( stot->pItem->item.asString.length > 0 && + stot->pItem->item.asString.value[ stot->pItem->item.asString.length - 1 ] == ' ' ) + stot->pItem->item.asString.length--; + stot->pItem->item.asString.value[ stot->pItem->item.asString.length ] = NULL; + } + pTag->TagBOF = pTag->TagEOF = FALSE; + K = hb_cdxPageSeekKey( pTag->RootPage, stot->Tag, stot, FALSE ); + hb_cdxKeyFree( stot ); + if( K == 0 ) + { + hb_cdxPageRetrieveKey( pTag->RootPage, pTag->CurKeyInfo ); + if( pTag->pForItem == NULL ) + return pTag->CurKeyInfo->Tag; + else + /* TODO: test for expression */ + pTag->TagEOF = TRUE; + } + else if( K < 0 ) + { + hb_cdxPageRetrieveKey( pTag->RootPage, pTag->CurKeyInfo ); + if( pTag->pForItem != NULL ) + /* TODO: test for expression */ + pTag->TagEOF = TRUE; + } + else + pTag->TagEOF = TRUE; + return 0; +} + +static LPPAGEINFO hb_cdxPageNew( LPTAGINFO PIT, LPPAGEINFO PIK, LONG FilePosn ) +{ + LPPAGEINFO pPage; + + pPage = ( LPPAGEINFO ) hb_xgrab( sizeof( PAGEINFO ) ); + memset( pPage, 0, sizeof( PAGEINFO ) ); + pPage->Page = FilePosn; + pPage->Left = pPage->Right = -1; + pPage->Owner = PIK; + pPage->TagParent = PIT; + pPage->CurKey = -1; + if( FilePosn > 0 ) + hb_cdxPagePageLoad( pPage ); + return pPage; +} + +static void hb_cdxPageFree( LPPAGEINFO pPage ) +{ + LPKEYINFO pKey; + + if( pPage->Child != NULL ) + { + hb_cdxPageFree( pPage->Child ); + pPage->Child = NULL; + } + + if( pPage->Changed ) + hb_cdxPagePageStore( pPage ); + + if( pPage->NewRoot && pPage->Owner != NULL ) + { + pPage->Owner->Child = NULL; + hb_cdxPageFree( pPage->Owner ); + pPage->Owner = NULL; + } + pPage->NewRoot = FALSE; + + if( pPage->Owner != NULL ) + pPage->Owner->Child = NULL; + pPage->Owner = NULL; + + /* Free all keys */ + while( pPage->pKeys != NULL ) + { + pKey = pPage->pKeys; + pPage->pKeys = pKey->pNext; + hb_cdxKeyFree( pKey ); + } + + hb_xfree( pPage ); +} + +static BOOL hb_cdxPageReadTopKey( LPPAGEINFO pPage ) +{ + LPKEYINFO pKey; + + if( pPage->uiKeys == 0 ) + return FALSE; + pPage->CurKey = 0; + pKey = pPage->pKeys; + if( pPage->PageType < PAGE_LEAF ) + { + if( hb_cdxPageGetChild( pPage, pKey->Tag ) ) + return hb_cdxPageReadTopKey( pPage->Child ); + else + return FALSE; + } + else + { + hb_itemCopy( pPage->TagParent->CurKeyInfo->pItem, pKey->pItem ); + pPage->TagParent->CurKeyInfo->Tag = pKey->Tag; + return TRUE; + } +} + +static BOOL hb_cdxPageReadBottomKey( LPPAGEINFO pPage ) +{ + LPKEYINFO pKey; + + if( pPage->uiKeys == 0 ) + return FALSE; + pPage->CurKey = pPage->uiKeys - 1; + pKey = hb_cdxPageGetKey( pPage, pPage->CurKey ); + if( pPage->PageType < PAGE_LEAF ) + { + printf( "hb_cdxPageReadBottomKey()" ); + return TRUE; + } + else + { + hb_itemCopy( pPage->TagParent->CurKeyInfo->pItem, pKey->pItem ); + pPage->TagParent->CurKeyInfo->Tag = pKey->Tag; + return TRUE; + } +} + +static int hb_cdxPageSeekKey( LPPAGEINFO pPage, LONG lBlock, LPKEYINFO pKey, BOOL bExact ) +{ + int k; + USHORT dav; + LPKEYINFO p; + + k = 1; + bExact = ( bExact || pPage->TagParent->KeyType != 'C' ); + pPage->CurKey = 0; + if( pPage->uiKeys > 0 ) + { + while( k > 0 && pPage->CurKey < pPage->uiKeys ) + { + p = hb_cdxPageGetKey( pPage, pPage->CurKey ); + k = hb_cdxKeyCompare( pKey, p, &dav, bExact ); + if( !pPage->TagParent->AscendKey ) + k = -k; + if( k == 0 && lBlock == CDX_MAX_REC_NUM ) + k = 1; + if( k == 0 && lBlock != CDX_IGNORE_REC_NUM ) + { + if( lBlock > p->Xtra ) + k = 1; + else if( lBlock < p->Xtra ) + k = -1; + } + if( k <= 0 || pPage->CurKey == pPage->uiKeys - 1 ) + { + if( pPage->PageType < PAGE_LEAF ) + { + hb_cdxPageGetChild( pPage, p->Tag ); + k = hb_cdxPageSeekKey( pPage->Child, lBlock, pKey, bExact ); + } + else if( k == 0 && lBlock != CDX_IGNORE_REC_NUM ) + { + if( lBlock > p->Tag ) + k = 1; + else if( lBlock < p->Tag ) + k = -1; + } + } + if( k > 0 ) + pPage->CurKey++; + } + } + return k; +} + +static void hb_cdxPageInsertKey( LPPAGEINFO pPage, LPKEYINFO pKey, BOOL bAddAfter ) +{ + USHORT uiCount; + LPKEYINFO pNewKey, pLastKey; + + if( pPage->Child != NULL ) + hb_cdxPageInsertKey( pPage->Child, pKey, bAddAfter ); + else + { + pNewKey = hb_cdxKeyNew(); + hb_itemCopy( pNewKey->pItem, pKey->pItem ); + pNewKey->Tag = pKey->Tag; + pNewKey->Xtra = pKey->Xtra; + if( bAddAfter ) + pPage->CurKey++; + if( pPage->CurKey > pPage->uiKeys ) + pPage->CurKey = pPage->uiKeys; + if( pPage->CurKey < 0 ) + pPage->CurKey = 0; + if( pPage->Owner != NULL && pPage->CurKey >= pPage->uiKeys ) + printf( "hb_cdxPageInsertKey()" ); + if( pPage->pKeys == NULL ) + pPage->pKeys = pNewKey; + else + { + if( pPage->CurKey == 0 ) + { + pNewKey->pNext = pPage->pKeys; + pPage->pKeys = pNewKey; + } + else + { + uiCount = pPage->CurKey; + pLastKey = pPage->pKeys; + while( uiCount > 1 && pLastKey->pNext ) + { + pLastKey = pLastKey->pNext; + uiCount--; + } + pNewKey->pNext = pLastKey->pNext; + pLastKey->pNext = pNewKey; + } + } + pPage->uiKeys++; + pPage->Changed = TRUE; + } +} + +static void hb_cdxPagePageStore( LPPAGEINFO pPage ) +{ + if( pPage->Page == 0 ) + pPage->Page = hb_cdxIndexGetAvailPage( pPage->TagParent->Owner ); + hb_cdxTagPageStore( pPage->TagParent, pPage ); + pPage->Changed = FALSE; +} + +static BOOL hb_cdxPageReadNextKey( LPPAGEINFO pPage ) +{ + BOOL b; + LPKEYINFO p; + + if( pPage->uiKeys == 0 ) + return FALSE; + if( pPage->PageType < PAGE_LEAF ) + { + b = FALSE; + while( ! b && pPage->CurKey < pPage->uiKeys ) + { + p = hb_cdxPageGetKey( pPage, pPage->CurKey ); + if( hb_cdxPageGetChild( pPage, p->Tag ) ) + { + if( pPage->Child->CurKey == -1 ) + { + if( pPage->Child->PageType < PAGE_LEAF ) + pPage->Child->CurKey = 0; + } + b = hb_cdxPageReadNextKey( pPage->Child ); + } + else + b = FALSE; + if( !b ) + pPage->CurKey++; + } + if( !b ) + pPage->CurKey = pPage->uiKeys; + return b; + } + else + { + pPage->CurKey++; + if( pPage->CurKey < pPage->uiKeys ) + { + p = hb_cdxPageGetKey( pPage, pPage->CurKey ); + hb_itemCopy( pPage->TagParent->CurKeyInfo->pItem, p->pItem ); + pPage->TagParent->CurKeyInfo->Tag = p->Tag; + return TRUE; + } + else + { + pPage->CurKey = pPage->uiKeys; + return FALSE; + } + } +} + +static LPKEYINFO hb_cdxPageGetKey( LPPAGEINFO pPage, USHORT uiKey ) +{ + LPKEYINFO pKey; + + pKey = pPage->pKeys; + while( uiKey > 0 && pKey->pNext != NULL ) + { + pKey = pKey->pNext; + uiKey--; + } + return pKey; +} + +static void hb_cdxPagePageLoad( LPPAGEINFO pPage ) +{ + LPKEYINFO pKey; + + while( pPage->pKeys != NULL ) + { + pKey = pPage->pKeys; + pPage->pKeys = pPage->pKeys->pNext; + hb_cdxKeyFree( pKey ); + } + pPage->uiKeys = 0; + hb_cdxTagPageLoad( pPage->TagParent, pPage ); + pPage->Changed = FALSE; +} + +static int hb_cdxPageRetrieveKey( LPPAGEINFO pPage, LPKEYINFO pKey ) +{ + int iCheck; + LPKEYINFO pNewKey; + + if( pPage->Owner == NULL ) + pPage->ChkBOF = pPage->ChkEOF = TRUE; + pPage->ChkBOF = ( pPage->ChkBOF && pPage->CurKey == 0 ); + pPage->ChkEOF = ( pPage->ChkEOF && pPage->CurKey == pPage->uiKeys - 1 ); + if( pPage->Child != NULL ) + return hb_cdxPageRetrieveKey( pPage->Child, pKey ); + else + { + pNewKey = hb_cdxPageGetKey( pPage, pPage->CurKey ); + hb_itemCopy( pKey->pItem, pNewKey->pItem ); + pKey->Tag = pNewKey->Tag; + iCheck = 0; + if( pPage->ChkBOF ) + iCheck = 1; + if( pPage->ChkEOF ) + iCheck += 2; + return iCheck; + } +} + +static void hb_cdxPageAddNodeKey( LPPAGEINFO pPage, LPKEYINFO pKey ) +{ + if( pPage->Owner == NULL ) + { + hb_cdxTagSetRoot( pPage->TagParent, pPage ); + pPage->NewRoot = TRUE; + } + pPage->Owner->CurKey = hb_cdxPageSeekNodeTag( pPage->Owner, pPage->Page ); + pPage->Owner->Child = NULL; + hb_cdxPageInsertKey( pPage->Owner, pKey, FALSE ); + pPage->Owner->CurKey++; + pPage->Owner->Child = pPage; + pPage->Reload = TRUE; +} + +static int hb_cdxPageSeekNodeTag( LPPAGEINFO pPage, LONG Tag ) +{ + int iSeek; + USHORT i; + LPKEYINFO p; + + if( pPage->uiKeys == 0 ) + return -1; + else + { + iSeek = -1; + i = 0; + while( iSeek < 0 && i < pPage->uiKeys ) + { + p = hb_cdxPageGetKey( pPage, i ); + if( p->Tag == Tag ) + iSeek = i; + i++; + } + return iSeek; + } +} + +static BOOL hb_cdxPageGetChild( LPPAGEINFO pPage, LONG Tag ) +{ + if( Tag == 0 ) + return FALSE; + if( pPage->TagParent->Owner->NextAvail > 0 && + Tag > pPage->TagParent->Owner->NextAvail ) + return FALSE; + if( pPage->PageType < PAGE_LEAF ) + { + if( pPage->Child != NULL ) + { + if( pPage->Child->Page != Tag || pPage->Child->Reload ) + { + hb_cdxPageFree( pPage->Child ); + pPage->Child = NULL; + } + } + if( pPage->Child == NULL ) + pPage->Child = hb_cdxPageNew( pPage->TagParent, pPage, Tag ); + } + return ( pPage->Child != NULL ); +} + +static void hb_cdxPageDeleteKey( LPPAGEINFO pPage ) +{ + BOOL lastone; + LONG TempTag; + LPKEYINFO p, pPrevKey; + + pPage->Changed = TRUE; + if( pPage->Child != NULL ) + hb_cdxPageDeleteKey( pPage->Child ); + else + { + lastone = ( pPage->CurKey >= pPage->uiKeys - 1 ); + p = hb_cdxPageGetKey( pPage, pPage->CurKey ); + if( pPage->pKeys == p ) + pPage->pKeys = p->pNext; + else + { + pPrevKey = hb_cdxPageGetKey( pPage, pPage->CurKey - 1 ); + pPrevKey->pNext = p->pNext; + } + pPage->uiKeys--; + hb_cdxKeyFree( p ); + if( pPage->CurKey >= pPage->uiKeys ) + pPage->CurKey = pPage->uiKeys - 1; + if( pPage->CurKey < 0 ) + pPage->CurKey = 0; + if( lastone && pPage->Owner != NULL ) + { + if( pPage->uiKeys > 0 ) + { + p = hb_cdxPageGetKey( pPage, pPage->CurKey ); + TempTag = p->Tag; + p->Tag = pPage->Page; + printf( "ReplaceNodeKey();" ); + p->Tag = TempTag; + } + else + printf( "DeleteNodeKey();" ); + } + } +} + +static LPINDEXINFO hb_cdxIndexNew( AREAP pArea ) +{ + LPINDEXINFO pIndex; + + pIndex = ( LPINDEXINFO ) hb_xgrab( sizeof( INDEXINFO ) ); + memset( pIndex, 0, sizeof( INDEXINFO ) ); + pIndex->DiskFile = FS_ERROR; + pIndex->Owner = pArea; + pIndex->NextAvail = -1; + return pIndex; +} + +static void hb_cdxIndexFree( LPINDEXINFO pIndex ) +{ + LPTAGINFO pTag; + + /* Free Compound tag */ + if( pIndex->CompoundTag != NULL ) + { + hb_cdxTagTagClose( pIndex->CompoundTag ); + hb_cdxTagFree( pIndex->CompoundTag ); + } + + /* Free all tags */ + while( pIndex->TagList ) + { + pTag = pIndex->TagList; + pIndex->TagList = pTag->pNext; + hb_cdxTagFree( pTag ); + } + + /* Close file */ + if( pIndex->DiskFile != FS_ERROR ) + hb_fsClose( pIndex->DiskFile ); + + hb_xfree( pIndex ); +} + +static LONG hb_cdxIndexGetAvailPage( LPINDEXINFO pIndex ) +{ + if( pIndex->NextAvail == -1 ) + hb_cdxIndexResetAvailPage( pIndex ); + pIndex->NextAvail += CDX_BLOCK_SIZE; + return pIndex->NextAvail - CDX_BLOCK_SIZE; +} + +static void hb_cdxIndexResetAvailPage( LPINDEXINFO pIndex ) +{ + pIndex->NextAvail = hb_fsSeek( pIndex->DiskFile, 0, FS_END ); +} + +static void hb_cdxIndexPageRead( LPINDEXINFO pIndex, LONG lPos, void * pBuffer, + USHORT uiSize ) +{ + if( hb_fsSeek( pIndex->DiskFile, lPos, FS_SET ) == lPos ) + hb_fsRead( pIndex->DiskFile, ( BYTE * ) pBuffer, uiSize ); +} + +static void hb_cdxIndexPageWrite( LPINDEXINFO pIndex, LONG lPos, void * pBuffer, + USHORT uiSize ) +{ + if( hb_fsSeek( pIndex->DiskFile, lPos, FS_SET ) == lPos ) + hb_fsWrite( pIndex->DiskFile, ( BYTE * ) pBuffer, uiSize ); +} + +static void hb_cdxIndexAddTag( LPINDEXINFO pIndex, char * szTagName, char * szKeyExp, + PHB_ITEM pKeyItem, BYTE bType, USHORT uiLen, char * szForExp, + PHB_ITEM pForItem, BOOL bAscending, BOOL bUnique ) +{ + LPTAGINFO pTag, pLastTag; + LPKEYINFO pKey; + + hb_cdxTagTagOpen( pIndex->CompoundTag, 0 ); + pKey = hb_cdxKeyNew(); + hb_itemPutC( pKey->pItem, szTagName ); + pTag = pIndex->TagList; + pLastTag = NULL; + while( pTag != NULL ) + { + if( strcmpi( pTag->TagName, szTagName ) == 0 ) + { + pKey->Tag = pTag->TagBlock; + if( hb_cdxTagKeyFind( pIndex->CompoundTag, pKey ) > 0 ) + hb_cdxPageDeleteKey( pIndex->CompoundTag->RootPage ); + if( pLastTag == NULL ) + pIndex->TagList = pTag->pNext; + else + pLastTag->pNext = pTag->pNext; + hb_cdxTagFree( pTag ); + break; + } + pLastTag = pTag; + pTag = pTag->pNext; + } + + /* Create new tag an add to tag list */ + pTag = hb_cdxTagNew( pIndex, szTagName, -1 ); + if( pIndex->TagList == NULL ) + pIndex->TagList = pTag; + else + { + pLastTag = pIndex->TagList; + while( pLastTag->pNext ) + pLastTag = pLastTag->pNext; + pLastTag->pNext = pTag; + } + hb_cdxTagIndexTagNew( pTag, szKeyExp, pKeyItem, bType, uiLen, szForExp, + pForItem, bAscending, bUnique ); + hb_itemPutC( pKey->pItem, pTag->TagName ); + pKey->Tag = pTag->TagBlock; + hb_cdxTagKeyAdd( pIndex->CompoundTag, pKey ); + hb_cdxKeyFree( pKey ); + pIndex->CompoundTag->RootPage->Changed = TRUE; + hb_cdxTagTagClose( pIndex->CompoundTag ); +} + +static LPSORTINFO hb_cdxSortNew( LPTAGINFO pTag, BOOL bUnique ) +{ + BYTE * P; + LPSORTINFO pSort; + + pSort = ( LPSORTINFO ) hb_xgrab( sizeof( SORTINFO ) ); + memset( pSort, 0, sizeof( SORTINFO ) ); + pSort->SortChunk = SORT_CHUNK_LIMIT; + pSort->NodeLimit = pSort->SortChunk / sizeof( SORTDATA ); + pSort->NodeMask = pSort->NodeShift = pSort->NodeCur = 1; + pSort->ChunkLimit = 0x8000; + while( pSort->NodeMask < pSort->NodeLimit - 1 ) + { + pSort->NodeMask = ( pSort->NodeMask << 1 ) + 1; + pSort->ChunkLimit >>= 1; + pSort->NodeShift++; + } + pSort->ChunkSize = pSort->ChunkLimit; + pSort->ChunkList = hb_xgrab( pSort->ChunkSize * sizeof( LONG ) ); + memset( pSort->ChunkList, 0, pSort->ChunkSize * sizeof( LONG ) ); + P = hb_xgrab( pSort->SortChunk * sizeof( BYTE ) ); + memset( P, 0, pSort->SortChunk * sizeof( BYTE ) ); + pSort->ChunkList[ 0 ] = ( LONG ) P; + hb_cdxSortLinkNew( pSort, &pSort->RootLink ); + pSort->Unique = bUnique; + pSort->Ascend = TRUE; + pSort->CurTag = pTag; + pSort->KeyTot = pTag->Owner->Owner->lpExtendInfo->ulRecCount; + pSort->KeyWork = hb_cdxKeyNew(); + pSort->LastKey = hb_cdxKeyNew(); + return pSort; +} + +static void hb_cdxSortFree( LPSORTINFO pSort ) +{ + USHORT usCount; + LONG pa; + + pSort->Closing = TRUE; + for( usCount = 0; usCount <= 30; usCount++ ) + { + if( pSort->NodeList[ usCount ] != NULL ) + { + pa = pSort->NodeList[ usCount ]->Rght_Ptr; + pSort->NodeList[ usCount ]->Rght_Ptr = -1; + if( pSort->NodeList[ usCount ]->Entry_Ct > 0 ) + { + if( pSort->NodeList[ usCount + 1 ] == NULL ) + { + pSort->CurTag->RootBlock = pa; + pSort->NodeList[ usCount ]->Node_Atr++; + } + hb_cdxIndexPageWrite( pSort->CurTag->Owner, pa, pSort->NodeList[ usCount ], + sizeof( CDXDATA ) ); + if( pSort->NodeList[ usCount + 1 ] != NULL ) + hb_cdxSortAddToNode( pSort, ( USHORT ) ( usCount + 1 ), pa, + pSort->LastTag, pSort->KeyWork ); + } + hb_xfree( ( LPCDXDATA ) pSort->NodeList[ usCount ] ); + } + } + + if( pSort->ChunkList != NULL ) + { + for( usCount = 0; usCount < pSort->ChunkLimit; usCount++ ) + { + if( pSort->ChunkList[ usCount ] != NULL ) + hb_xfree( ( BYTE * ) pSort->ChunkList[ usCount ] ); + } + hb_xfree( pSort->ChunkList ); + } + hb_cdxKeyFree( pSort->KeyWork ); + hb_cdxKeyFree( pSort->LastKey ); + + hb_xfree( pSort ); +} + +static void hb_cdxSortLinkNew( LPSORTINFO pSort, LONG * NewLink ) +{ + if( pSort->NodeCur >= pSort->NodeLimit ) + hb_cdxSortGetNewChunk( pSort ); + * NewLink = ( pSort->ChunkCur << pSort->NodeShift ) + pSort->NodeCur; + pSort->NodeCur++; +} + +static void hb_cdxSortGetNewChunk( LPSORTINFO pSort ) +{ + BYTE * P; + + pSort->ChunkCur++; + if( pSort->ChunkCur == pSort->ChunkLimit ) + { + printf( "FlushChunks();" ); + return; + } + P = ( BYTE * ) pSort->ChunkList[ pSort->ChunkCur ]; + if( P == NULL ) + P = hb_xgrab( pSort->SortChunk * sizeof( BYTE ) ); + if( pSort->ChunkCur != 0 ) + { + memset( P, 0, pSort->SortChunk * sizeof( BYTE ) ); + pSort->ChunkList[ pSort->ChunkCur ] = ( LONG ) P; + pSort->NodeCur = 0; + } +} + +static void hb_cdxSortInsertWord( LPSORTINFO pSort, LONG Tag, char * Value ) +{ + char s[ 34 ]; + USHORT w, cc, nc, EOK; + SHORT v; + LPSORTDATA wx; + + ltoa( Tag, s + 1, 10 ); + w = strlen( Value ); + if( pSort->NodeLimit - pSort->NodeCur < w + strlen( s + 1 ) + 1 ) + { + cc = pSort->ChunkCur; + nc = pSort->NodeCur; + hb_cdxSortGetNewChunk( pSort ); + if( pSort->ChunkCur > 0 ) + { + pSort->ChunkCur = cc; + pSort->NodeCur = nc; + } + } + pSort->WordCount++; + strcpy( pSort->WPch, Value ); + v = strlen( pSort->WPch ); + if( v > 0 ) + { + if( v > pSort->KeySize ) + pSort->KeySize = v; + v--; + } + while( v >= 0 && pSort->WPch[ v ] == ' ' ) + { + pSort->WPch[ v ] = NULL; + v--; + } + v++; + EOK = v; + if( !pSort->Unique ) + { + s[ 0 ] = ( char ) strlen( s + 1 ); + memcpy( &pSort->WPch[ v ], s, s[ 0 ] + 1 ); + v += ( SHORT ) ( s[ 0 ] + 1 ); + pSort->WPch[ v ] = NULL; + } + pSort->LevelPtr = pSort->RootLink; + pSort->PriorPtr = 0; + pSort->WCur = 0; + do + hb_cdxSortStuffKey( pSort, &wx ); + while( pSort->WPch[ pSort->WCur ] != 0 ); + if( pSort->Unique ) + { + if( wx->sortu.A.NUse == SORT_END_OF_KEY ) + return; + wx->sortu.A.NUse = SORT_END_OF_KEY; + if( EOK == 0 ) + EOK++; + memcpy( &pSort->WPch[ EOK ], s, s[ 0 ] + 1 ); + v = EOK + s[ 0 ] + 1; + pSort->WPch[ v ] = NULL; + do + hb_cdxSortStuffKey( pSort, &wx ); + while( pSort->WPch[ pSort->WCur ] != 0 ); + } + wx->sortu.A.NUse = SORT_END_OF_WORD; +} + +static void hb_cdxSortStuffKey( LPSORTINFO pSort, LPSORTDATA * wx ) +{ + USHORT w; + SHORT v; + LONG p1; + LPSORTDATA x; + + hb_cdxSortGetNode( pSort, pSort->WPch[ pSort->WCur ], &p1 ); + * wx = hb_cdxSortLinkGet( pSort, p1 ); + pSort->WCur++; + if( pSort->LevelPtr == 0 ) + { + if( pSort->PriorPtr > 0 ) + { + x = hb_cdxSortLinkGet( pSort, pSort->PriorPtr ); + x->sortu.A.WordArray = p1; + } + w = strlen( pSort->WPch ); + v = w - pSort->WCur - 1; + if( v > 0 ) + { + if( v > 4 ) + v = 4; + memcpy( ( * wx )->sortu.B.ChrStack, &pSort->WPch[ pSort->WCur ], v ); + ( * wx )->sortu.A.NUse = SORT_STACK_OF_CHAR; + pSort->WCur += v; + } + } + pSort->PriorPtr = p1; + pSort->LevelPtr = ( * wx )->sortu.A.WordArray; +} + +static void hb_cdxSortGetNode( LPSORTINFO pSort, char Character, LONG * NewLink ) +{ + char c; + int df; + LONG p, q, r; + LPSORTDATA px, qx, rx; + + if( pSort->LevelPtr == 0 ) + { + hb_cdxSortLinkNew( pSort, NewLink ); + px = hb_cdxSortLinkGet( pSort, * NewLink ); + px->sortu.A.Character = Character; + return; + } + p = pSort->LevelPtr; + px = hb_cdxSortLinkGet( pSort, pSort->LevelPtr ); + q = pSort->PriorPtr; + if( px->sortu.A.NUse == SORT_STACK_OF_CHAR ) + { + hb_cdxSortLinkNew( pSort, &r ); + c = px->sortu.A.Character; + qx = hb_cdxSortLinkGet( pSort, q ); + qx->sortu.A.WordArray = r; + rx = hb_cdxSortLinkGet( pSort, r ); + rx->sortu.A.Character = c; + rx->sortu.A.WordArray = p; + px = hb_cdxSortLinkGet( pSort, p ); + px->sortu.A.Character = px->sortu.B.ChrStack[ 0 ]; + memmove( &px->sortu.B.ChrStack[ 0 ], &px->sortu.B.ChrStack[ 1 ], 3 ); + px->sortu.B.ChrStack[ 3 ] = NULL; + if( px->sortu.C.ChrFill != 0 ) + px->sortu.A.NUse = SORT_STACK_OF_CHAR; + else + px->sortu.A.NUse = SORT_ACTIVE_LIST; + p = r; + px = hb_cdxSortLinkGet( pSort, p ); + } + if( Character > px->sortu.A.Character ) + df = 1; + else if( Character < px->sortu.A.Character ) + df = -1; + else + df = 0; + if( !pSort->Ascend && Character > 0 && px->sortu.A.Character > 0 ) + df = -df; + while( px->sortu.A.LevelLink != 0 && df > 0 ) + { + q = p; + p = px->sortu.A.LevelLink; + px = hb_cdxSortLinkGet( pSort, p ); + if( px->sortu.A.NUse == SORT_STACK_OF_CHAR ) + { + hb_cdxSortLinkNew( pSort, &r ); + c = px->sortu.A.Character; + qx = hb_cdxSortLinkGet( pSort, q ); + qx->sortu.A.WordArray = r; + rx = hb_cdxSortLinkGet( pSort, r ); + rx->sortu.A.Character = c; + rx->sortu.A.WordArray = p; + px = hb_cdxSortLinkGet( pSort, p ); + px->sortu.A.Character = px->sortu.B.ChrStack[ 0 ]; + memmove( &px->sortu.B.ChrStack[ 0 ], &px->sortu.B.ChrStack[ 1 ], 3 ); + px->sortu.B.ChrStack[ 3 ] = NULL; + if( px->sortu.C.ChrFill != 0 ) + px->sortu.A.NUse = SORT_STACK_OF_CHAR; + else + px->sortu.A.NUse = SORT_ACTIVE_LIST; + p = r; + px = hb_cdxSortLinkGet( pSort, p ); + } + if( Character > px->sortu.A.Character ) + df = 1; + else if( Character < px->sortu.A.Character ) + df = -1; + else + df = 0; + if( !pSort->Ascend && Character > 0 && px->sortu.A.Character > 0 ) + df = -df; + } + if( df == 0 ) + * NewLink = p; + else + { + hb_cdxSortLinkNew( pSort, &r ); + if( df == -1 ) + { + qx = hb_cdxSortLinkGet( pSort, q ); + if( q == pSort->PriorPtr ) + qx->sortu.A.WordArray = r; + else + qx->sortu.A.LevelLink = r; + } + else + { + p = px->sortu.A.LevelLink; + px->sortu.A.LevelLink = r; + } + rx = hb_cdxSortLinkGet( pSort, r ); + rx->sortu.A.LevelLink = p; + rx->sortu.A.Character = Character; + * NewLink = r; + } +} + +static LPSORTDATA hb_cdxSortLinkGet( LPSORTINFO pSort, LONG Value ) +{ + LPSORTDATA P; + + if( Value > 0 ) + { + P = ( LPSORTDATA ) pSort->ChunkList[ Value >> pSort->NodeShift ]; + if( P != NULL ) + return &P[ Value & pSort->NodeMask ]; + else + return NULL; + } + return NULL; +} + +static void hb_cdxSortDisplayWord( LPSORTINFO pSort ) +{ + pSort->WPch[ 0 ] = NULL; + hb_cdxSortRecurseDict( pSort, pSort->RootLink, 0 ); +} + +static void hb_cdxSortRecurseDict( LPSORTINFO pSort, LONG WPtr, LONG WBgn ) +{ + USHORT WCnt; + + if( WPtr == 0 ) + return; + WCnt = strlen( pSort->WPch ); + pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr ); + if( pSort->WAdr->sortu.A.Character != 0 ) + { + pSort->WPch[ WCnt ] = pSort->WAdr->sortu.A.Character; + pSort->WPch[ WCnt + 1 ] = NULL; + } + if( pSort->WAdr->sortu.A.NUse == SORT_STACK_OF_CHAR ) + { + memcpy( &pSort->WPch[ strlen( pSort->WPch ) ], pSort->WAdr->sortu.B.ChrStack, 4 ); + pSort->WPch[ WCnt + 5 ] = NULL; + } + if( pSort->WAdr->sortu.A.NUse == SORT_END_OF_WORD ) + hb_cdxSortSendWord( pSort, pSort->WPch ); + else + { + if( pSort->WAdr->sortu.A.WordArray != 0 ) + hb_cdxSortRecurseDict( pSort, pSort->WAdr->sortu.A.WordArray, WBgn ); + pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr ); + } + pSort->WPch[ WCnt ] = NULL; + if( pSort->WAdr->sortu.A.LevelLink != 0 && pSort->WAdr->sortu.A.NUse != SORT_STACK_OF_CHAR ) + hb_cdxSortRecurseDict( pSort, pSort->WAdr->sortu.A.LevelLink, WCnt ); +} + +static void hb_cdxSortSendWord( LPSORTINFO pSort, char * Value ) +{ + LONG Tag; + BYTE OldByte; + char * pce; + + pce = Value + strlen( Value ) - 1; + while( pce[ 0 ] > 31 ) + pce--; + Tag = atol( pce + 1 ); + OldByte = pce[ 0 ]; + pce[ 0 ] = NULL; + hb_cdxSortOutputWord( pSort, Tag, Value ); + pce[ 0 ] = OldByte; +} + +static void hb_cdxSortOutputWord( LPSORTINFO pSort, LONG Tag, char * Value ) +{ + pSort->KeyCnt++; + hb_itemPutC( pSort->KeyWork->pItem, Value ); + if( pSort->CurTag->KeyType != 'C' ) + printf( "pSort->CurTag->AdjustValue( &KeyWork );" ); + hb_cdxSortAddToNode( pSort, 0, Tag, Tag, pSort->KeyWork ); + pSort->LastTag = Tag; + hb_itemCopy( pSort->LastKey->pItem, pSort->KeyWork->pItem ); +} + +static void hb_cdxSortAddToNode( LPSORTINFO pSort, USHORT Lvl, LONG Tag, + LONG Link, LPKEYINFO Value ) +{ + USHORT i, bitcnt; + LONG sr; + + if( pSort->NodeList[ Lvl ] == NULL ) + { + pSort->NodeList[ Lvl ] = ( LPCDXDATA ) hb_xgrab( sizeof( CDXDATA ) ); + memset( pSort->NodeList[ Lvl ], 0, sizeof( CDXDATA ) ); + if( Lvl == 0 ) + { + sr = pSort->KeyTot; + i = pSort->CurTag->KeyLength; + for( bitcnt = 0; i; bitcnt++, i >>= 1 ); + pSort->NodeList[ 0 ]->cdxu.External.ShortBytes = 3; + pSort->NodeList[ 0 ]->cdxu.External.RecNumBits = 24 - bitcnt * 2; + pSort->NodeList[ 0 ]->cdxu.External.RecNumMask = + hb_cdxMakeMask( pSort->NodeList[ 0 ]->cdxu.External.RecNumBits ); + while( sr > pSort->NodeList[ 0 ]->cdxu.External.RecNumMask ) + { + pSort->NodeList[ 0 ]->cdxu.External.ShortBytes++; + pSort->NodeList[ 0 ]->cdxu.External.RecNumBits += 8; + pSort->NodeList[ 0 ]->cdxu.External.RecNumMask = + ( pSort->NodeList[ 0 ]->cdxu.External.RecNumMask << 8 ) | 0xFF; + } + pSort->NodeList[ 0 ]->cdxu.External.FreeSpace = CDX_EXTERNAL_SPACE; + pSort->NodeList[ 0 ]->cdxu.External.DupCntBits = + pSort->NodeList[ 0 ]->cdxu.External.TrlCntBits = bitcnt; + pSort->NodeList[ 0 ]->cdxu.External.DupCntMask = + hb_cdxMakeMask( pSort->NodeList[ 0 ]->cdxu.External.DupCntBits ); + pSort->NodeList[ 0 ]->cdxu.External.TrlCntMask = + hb_cdxMakeMask( pSort->NodeList[ 0 ]->cdxu.External.TrlCntBits ); + } + pSort->NodeList[ Lvl ]->Left_Ptr = -1; + pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->Owner ); + pSort->NodeList[ Lvl ]->Node_Atr = ( Lvl == 0 ) ? 2 : 0; + } + if( Lvl == 0 ) + hb_cdxSortAddExternal( pSort, Lvl, Tag, Link, Value ); + else + hb_cdxSortAddInternal( pSort, Lvl, Tag, Link, Value ); +} + +static void hb_cdxSortAddExternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link, + LPKEYINFO Value ) +{ + USHORT k, ct, cd, v, c; + LONG m, r, pa; + + if( pSort->NodeList[ Lvl ]->Entry_Ct == 0 ) + { + memset( pSort->NodeList[ Lvl ]->cdxu.External.ExtData, 0, + sizeof( pSort->NodeList[ Lvl ]->cdxu.External.ExtData ) ); + pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace = CDX_EXTERNAL_SPACE; + hb_itemPutC( pSort->LastKey->pItem, "" ); + } + m = ~pSort->NodeList[ Lvl ]->cdxu.External.RecNumMask; + ct = ( USHORT ) ( pSort->CurTag->KeyLength - + Value->pItem->item.asString.length ); + hb_cdxKeyCompare( Value, pSort->LastKey, &cd, TRUE ); + if( cd > 0 ) + cd -= ( USHORT ) 1; + v = ( USHORT ) ( pSort->NodeList[ Lvl ]->Entry_Ct * + pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes ); + k = ( USHORT ) ( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace + v ); + pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace -= + ( USHORT ) ( pSort->CurTag->KeyLength + + pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes - cd - ct ); + c = ( USHORT ) ( ( ct << ( 16 - pSort->NodeList[ Lvl ]->cdxu.External.TrlCntBits ) ) | + ( cd << ( 16 - pSort->NodeList[ Lvl ]->cdxu.External.TrlCntBits - + pSort->NodeList[ Lvl ]->cdxu.External.DupCntBits ) ) ); + memcpy( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ v + + pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes - 2 ], &c, 2 ); + memcpy( &r, &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ v ], 4 ); + r &= m; + r |= Tag; + memcpy( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ v ], &r, 4 ); + k -= ( USHORT ) ( pSort->CurTag->KeyLength - cd - ct ); + if( pSort->CurTag->KeyLength - cd - ct > 0 ) + memcpy( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ k ], + Value->pItem->item.asString.value + cd, + pSort->CurTag->KeyLength - cd - ct ); + pSort->NodeList[ Lvl ]->Entry_Ct++; + if( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace < + ( pSort->CurTag->KeyLength + 8 + + pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes ) * 2 ) + { + pa = pSort->NodeList[ Lvl ]->Rght_Ptr; + if( pSort->KeyCnt < pSort->KeyTot ) + pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->Owner ); + else + pSort->NodeList[ Lvl ]->Rght_Ptr = -1; + pSort->NodeList[ Lvl ]->Node_Atr = 2; + hb_cdxIndexPageWrite( pSort->CurTag->Owner, pa, pSort->NodeList[ Lvl ], + sizeof( CDXDATA ) ); + pSort->NodeList[ Lvl ]->Left_Ptr = pa; + hb_cdxSortAddToNode( pSort, ( USHORT ) ( Lvl + 1 ), pa, Link, Value ); + pSort->NodeList[ Lvl ]->Entry_Ct = 0; + } +} + +static void hb_cdxSortAddInternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link, + LPKEYINFO Value ) +{ + USHORT v; + LONG r, pa; + + if( pSort->NodeList[ Lvl ]->Entry_Ct == 0 ) + memset( pSort->NodeList[ Lvl ]->cdxu.Internal.IntData, + pSort->CurTag->KeyType == 'C' ? 32 : 0, + sizeof( pSort->NodeList[ Lvl ]->cdxu.Internal.IntData ) ); + v = ( USHORT ) ( pSort->NodeList[ Lvl ]->Entry_Ct * + ( pSort->CurTag->KeyLength + 8 ) ); + memcpy( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v ], + Value->pItem->item.asString.value, Value->pItem->item.asString.length ); + v += pSort->CurTag->KeyLength; + r = hb_cdxSwapBytes( Link ); + memcpy( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v ], &r, 4 ); + r = hb_cdxSwapBytes( Tag ); + memcpy( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v + 4 ], &r, 4 ); + pSort->NodeList[ Lvl ]->Entry_Ct++; + if( pSort->NodeList[ Lvl ]->Entry_Ct >= pSort->CurTag->MaxKeys ) + { + pa = pSort->NodeList[ Lvl ]->Rght_Ptr; + if( !pSort->Closing ) + pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->Owner ); + else + pSort->NodeList[ Lvl ]->Rght_Ptr = -1; + pSort->NodeList[ Lvl ]->Node_Atr = 0; + hb_cdxIndexPageWrite( pSort->CurTag->Owner, pa, pSort->NodeList[ Lvl ], + sizeof( CDXDATA ) ); + pSort->NodeList[ Lvl ]->Left_Ptr = pa; + hb_cdxSortAddToNode( pSort, ( USHORT ) ( Lvl + 1 ), pa, Link, Value ); + pSort->NodeList[ Lvl ]->Entry_Ct = 0; + } +} /* * -- CDX METHODS -- @@ -306,7 +2538,6 @@ static BOOL hb_cdxWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) #define cdxRecNo NULL #define cdxSetFieldsExtent NULL #define cdxAlias NULL -#define cdxClose NULL #define cdxCreate NULL #define cdxNewArea NULL #define cdxOpen NULL @@ -319,14 +2550,9 @@ static BOOL hb_cdxWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) #define cdxOrderCondition NULL #define cdxClearFilter NULL #define cdxClearLocate NULL -#define cdxClearScope NULL -#define cdxCountScope NULL #define cdxFilterText NULL -#define cdxScopeInfo NULL #define cdxSetFilter NULL #define cdxSetLocate NULL -#define cdxSetScope NULL -#define cdxSkipScope NULL #define cdxCompile NULL #define cdxError NULL #define cdxEvalBlock NULL @@ -337,6 +2563,14 @@ static BOOL hb_cdxWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) #define cdxReadDBHeader NULL #define cdxWhoCares NULL +static ERRCODE cdxClose( AREAP pArea ) +{ + HB_TRACE(HB_TR_DEBUG, ("cdxClose(%p)", pArea)); + + cdxOrderListClear( pArea ); + return SUPER_CLOSE( pArea ); +} + static ERRCODE cdxCreateMemFile( AREAP pArea, LPDBOPENINFO pCreateInfo ) { LPFILEINFO lpMemInfo; @@ -393,8 +2627,8 @@ static ERRCODE cdxGetValueFile( AREAP pArea, USHORT uiIndex, void * pFile ) LPFIELD pField; HB_TRACE(HB_TR_DEBUG, ("cdxGetValueFile(%p, %hu, %p)", pArea, uiIndex, pFile)); - HB_SYMBOL_UNUSED( pFile ); + if( uiIndex > pArea->uiFieldCount ) return FAILURE; @@ -411,7 +2645,7 @@ static ERRCODE cdxGetValueFile( AREAP pArea, USHORT uiIndex, void * pFile ) if( !hb_cdxWriteMemo( pArea, ( LPDBFMEMO ) pField->memo, &lNewRecNo ) ) return FAILURE; if( lNewRecNo != lRecNo ) - hb_nltoa( lNewRecNo, ( char * ) szText, pField->uiLen ); + hb_cdxltoa( lNewRecNo, ( char * ) szText, pField->uiLen ); * ( szText + pField->uiLen ) = szEndChar; } ( ( LPDBFMEMO ) pField->memo )->fChanged = FALSE; @@ -481,12 +2715,17 @@ static ERRCODE cdxOpenMemFile( AREAP pArea, LPDBOPENINFO pOpenInfo ) static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) { - PHB_ITEM pExpr, pResult, pError; - HB_MACRO_PTR pMacro; - USHORT uiType, uiLen = 0; - char * szFileName; + PHB_ITEM pExpr, pKeyExp, pForExp, pResult, pError; + HB_MACRO_PTR pExpMacro, pForMacro; + USHORT uiType, uiLen, uiCount; + char * szFileName, * szTagName; PHB_FNAME pFileName; DBORDERINFO pExtInfo; + LPINDEXINFO pIndex; + LPTAGINFO pTag, pLastTag; + DBFHEADER pHeader; + BYTE bType; + BOOL bNewFile; HB_TRACE(HB_TR_DEBUG, ("cdxOrderCreate(%p, %p)", pArea, pOrderInfo)); @@ -498,70 +2737,85 @@ static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) pExpr = pOrderInfo->itmCobExpr; else /* Otherwise, try compiling the key expression string */ { - if( SELF_COMPILE( pArea, ( BYTE * ) hb_itemGetCPtr( pOrderInfo->abExpr ) ) == FAILURE ) + if( SELF_COMPILE( 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( pArea ); SELF_SKIP( pArea, 1 ); + pExpMacro = pForMacro = NULL; if( hb_itemType( pExpr ) == HB_IT_BLOCK ) { if( SELF_EVALBLOCK( pArea, pExpr ) == FAILURE ) + { + hb_itemRelease( pKeyExp ); return FAILURE; + } pResult = pArea->valResult; pArea->valResult = NULL; } else { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr ); - hb_macroRun( pMacro ); - hb_macroDelete( pMacro ); + pExpMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr ); + hb_macroRun( pExpMacro ); pResult = pExpr; hb_itemCopy( pResult, &hb_stack.Return ); } uiType = hb_itemType( pResult ); + uiLen = 0; switch( uiType ) { case HB_IT_INTEGER: case HB_IT_LONG: case HB_IT_DOUBLE: + bType = 'N'; uiLen = 10; break; case HB_IT_DATE: + bType = 'D'; uiLen = 8; break; case HB_IT_LOGICAL: + bType = 'C'; uiLen = 1; break; case HB_IT_STRING: - uiLen = ( hb_itemGetCLen( pResult ) > CDX_MAX_KEY ) ? CDX_MAX_KEY : - ( USHORT ) hb_itemGetCLen( pResult ); + bType = 'C'; + uiLen = pResult->item.asString.length > CDX_MAX_KEY ? CDX_MAX_KEY : + pResult->item.asString.length; break; } hb_itemRelease( pResult ); /* Make sure uiLen is not 0 */ - if( !uiLen ) + if( uiLen == 0 ) { + hb_itemRelease( pKeyExp ); pError = hb_errNew(); hb_errPutGenCode( pError, EG_DATAWIDTH ); hb_errPutSubCode( pError, 1026 ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATAWIDTH ) ); SELF_ERROR( pArea, pError ); hb_errRelease( pError ); + if( pExpMacro != NULL ) + hb_macroDelete( pExpMacro ); return FAILURE; } /* Check conditional expression */ - pExpr = NULL; + pExpr = pForExp = NULL; if( pArea->lpdbOrdCondInfo ) { /* If we have a codeblock for the conditional expression, use it */ @@ -570,10 +2824,18 @@ static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) else /* Otherwise, try compiling the conditional expression string */ { if( SELF_COMPILE( pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) + { + hb_itemRelease( pKeyExp ); + if( pExpMacro != NULL ) + hb_macroDelete( pExpMacro ); return FAILURE; + } pExpr = pArea->valResult; pArea->valResult = NULL; } + /* Save for later use */ + pForExp = hb_itemNew( NULL ); + hb_itemCopy( pForExp, pExpr ); } /* Test conditional expression */ @@ -582,21 +2844,34 @@ static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) if( hb_itemType( pExpr ) == HB_IT_BLOCK ) { if( SELF_EVALBLOCK( pArea, pExpr ) == FAILURE ) + { + hb_itemRelease( pKeyExp ); + hb_itemRelease( pForExp ); + if( pExpMacro != NULL ) + hb_macroDelete( pExpMacro ); return FAILURE; + } pResult = pArea->valResult; } else { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr ); - hb_macroRun( pMacro ); - hb_macroDelete( pMacro ); + 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 */ @@ -612,7 +2887,7 @@ static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) strcat( szFileName, pFileName->szName ); pExtInfo.itmResult = hb_itemPutC( NULL, "" ); SELF_ORDINFO( pArea, DBOI_BAGEXT, &pExtInfo ); - strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) ); + strcat( szFileName, pExtInfo.itmResult->item.asString.value ); hb_itemRelease( pExtInfo.itmResult ); } else @@ -623,31 +2898,117 @@ static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) { pExtInfo.itmResult = hb_itemPutC( NULL, "" ); SELF_ORDINFO( pArea, DBOI_BAGEXT, &pExtInfo ); - strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) ); + strcat( szFileName, pExtInfo.itmResult->item.asString.value ); hb_itemRelease( pExtInfo.itmResult ); } } + szTagName = ( char * ) hb_xgrab( CDX_MAX_TAG_NAME_LEN + 1 ); + hb_strncpyUpper( szTagName, pFileName->szName, CDX_MAX_TAG_NAME_LEN ); hb_xfree( pFileName ); - /* TODO: - open szFileName - if error - create szFileName - create new tag index - else - find tag index - if not found - create new tag index + /* Close all index */ + cdxOrderListClear( pArea ); + + pIndex = hb_cdxIndexNew( pArea ); + pArea->lpIndexInfo = pIndex; + + /* New file? */ + if( !hb_fsFile( szFileName ) ) + { + pIndex->DiskFile = hb_fsCreate( szFileName, FC_NORMAL ); + bNewFile = TRUE; + } + else + { + pIndex->DiskFile = hb_fsOpen( szFileName, FO_READWRITE | + ( pArea->lpExtendInfo->fExclusive ? + FO_EXCLUSIVE : FO_DENYNONE ) ); + bNewFile = FALSE; + } + + if( pIndex->DiskFile == FS_ERROR ) + { + cdxOrderListClear( pArea ); + hb_xfree( szFileName ); + hb_xfree( szTagName ); + hb_itemRelease( pKeyExp ); + if( pForExp != NULL ) + hb_itemRelease( pForExp ); + if( pExpMacro != NULL ) + hb_macroDelete( pExpMacro ); + if( pForMacro != NULL ) + hb_macroDelete( pForMacro ); + return FAILURE; + } + + /* Corrupted? */ + if( !bNewFile ) + { + bNewFile = ( hb_fsSeek( pIndex->DiskFile, 0, FS_END ) <= CDX_BLOCK_SIZE ); + hb_fsSeek( pIndex->DiskFile, 0, FS_SET ); + } + + if( bNewFile ) + { + pIndex->NextAvail = 0; + pIndex->CompoundTag = hb_cdxTagNew( pIndex, szTagName, -1 ); + pIndex->CompoundTag->OptFlags = 0xE0; + hb_cdxTagIndexTagNew( pIndex->CompoundTag, NULL, NULL, 'C', 10, NULL, NULL, + TRUE, FALSE ); + hb_cdxTagTagOpen( pIndex->CompoundTag, 0 ); + } + else + { + pIndex->CompoundTag = hb_cdxTagNew( pIndex, szTagName, 0 ); + pIndex->CompoundTag->OptFlags = 0xE0; + hb_cdxIndexResetAvailPage( pIndex ); + hb_cdxTagTagOpen( pIndex->CompoundTag, 0 ); + while( !pIndex->CompoundTag->TagEOF ) + { + pTag = hb_cdxTagNew( pIndex, + pIndex->CompoundTag->CurKeyInfo->pItem->item.asString.value, + pIndex->CompoundTag->CurKeyInfo->Tag ); + if( pIndex->TagList == NULL ) + pIndex->TagList = pTag; else - overwrite tag index - go top - while not eof - add key - skip - */ + { + pLastTag = pIndex->TagList; + while( pLastTag->pNext ) + pLastTag = pLastTag->pNext; + pLastTag->pNext = pTag; + } + hb_cdxTagKeyRead( pIndex->CompoundTag, NEXT_RECORD ); + } + } + + /* Update DBF header */ + if( !pArea->lpExtendInfo->fHasMDX ) + { + pFileName = hb_fsFNameSplit( pArea->lpDataInfo->szFileName ); + hb_strncpyUpper( szFileName, pFileName->szName, CDX_MAX_TAG_NAME_LEN ); + hb_xfree( pFileName ); + if( strcmp( szFileName, szTagName ) == 0 && hb_fsRead( pArea->lpDataInfo->hFile, + ( BYTE * ) &pHeader, sizeof( DBFHEADER ) ) == sizeof( DBFHEADER ) ) + { + pHeader.bHasMDX = 1; + hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader, sizeof( DBFHEADER ) ); + } + } hb_xfree( szFileName ); + hb_strncpyUpper( szTagName, pOrderInfo->atomBagName, CDX_MAX_TAG_NAME_LEN ); + uiCount = strlen( szTagName ); + while( uiCount > 0 && szTagName[ uiCount - 1 ] == ' ' ) + uiCount--; + szTagName[ uiCount ] = NULL; + hb_cdxIndexAddTag( pIndex, szTagName, pOrderInfo->abExpr->item.asString.value, + pKeyExp, bType, uiLen, pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->abFor : + NULL, pForExp, pArea->lpdbOrdCondInfo ? + !pArea->lpdbOrdCondInfo->fDescending : TRUE , pOrderInfo->fUnique ); + + hb_xfree( szTagName ); + /* Clear pArea->lpdbOrdCondInfo */ SELF_ORDSETCOND( pArea, NULL ); return SELF_GOTOP( pArea ); @@ -690,10 +3051,17 @@ static ERRCODE cdxOrderListAdd( AREAP pArea, LPDBORDERINFO pOrderInfo ) static ERRCODE cdxOrderListClear( AREAP pArea ) { + LPINDEXINFO pIndex; + HB_TRACE(HB_TR_DEBUG, ("cdxOrderListClear(%p)", pArea)); - HB_SYMBOL_UNUSED( pArea ); - + while( pArea->lpIndexInfo ) + { + pIndex = pArea->lpIndexInfo; + pArea->lpIndexInfo = pArea->lpIndexInfo->pNext; + hb_cdxIndexFree( pIndex ); + } + pArea->lpIndexInfo = NULL; return SUCCESS; } @@ -723,7 +3091,6 @@ static ERRCODE cdxPutValueFile( AREAP pArea, USHORT uiIndex, void * pFile ) ULONG lMemoBlock; HB_TRACE(HB_TR_DEBUG, ("cdxPutValueFile(%p, %hu, %p)", pArea, uiIndex, pFile)); - HB_SYMBOL_UNUSED( pFile ); if( uiIndex > pArea->uiFieldCount ) @@ -804,8 +3171,8 @@ static ERRCODE cdxWriteDBHeader( AREAP pArea ) pHeader.bMonth = ( BYTE ) pTime->tm_mon + 1; pHeader.bDay = ( BYTE ) pTime->tm_mday; pHeader.uiHeaderLen = ( USHORT ) ( 32 * ( pArea->uiFieldCount + 1 ) + 1 ); - pHeader.bHasTag = 0; pHeader.ulRecords = 0; + pHeader.bHasMDX = pArea->lpExtendInfo->fHasMDX; if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader, sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) ) return FAILURE; @@ -816,7 +3183,7 @@ static ERRCODE cdxWriteDBHeader( AREAP pArea ) memset( &pDBField, 0, sizeof( DBFFIELD ) ); strncpy( ( char * ) pDBField.bName, ( ( PHB_DYNS ) pField->sym )->pSymbol->szName, sizeof( pDBField.bName ) ); - pDBField.bType = ( BYTE ) pField->uiType; + pDBField.bType = pField->uiType; switch( pDBField.bType ) { case 'C': @@ -840,8 +3207,8 @@ static ERRCODE cdxWriteDBHeader( AREAP pArea ) break; case 'N': - pDBField.bLen = ( BYTE ) pField->uiLen; - pDBField.bDec = ( BYTE ) pField->uiDec; + pDBField.bLen = pField->uiLen; + pDBField.bDec = pField->uiDec; break; } if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pDBField, @@ -909,14 +3276,9 @@ static RDDFUNCS cdxTable = { cdxBof, cdxOrderInfo, cdxClearFilter, cdxClearLocate, - cdxClearScope, - cdxCountScope, cdxFilterText, - cdxScopeInfo, cdxSetFilter, cdxSetLocate, - cdxSetScope, - cdxSkipScope, cdxCompile, cdxError, cdxEvalBlock, @@ -933,11 +3295,11 @@ static RDDFUNCS cdxTable = { cdxBof, cdxWhoCares }; -HB_FUNC( _DBFCDX ) +HARBOUR HB__DBFCDX( void ) { } -HB_FUNC( DBFCDX_GETFUNCTABLE ) +HARBOUR HB_DBFCDX_GETFUNCTABLE( void ) { RDDFUNCS * pTable; USHORT * uiCount;