3303 lines
98 KiB
C
3303 lines
98 KiB
C
/*
|
||
* $Id$
|
||
*/
|
||
|
||
/*
|
||
* Harbour Project source code:
|
||
* DBFCDX RDD
|
||
*
|
||
* Copyright 1999 Bruno Cantero <bruno@issnet.net>
|
||
* www - http://www.harbour-project.org
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version, with one exception:
|
||
*
|
||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||
* an executable, this does not by itself cause the resulting executable
|
||
* to be covered by the GNU General Public License. Your use of that
|
||
* executable is in no way restricted on account of linking the HRL
|
||
* and/or HVM code into it.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program; if not, write to the Free Software
|
||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||
* their web site at http://www.gnu.org/).
|
||
*
|
||
*/
|
||
|
||
#define SUPERTABLE ( &cdxSuper )
|
||
|
||
#include <time.h>
|
||
#include <ctype.h>
|
||
|
||
#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<61>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 );
|
||
}
|
||
|