/* * $Id$ */ /* * Harbour Project source code: * DBFCDX RDD * * Copyright 1999 Bruno Cantero * 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/). * */ #define SUPERTABLE ( &cdxSuper ) #include #include #include "hbapi.h" #include "hbapiitm.h" #include "hbapirdd.h" #include "hbapierr.h" #include "hbapilng.h" #include "hbdate.h" #include "hbvm.h" #include "hbinit.h" #include "rddsys.ch" #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 { BYTE bVersion; BYTE bYear; BYTE bMonth; BYTE bDay; ULONG ulRecords; USHORT uiHeaderLen; USHORT uiRecordLen; BYTE bReserved1[ 16 ]; BYTE bHasMDX; BYTE bReserved2[ 3 ]; } DBFHEADER; typedef DBFHEADER * LPDBFHEADER; typedef struct _DBFFIELD { BYTE bName[ 11 ]; BYTE bType; BYTE bReserved1[ 4 ]; BYTE bLen; BYTE bDec; BYTE bReserved2[ 13 ]; BYTE bHasTag; } DBFFIELD; typedef DBFFIELD * LPDBFFIELD; typedef struct { ULONG lNextBlock; ULONG lBlockSize; } MEMOHEADER; typedef MEMOHEADER * LPMEMOHEADER; typedef struct _DBFMEMO { BOOL fChanged; /* Memo status */ BYTE * pData; /* Memo data */ USHORT uiLen; /* Len of data */ } DBFMEMO; typedef DBFMEMO * LPDBFMEMO; 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; extern HB_FUNC( _DBFCDX ); extern 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 } HB_INIT_SYMBOLS_END( dbfcdx1__InitSymbols ) #if ! defined(__GNUC__) && ! defined(_MSC_VER) #pragma startup dbfcdx1__InitSymbols #endif static RDDFUNCS cdxSuper = { 0 }; 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; HB_TRACE(HB_TR_DEBUG, ("hb_nltoa(%ld, %p, %hu)", lValue, szBuffer, uiLen)); lAbsNumber = ( lValue > 0 ) ? lValue : - lValue; iCount = iPos = uiLen; while( iCount-- > 0 ) { szBuffer[ iCount ] = ( '0' + lAbsNumber % 10 ); lAbsNumber /= 10; } if( lAbsNumber > 0 ) { memset( szBuffer, ' ', uiLen ); return FALSE; } uiLen--; for( iCount = 0; iCount < uiLen; iCount++ ) if( szBuffer[ iCount ] == '0' ) szBuffer[ iCount ] = ' '; else break; if( lValue < 0 ) { if( szBuffer[ 0 ] != ' ' ) { memset( szBuffer, ' ', iPos ); return FALSE; } for( iCount = uiLen; iCount >= 0; iCount-- ) { if( szBuffer[ iCount ] == ' ' ) { szBuffer[ iCount ] = '-'; break; } } } return TRUE; } static ULONG hb_cdxSwapBytes( ULONG ulValue ) { BYTE * pValue, * pNewValue; ULONG ulNewValue; HB_TRACE(HB_TR_DEBUG, ("hb_cdxSwapBytes(%lu)", ulValue)); pValue = ( BYTE * ) &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 ) { ULONG ulSpaceUsed; MEMOHEADER pMemoHeader; HB_TRACE(HB_TR_DEBUG, ("hb_cdxReadMemo(%p, %p, %lu)", pArea, pMemo, lMemoBlock)); hb_fsSeek( pArea->lpDataInfo->pNext->hFile, lMemoBlock * MEMO_BLOCK, FS_SET ); hb_fsRead( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, sizeof( MEMOHEADER ) ); ulSpaceUsed = hb_cdxSwapBytes( pMemoHeader.lBlockSize ); if( pMemo->uiLen != ulSpaceUsed ) { if( pMemo->uiLen > 0 ) pMemo->pData = ( BYTE * ) hb_xrealloc( pMemo->pData, ulSpaceUsed + 1 ); else pMemo->pData = ( BYTE * ) hb_xgrab( ulSpaceUsed + 1 ); pMemo->uiLen = ulSpaceUsed; } hb_fsRead( pArea->lpDataInfo->pNext->hFile, pMemo->pData, pMemo->uiLen ); } static BOOL hb_cdxWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) { USHORT uiNumBlocks; MEMOHEADER pMemoHeader; BYTE * pBuffer; HB_TRACE(HB_TR_DEBUG, ("hb_cdxWriteMemo(%p, %p, %p)", pArea, pMemo, lNewRecNo)); if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked && !hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_LOCK ) ) return FALSE; uiNumBlocks = 1 + ( pMemo->uiLen + sizeof( MEMOHEADER ) ) / MEMO_BLOCK; if( * lNewRecNo > 0 ) { hb_fsSeek( pArea->lpDataInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET ); hb_fsRead( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, sizeof( MEMOHEADER ) ); if( pMemo->uiLen > hb_cdxSwapBytes( pMemoHeader.lBlockSize ) ) * lNewRecNo = 0; /* Not room for data */ } if( * lNewRecNo == 0 ) /* Add an entry at eof */ { hb_fsSeek( pArea->lpDataInfo->pNext->hFile, 0, FS_SET ); hb_fsRead( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, sizeof( MEMOHEADER ) ); * lNewRecNo = hb_cdxSwapBytes( pMemoHeader.lNextBlock ); pMemoHeader.lNextBlock = hb_cdxSwapBytes( * lNewRecNo + uiNumBlocks ); hb_fsSeek( pArea->lpDataInfo->pNext->hFile, 0, FS_SET ); hb_fsWrite( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, sizeof( MEMOHEADER ) ); } hb_fsSeek( pArea->lpDataInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET ); pMemoHeader.lNextBlock = hb_cdxSwapBytes( 1 ); pMemoHeader.lBlockSize = hb_cdxSwapBytes( pMemo->uiLen ); hb_fsWrite( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, sizeof( MEMOHEADER ) ); if( hb_fsWrite( pArea->lpDataInfo->pNext->hFile, pMemo->pData, pMemo->uiLen ) != pMemo->uiLen ) { if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked ) hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK ); return FALSE; } uiNumBlocks = ( pMemo->uiLen + sizeof( MEMOHEADER ) ) % MEMO_BLOCK; if( uiNumBlocks > 0 ) { pBuffer = ( BYTE * ) hb_xgrab( MEMO_BLOCK ); memset( pBuffer, 0, MEMO_BLOCK ); hb_fsWrite( pArea->lpDataInfo->pNext->hFile, pBuffer, MEMO_BLOCK - uiNumBlocks ); hb_xfree( pBuffer); } if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked ) hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK ); 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( hb_stricmp( 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; hb_cdxltoa( 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 -- */ #define cdxBof NULL #define cdxEof NULL #define cdxFound NULL #define cdxGoBottom NULL #define cdxGoTo NULL #define cdxGoToId NULL #define cdxGoTop NULL #define cdxSkip NULL #define cdxSkipFilter NULL #define cdxSkipRaw NULL #define cdxAddField NULL #define cdxAppend NULL #define cdxCreateFields NULL #define cdxDeleteRec NULL #define cdxDeleted NULL #define cdxFieldCount NULL #define cdxFieldDisplay NULL #define cdxFieldInfo NULL #define cdxFieldName NULL #define cdxFlush NULL #define cdxGetRec NULL #define cdxGetValue NULL #define cdxGetVarLen NULL #define cdxGoCold NULL #define cdxGoHot NULL #define cdxPutRec NULL #define cdxPutValue NULL #define cdxRecAll NULL #define cdxRecCount NULL #define cdxRecInfo NULL #define cdxRecNo NULL #define cdxSetFieldsExtent NULL #define cdxAlias NULL #define cdxCreate NULL #define cdxNewArea NULL #define cdxOpen NULL #define cdxRelease NULL #define cdxStructSize NULL #define cdxSysName NULL #define cdxEval NULL #define cdxPack NULL #define cdxZap NULL #define cdxOrderCondition NULL #define cdxClearFilter NULL #define cdxClearLocate NULL #define cdxFilterText NULL #define cdxSetFilter NULL #define cdxSetLocate NULL #define cdxCompile NULL #define cdxError NULL #define cdxEvalBlock NULL #define cdxRawLock NULL #define cdxLock NULL #define cdxUnLock NULL #define cdxCloseMemFile NULL #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; LPMEMOHEADER pMemoHeader; BOOL bError; PHB_ITEM pError = NULL; HB_TRACE(HB_TR_DEBUG, ("cdxCreateMemFile(%p, %p)", pArea, pCreateInfo)); lpMemInfo = pArea->lpDataInfo->pNext; do { lpMemInfo->hFile = hb_fsCreate( pCreateInfo->abName, FC_NORMAL ); if( lpMemInfo->hFile == FS_ERROR ) { if( !pError ) { pError = hb_errNew(); hb_errPutGenCode( pError, EG_CREATE ); hb_errPutSubCode( pError, 1005 ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); hb_errPutFlags( pError, EF_CANRETRY ); } bError = ( SELF_ERROR( pArea, pError ) == E_RETRY ); } else bError = FALSE; } while( bError ); if( pError ) hb_errRelease( pError ); if( lpMemInfo->hFile == FS_ERROR ) return FAILURE; pMemoHeader = ( LPMEMOHEADER ) hb_xgrab( 512 ); memset( pMemoHeader, 0, 512 ); pMemoHeader->lNextBlock = hb_cdxSwapBytes( 512 / MEMO_BLOCK ); pMemoHeader->lBlockSize = hb_cdxSwapBytes( MEMO_BLOCK ); bError = ( hb_fsWrite( lpMemInfo->hFile, ( BYTE * ) pMemoHeader, 512 ) != 512 ); hb_xfree( pMemoHeader ); hb_fsClose( lpMemInfo->hFile ); lpMemInfo->hFile = FS_ERROR; if( bError ) return FAILURE; else return SUCCESS; } static ERRCODE cdxGetValueFile( AREAP pArea, USHORT uiIndex, void * pFile ) { ULONG lRecNo, lNewRecNo; BYTE * szText, szEndChar; LPFIELD pField; HB_TRACE(HB_TR_DEBUG, ("cdxGetValueFile(%p, %hu, %p)", pArea, uiIndex, pFile)); HB_SYMBOL_UNUSED( pFile ); if( uiIndex > pArea->uiFieldCount ) return FAILURE; pField = pArea->lpFields + uiIndex - 1; szText = pArea->lpExtendInfo->bRecord + pField->uiOffset; if( !( ( LPDBFMEMO ) pField->memo )->pData ) memset( szText, ' ', pField->uiLen ); else { szEndChar = * ( szText + pField->uiLen ); * ( szText + pField->uiLen ) = 0; lRecNo = atol( ( char * ) szText ); lNewRecNo = lRecNo; if( !hb_cdxWriteMemo( pArea, ( LPDBFMEMO ) pField->memo, &lNewRecNo ) ) return FAILURE; if( lNewRecNo != lRecNo ) hb_cdxltoa( lNewRecNo, ( char * ) szText, pField->uiLen ); * ( szText + pField->uiLen ) = szEndChar; } ( ( LPDBFMEMO ) pField->memo )->fChanged = FALSE; return SUCCESS; } static ERRCODE cdxInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { HB_TRACE(HB_TR_DEBUG, ("cdxInfo(%p, %hu, %p)", pArea, uiIndex, pItem)); if( uiIndex == DBI_MEMOEXT ) { hb_itemPutC( pItem, ".fpt" ); return SUCCESS; } return SUPER_INFO( pArea, uiIndex, pItem ); } static ERRCODE cdxOpenMemFile( AREAP pArea, LPDBOPENINFO pOpenInfo ) { LPFILEINFO lpMemInfo; LPMEMOHEADER pMemoHeader; USHORT uiFlags; PHB_ITEM pError = NULL; BOOL bRetry; HB_TRACE(HB_TR_DEBUG, ("cdxOpenMemFile(%p, %p)", pArea, pOpenInfo)); lpMemInfo = pArea->lpDataInfo->pNext; uiFlags = pOpenInfo->fReadonly ? FO_READ : FO_READWRITE; uiFlags |= pOpenInfo->fShared ? FO_DENYNONE : FO_EXCLUSIVE; do { lpMemInfo->hFile = hb_fsOpen( pOpenInfo->abName, uiFlags ); if( lpMemInfo->hFile == FS_ERROR ) { if( !pError ) { pError = hb_errNew(); hb_errPutGenCode( pError, EG_OPEN ); hb_errPutSubCode( pError, 1002 ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); hb_errPutFileName( pError, ( char * ) pOpenInfo->abName ); hb_errPutFlags( pError, EF_CANRETRY ); } bRetry = ( SELF_ERROR( pArea, pError ) == E_RETRY ); } else bRetry = FALSE; } while( bRetry ); if( pError ) hb_errRelease( pError ); if( lpMemInfo->hFile == FS_ERROR ) return FAILURE; pMemoHeader = ( LPMEMOHEADER ) hb_xgrab( 512 ); if( hb_fsRead( lpMemInfo->hFile, ( BYTE * ) pMemoHeader, 512 ) != 512 ) { hb_xfree( pMemoHeader ); return FAILURE; } hb_xfree( pMemoHeader ); return SUCCESS; } static ERRCODE cdxOrderCreate( AREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) { 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)); if( SELF_GOCOLD( 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( 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 { 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: 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 == 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 = 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( 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 */ if( pExpr ) { 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 { 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->lpDataInfo->szFileName ); 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( pArea, DBOI_BAGEXT, &pExtInfo ); strcat( szFileName, pExtInfo.itmResult->item.asString.value ); hb_itemRelease( pExtInfo.itmResult ); } else { strcpy( szFileName, ( char * ) pOrderInfo->abBagName ); pFileName = hb_fsFNameSplit( szFileName ); if( !pFileName->szExtension ) { pExtInfo.itmResult = hb_itemPutC( NULL, "" ); SELF_ORDINFO( pArea, DBOI_BAGEXT, &pExtInfo ); 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 ); /* 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 { 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 ); } static ERRCODE cdxOrderDestroy( AREAP pArea, LPDBORDERINFO pOrderInfo ) { HB_TRACE(HB_TR_DEBUG, ("cdxOrderDestroy(%p, %p)", pArea, pOrderInfo)); HB_SYMBOL_UNUSED( pArea ); HB_SYMBOL_UNUSED( pOrderInfo ); return SUCCESS; } static ERRCODE cdxOrderInfo( AREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo ) { HB_TRACE(HB_TR_DEBUG, ("cdxOrderInfo(%p, %hu, %p)", pArea, uiIndex, pInfo)); HB_SYMBOL_UNUSED( pArea ); switch( uiIndex ) { case DBOI_BAGEXT: hb_itemPutC( pInfo->itmResult, ".cdx" ); break; } return SUCCESS; } static ERRCODE cdxOrderListAdd( AREAP pArea, LPDBORDERINFO pOrderInfo ) { HB_TRACE(HB_TR_DEBUG, ("cdxOrderListAdd(%p, %p)", pArea, pOrderInfo)); HB_SYMBOL_UNUSED( pArea ); HB_SYMBOL_UNUSED( pOrderInfo ); return SUCCESS; } static ERRCODE cdxOrderListClear( AREAP pArea ) { LPINDEXINFO pIndex; HB_TRACE(HB_TR_DEBUG, ("cdxOrderListClear(%p)", pArea)); while( pArea->lpIndexInfo ) { pIndex = pArea->lpIndexInfo; pArea->lpIndexInfo = pArea->lpIndexInfo->pNext; hb_cdxIndexFree( pIndex ); } pArea->lpIndexInfo = NULL; return SUCCESS; } static ERRCODE cdxOrderListFocus( AREAP pArea, LPDBORDERINFO pOrderInfo ) { HB_TRACE(HB_TR_DEBUG, ("cdxOrderListFocus(%p, %p)", pArea, pOrderInfo)); HB_SYMBOL_UNUSED( pArea ); HB_SYMBOL_UNUSED( pOrderInfo ); return SUCCESS; } static ERRCODE cdxOrderListRebuild( AREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("cdxOrderListRebuild(%p)", pArea)); HB_SYMBOL_UNUSED( pArea ); return SUCCESS; } static ERRCODE cdxPutValueFile( AREAP pArea, USHORT uiIndex, void * pFile ) { LPFIELD pField; BYTE * szText, szEndChar; ULONG lMemoBlock; HB_TRACE(HB_TR_DEBUG, ("cdxPutValueFile(%p, %hu, %p)", pArea, uiIndex, pFile)); HB_SYMBOL_UNUSED( pFile ); if( uiIndex > pArea->uiFieldCount ) return FAILURE; pField = pArea->lpFields + uiIndex - 1;; szText = pArea->lpExtendInfo->bRecord + pField->uiOffset; szEndChar = * ( szText + pField->uiLen ); * ( szText + pField->uiLen ) = 0; lMemoBlock = atol( ( char * ) szText ) * MEMO_BLOCK; * ( szText + pField->uiLen ) = szEndChar; if( lMemoBlock > 0 ) hb_cdxReadMemo( pArea, ( LPDBFMEMO ) pField->memo, lMemoBlock ); else if( ( ( LPDBFMEMO ) pField->memo )->pData ) { hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData ); memset( pField->memo, 0, sizeof( DBFMEMO ) ); } return SUCCESS; } static ERRCODE cdxSeek( AREAP pArea, BOOL bSoftSeek, PHB_ITEM pKey, BOOL bFindLast ) { HB_TRACE(HB_TR_DEBUG, ("cdxSeek(%p, %d, %p, %d)", pArea, bSoftSeek, pKey, bFindLast)); HB_SYMBOL_UNUSED( pArea ); HB_SYMBOL_UNUSED( bSoftSeek ); HB_SYMBOL_UNUSED( pKey ); HB_SYMBOL_UNUSED( bFindLast ); return SUCCESS; } static ERRCODE cdxWriteDBHeader( AREAP pArea ) { DBFHEADER pHeader; DBFFIELD pDBField; USHORT uiCount; LPFIELD pField; time_t t; struct tm * pTime; HB_TRACE(HB_TR_DEBUG, ("cdxWriteDBHeader(%p)", pArea)); memset( &pHeader, 0, sizeof( DBFHEADER ) ); pHeader.uiRecordLen = 1; pHeader.bVersion = 0x03; pField = pArea->lpFields; for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) { switch( pField->uiType ) { case 'C': case 'N': pHeader.uiRecordLen += pField->uiLen; break; case 'M': pHeader.uiRecordLen += 10; pHeader.bVersion = 0xF5; pArea->lpExtendInfo->fHasMemo = TRUE; break; case 'D': pHeader.uiRecordLen += 8; break; case 'L': pHeader.uiRecordLen += 1; break; } pField++; } time( &t ); pTime = localtime( &t ); pHeader.bYear = ( BYTE ) pTime->tm_year; pHeader.bMonth = ( BYTE ) pTime->tm_mon + 1; pHeader.bDay = ( BYTE ) pTime->tm_mday; pHeader.uiHeaderLen = ( USHORT ) ( 32 * ( pArea->uiFieldCount + 1 ) + 1 ); pHeader.ulRecords = 0; pHeader.bHasMDX = pArea->lpExtendInfo->fHasMDX; if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader, sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) ) return FAILURE; pField = pArea->lpFields; for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) { memset( &pDBField, 0, sizeof( DBFFIELD ) ); strncpy( ( char * ) pDBField.bName, ( ( PHB_DYNS ) pField->sym )->pSymbol->szName, sizeof( pDBField.bName ) ); pDBField.bType = pField->uiType; switch( pDBField.bType ) { case 'C': pDBField.bLen = pField->uiLen & 0xFF; pDBField.bDec = pField->uiLen >> 8; break; case 'M': pDBField.bLen = 10; pDBField.bDec = 0; break; case 'D': pDBField.bLen = 8; pDBField.bDec = 0; break; case 'L': pDBField.bLen = 1; pDBField.bDec = 0; break; case 'N': pDBField.bLen = pField->uiLen; pDBField.bDec = pField->uiDec; break; } if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pDBField, sizeof( DBFFIELD ) ) != sizeof( DBFFIELD ) ) return FAILURE; pField++; } if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) "\15\32", 2 ) != 2 ) return FAILURE; return SUCCESS; } static RDDFUNCS cdxTable = { cdxBof, cdxEof, cdxFound, cdxGoBottom, cdxGoTo, cdxGoToId, cdxGoTop, cdxSeek, cdxSkip, cdxSkipFilter, cdxSkipRaw, cdxAddField, cdxAppend, cdxCreateFields, cdxDeleteRec, cdxDeleted, cdxFieldCount, cdxFieldDisplay, cdxFieldInfo, cdxFieldName, cdxFlush, cdxGetRec, cdxGetValue, cdxGetVarLen, cdxGoCold, cdxGoHot, cdxPutRec, cdxPutValue, cdxRecAll, cdxRecCount, cdxRecInfo, cdxRecNo, cdxSetFieldsExtent, cdxAlias, cdxClose, cdxCreate, cdxInfo, cdxNewArea, cdxOpen, cdxRelease, cdxStructSize, cdxSysName, cdxEval, cdxPack, cdxZap, cdxOrderListAdd, cdxOrderListClear, cdxOrderListFocus, cdxOrderListRebuild, cdxOrderCondition, cdxOrderCreate, cdxOrderDestroy, cdxOrderInfo, cdxClearFilter, cdxClearLocate, cdxFilterText, cdxSetFilter, cdxSetLocate, cdxCompile, cdxError, cdxEvalBlock, cdxRawLock, cdxLock, cdxUnLock, cdxCloseMemFile, cdxCreateMemFile, cdxGetValueFile, cdxOpenMemFile, cdxPutValueFile, cdxReadDBHeader, cdxWriteDBHeader, cdxWhoCares }; HB_FUNC( _DBFCDX ) { } HB_FUNC( DBFCDX_GETFUNCTABLE ) { RDDFUNCS * pTable; USHORT * uiCount; uiCount = ( USHORT * ) hb_parnl( 1 ); * uiCount = RDDFUNCSCOUNT; pTable = ( RDDFUNCS * ) hb_parnl( 2 ); if( pTable ) hb_retni( hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ) ); else hb_retni( FAILURE ); }