summaryrefslogtreecommitdiff
path: root/src/core/xbixbase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/xbixbase.cpp')
-rwxr-xr-xsrc/core/xbixbase.cpp792
1 files changed, 792 insertions, 0 deletions
diff --git a/src/core/xbixbase.cpp b/src/core/xbixbase.cpp
new file mode 100755
index 0000000..40c1563
--- /dev/null
+++ b/src/core/xbixbase.cpp
@@ -0,0 +1,792 @@
+/* xbixbase.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+ Base index class
+
+*/
+
+#include "xbase.h"
+#ifdef XB_INDEX_SUPPORT
+
+namespace xb{
+
+/***********************************************************************/
+//! @brief Class constructor.
+/*!
+ /param dbf Pointer to dbf instance.
+*/
+xbIx::xbIx( xbDbf *dbf ) : xbFile( dbf->GetXbasePtr()) {
+ this->dbf = dbf;
+ vpCurTag = NULL;
+ cNodeBuf = NULL;
+ bLocked = xbFalse;
+}
+/***********************************************************************/
+//! @brief Class Destructor.
+xbIx::~xbIx(){}
+
+
+/***********************************************************************/
+//! @brief Add Keys for record number
+/*!
+ For a given a record number, add keys to each tag in the index file
+ if it was updated
+
+ \param ulRecNo Record number to add keys for
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbIx::AddKeys( xbUInt32 ulRecNo ){
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+ xbInt16 i = 0;
+ xbInt16 iKeySts;
+// std::cout << "xbIx::AddKeys\n";
+
+ try{
+ void * vpTag;
+ xbInt16 iTagCount = GetTagCount();
+
+ for( i = 0; i < iTagCount; i++ ){
+ vpTag = GetTag( i );
+
+ iKeySts = GetKeySts( vpTag );
+// std::cout << "AddKeys() KeySts = " << iKeySts << "\n";
+
+ if( iKeySts == 1 || iKeySts == 2 ){
+ if(( iRc = UpdateTagKey( 'A', vpTag, ulRecNo )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::AddKeys() Exception Caught. Error Stop = [%d] iRc = [%d] Tag=[%d]", iErrorStop, iRc, i );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+//! @brief Allocate memory for index node.
+/*!
+ Allocate an index node.
+
+ \param ulBufSize Size of buffer to allocate
+ \returns null on error<br>Pointer to newly allocated xbIxNode on success
+*/
+xbIxNode * xbIx::AllocateIxNode( xbUInt32 ulBufSize, xbInt16 )
+{
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+
+ try{
+ xbIxNode * pNode = (xbIxNode *) calloc( 1, sizeof( xbIxNode ));
+ if( pNode == NULL ){
+ iErrorStop = 100;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+ if( ulBufSize == 0 )
+ ulBufSize = GetBlockSize();
+
+ pNode->ulBufSize = ulBufSize;
+ pNode->cpBlockData = (char *) calloc( 1, ulBufSize );
+ if( pNode->cpBlockData == NULL ){
+ free( pNode );
+ iErrorStop = 110;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+ return pNode;
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::AllocateIxNode() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return NULL;
+}
+
+
+/***********************************************************************/
+//! @brief Binary search for given value on an index node.
+/*!
+
+ Binary search for key lookups
+ \param cKeyType Key type
+ \param npNode Pointer to index node for search
+ \param lKeyItemLen Lenth of key plus pointer values
+ \param vpKey Pointer to key value
+ \param lSearchKeyLen length of key to search
+ \param iCompRc output return code from the CompareKey routine. CompareKey returns an
+ integer value less than, equal to or greater than zero in when comparing values
+
+ \param bDescending xbTrue for descending index key lookup.<br>
+ xbFalse for ascending index key lookup.
+ \return The position in the node the key was found, if multiples it returns the first occurrence.
+ If the key is not found, it returns the slot it should be in.
+*/
+
+xbInt16 xbIx::BSearchBlock( char cKeyType, xbIxNode *npNode, xbInt32 lKeyItemLen, const void *vpKey,
+ xbInt32 lSearchKeyLen, xbInt16 &iCompRc, xbBool bDescending ) const {
+ xbInt32 lLo = 0;
+ xbInt32 lHi = 0;
+ xbInt32 lMid = 0;
+ xbInt32 lKeyCnt = GetKeyCount( npNode );
+
+
+ if( !bDescending ){
+ lHi = lKeyCnt - 1;
+
+ while( lLo <= lHi ){
+ lMid = (lLo + lHi) / 2;
+ iCompRc = CompareKey( cKeyType, GetKeyData( npNode, lMid, lKeyItemLen ), vpKey, (size_t) lSearchKeyLen );
+ if( iCompRc > 0 )
+ lHi = lMid - 1;
+ else if( iCompRc < 0 )
+ lLo = lMid + 1;
+ else{ // found match, look for leftmost occurrence
+
+ xbInt32 lFoundPos = lMid;
+ lMid--;
+ while( lMid >= 0 && CompareKey( cKeyType, GetKeyData( npNode, lMid, lKeyItemLen ), vpKey, (size_t) lSearchKeyLen ) == 0 ){
+ lFoundPos = lMid;
+ lMid--;
+ }
+ iCompRc = 0;
+ lLo = lFoundPos;
+ lHi = -1;
+ }
+ }
+ // update the compare key results
+ if( lMid != lLo ){
+ if( lLo >= lKeyCnt )
+ iCompRc = 1;
+ else
+ iCompRc = CompareKey( cKeyType, GetKeyData( npNode, lLo, lKeyItemLen ), vpKey, (size_t) lSearchKeyLen );
+ }
+ return (xbInt16) lLo;
+
+ } else { // descending key
+
+ lLo = lKeyCnt - 1;
+ while( lLo >= lHi && lHi != -1 ){
+ lMid = (lLo + lHi) / 2;
+ iCompRc = CompareKey( cKeyType, GetKeyData( npNode, lMid, lKeyItemLen ), vpKey, (size_t) lSearchKeyLen );
+
+ if( iCompRc > 0 ) {
+ lHi = lMid + 1;
+ }
+ else if( iCompRc < 0) {
+ lLo = lMid - 1;
+ }
+ else{ // found match, look for leftmost occurrence
+
+ xbInt32 lFoundPos = lMid;
+ lMid--;
+ while( lMid >= 0 && CompareKey( cKeyType, GetKeyData( npNode, lMid, lKeyItemLen ), vpKey, (size_t) lSearchKeyLen ) == 0 ){
+ lFoundPos = lMid;
+ lMid--;
+ }
+ iCompRc = 0;
+ lHi = lFoundPos;
+ lLo = -1;
+ }
+ }
+
+ // std::cout << "BSB1 lo = " << lLo << " mid = " << lMid << " hi = " << lHi << " keycnt = " << lKeyCnt << " iCompRc = " << iCompRc << "\n"; // key=" << (char *) vpKey << "\n";
+ if( lLo < 0 && iCompRc < 0 )
+ iCompRc = 1;
+ else if( iCompRc != 0 ) {
+ iCompRc = CompareKey( cKeyType, GetKeyData( npNode, (lLo < 0 ? 0 : lLo), lKeyItemLen ), vpKey, (size_t) lSearchKeyLen );
+ }
+ // std::cout << "BSB2 lo = " << lLo << " mid = " << lMid << " hi = " << lHi << " keycnt = " << lKeyCnt << " iCompRc = " << iCompRc << "\n"; // key=" << (char *) vpKey << "\n";
+ return (xbInt16) lHi;
+ }
+
+ // should never get here
+ // return (xbInt16) 0;
+}
+
+/***********************************************************************/
+//! @brief Check for duplicate keys.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::CheckForDupKeys(){
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+ xbInt16 i = 0;
+
+ try{
+ void * vpTag;
+ xbInt16 iTagCount = GetTagCount();
+ for( i = 0; i < iTagCount; i++ ){
+ vpTag = GetTag( i );
+ if(( iRc = CheckForDupKey( vpTag )) < XB_NO_ERROR ){
+ iErrorStop = 10;
+ throw iRc;
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ if( iRc != XB_KEY_NOT_UNIQUE ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIxBase::CheckForDupKeys() Exception Caught. Error Stop = [%d] iRc = [%d] Tag=[%d]", iErrorStop, iRc, i );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ }
+ return iRc;
+}
+/***********************************************************************/
+//! @brief Close index file.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbIx::Close(){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+ if(( iRc = xbFclose()) != XB_NO_ERROR ){
+ iErrorStop = 20;
+ throw iRc;
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::Close() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+//! @brief Compare keys.
+/*!
+ \param cKeyType C - Character compare.<br>
+ N - Numeric BCD compare.<br>
+ D - Numeric compare.<br>
+ F - Numeric compare.<br>
+ \param v1 Left compare.<br>v2 - Right Compare.
+ \param iSearchKeyLen Length of key compare.
+ \returns 1 - Left operand is greater then right operand.<br>
+ 0 - Left operand is equal to right operand.<br>
+ -1 - Left operand is less than right operand.
+*/
+inline xbInt16 xbIx::CompareKey( char cKeyType, const void *v1, const void *v2, size_t iSearchKeyLen ) const{
+ if( cKeyType == 'C' ){ // character compare
+ return memcmp( v1, v2, iSearchKeyLen );
+ } else if( cKeyType == 'N' ){ // numeric bcd compare, mdx bcd numeric indices
+ xbBcd bcdk1( v1 );
+ return bcdk1.Compare( v2 );
+ } else if( cKeyType == 'D' || cKeyType == 'F' ){ // julian date compare, ndx float numeric indices
+ xbDouble *d1 = (xbDouble *) v1;
+ xbDouble *d2 = (xbDouble *) v2;
+ if( *d1 < *d2 )
+ return -1;
+ else if( *d1 > *d2 )
+ return 1;
+ else
+ return 0;
+ } else {
+// std::cout << "Unhandled key type [" << cKeyType << "]\n";
+ }
+ return XB_NO_ERROR;
+}
+/***********************************************************************/
+//! @brief Create Keys for record number
+/*!
+ \param iOpt 0 Build a key for FindKey usage, only rec buf 0.<br>
+ 1 Append Mode, Create key for an append, only use rec buf 0, set updated switch.<br>
+ 2 Update Mode, Create old version and new version keys, check if different, set update switch appropriately.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::CreateKeys( xbInt16 iOpt ) {
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+ xbInt16 i = 0;
+
+ try{
+ void * vpTag;
+ xbInt16 iTagCount = GetTagCount();
+
+ for( i = 0; i < iTagCount; i++ ){
+ vpTag = GetTag( i );
+ if(( iRc = CreateKey( vpTag, iOpt )) < XB_NO_ERROR ){
+ iErrorStop = 10;
+ throw iRc;
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::CreateKeys() Exception Caught. Error Stop = [%d] iRc = [%d] Tag=[%d]", iErrorStop, iRc, i );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return XB_NO_ERROR;
+}
+/***********************************************************************/
+//! @brief Delete keys for record number
+/*!
+ Delete keys to each tag in the index file if it was updated as determined
+ by CreateKeys function
+
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+//xbInt16 xbIx::DeleteKeys( xbUInt32 ulRecNo ){
+
+xbInt16 xbIx::DeleteKeys(){
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+ xbInt16 i = 0;
+
+ try{
+ void * vpTag;
+ xbInt16 iTagCount = GetTagCount();
+
+ for( i = 0; i < iTagCount; i++ ){
+ vpTag = GetTag( i );
+ if( GetKeySts( vpTag ) > 1 ){ // 0 = no update 1 = add 2 = update, 3 = delete
+ if(( iRc = UpdateTagKey( 'D', vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 10;
+ throw iRc;
+ }
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::DeleteKeys() Exception Caught. Error Stop = [%d] iRc = [%d] Tag=[%d]", iErrorStop, iRc, i );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+#ifdef XB_DEBUG_SUPPORT
+//! @brief Dump anode for debug purposes.
+/*!
+ \param pNode Pointer to node to dump.
+ \param iOption 0 = stdout<br>
+ 1 = Syslog<br>
+ 2 = Both<br>
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbIx::DumpNode( void *, xbIxNode *pNode, xbInt16 iOption ) const
+{
+ xbString s;
+ s.Sprintf( "Dump Node Block=[%d] CurKey=[%d]", pNode->ulBlockNo, pNode->iCurKeyNo );
+ xbase->WriteLogMessage( s, iOption );
+
+ return XB_NO_ERROR;
+}
+#endif // XB_DEBUG_SUPPORT
+
+/***********************************************************************/
+//! @brief Find double key
+/*!
+ \param vpTag Pointer to tag to search.
+ \param dKey Double value to search for.
+ \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
+ xbFalse - Don't retrieve record, check for key existence only.
+ \returns XB_NO_ERROR - Key found.<br>
+ XB_NOT_FOUND - Key not found.<br>
+ <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw ){
+ return FindKey( vpTag, &dKey, 8, iRetrieveSw );
+}
+/***********************************************************************/
+//! @brief Find string key
+/*!
+ \param vpTag Pointer to tag to search.
+ \param sKey String data to search for.
+ \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
+ xbFalse - Don't retrieve record, check for key existence only.
+ \returns XB_NO_ERROR - Key found.<br>
+ XB_NOT_FOUND - Key not found.<br>
+ <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::FindKey( void *vpTag, const xbString &sKey, xbInt16 iRetrieveSw ){
+ return FindKey( vpTag, sKey.Str(), (xbInt32) sKey.Len(), iRetrieveSw );
+}
+/***********************************************************************/
+//! @brief Find character key
+/*!
+ \param vpTag Pointer to tag to search.
+ \param cKey String data to search for.
+ \param lKeyLen Length of key to search for.
+ \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
+ xbFalse - Don't retrieve record, check for key existence only.
+ \returns XB_NO_ERROR - Key found.<br>
+ XB_NOT_FOUND - Key not found.<br>
+ <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::FindKey( void *vpTag, const char *cKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw ){
+ return FindKey( vpTag, (void *) cKey, lKeyLen, iRetrieveSw );
+}
+/***********************************************************************/
+//! @brief Find bcd key
+/*!
+ \param vpTag Pointer to tag to search.
+ \param bcd BCD data to search for.
+ \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
+ xbFalse - Don't retrieve record, check for key existence only.
+
+ \returns XB_NO_ERROR - Key found.<br>
+ XB_NOT_FOUND - Key not found.<br>
+ <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::FindKey( void *vpTag, const xbBcd &bcd, xbInt16 iRetrieveSw ){
+ return FindKey( vpTag, bcd.GetBcd(), 12, iRetrieveSw );
+}
+/***********************************************************************/
+//! @brief Find date key
+/*!
+ \param vpTag Pointer to tag to search.
+ \param dtKey Date data to search for.
+ \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
+ xbFalse - Don't retrieve record, check for key existence only.
+ \returns XB_NO_ERROR - Key found.<br>
+ XB_NOT_FOUND - Key not found.<br>
+ <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::FindKey( void *vpTag, const xbDate &dtKey, xbInt16 iRetrieveSw ){
+ xbDouble d = (xbDouble) dtKey.JulianDays();
+ return FindKey( vpTag, &d, 8, iRetrieveSw );
+}
+/***********************************************************************/
+//! @brief Free all nodes in a linked list.
+/*!
+ \param np Pointer to first node in linked list to free.
+ \returns NULL.
+*/
+xbIxNode *xbIx::FreeNodeChain( xbIxNode *np ){
+
+ // routine returns NULL
+ if( np ){
+ // free memory for a given chain of nodes
+ xbIxNode * np2;
+
+ // Clear the previous node's next pointer
+ if( np->npPrev )
+ np->npPrev->npNext = NULL;
+
+ // Clear out the tree
+ while( np ){
+ np2 = np->npNext;
+ NodeFree( np );
+ np = NULL;
+ np = np2;
+ }
+ }
+ return NULL;
+}
+/***********************************************************************/
+//! @brief Read block for block number.
+/*!
+ Routine to read a node/block out of an index file and store in xbIxNode structure
+ \param vpTag Pointer to tag.
+ \param ulBlockNo Block number to read off disk.
+ \param iOpt
+ 0 = Node is read into block buffer, not added to the node chain<br>
+ 1 = Node is read into new xbIxNode, then added to the node chain, and sets CurNode with new node<br>
+ 2 = Node is read into new xbIxNode, not added to the node chain<br>
+ CurNode points to new node<br>
+ \param ulAddlBuf Additional buffer size added to memory
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+
+*/
+
+xbInt16 xbIx::GetBlock( void *vpTag, xbUInt32 ulBlockNo, xbInt16 iOpt, xbUInt32 ulAddlBuf ){
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbIxNode *np = NULL;
+ try{
+
+ if( !vpTag && iOpt == 1 ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+
+ // set target location of block read to read
+ char *cp;
+ if( iOpt == 0 )
+ cp = cNodeBuf;
+ else{
+ if(( np = AllocateIxNode(GetBlockSize() + ulAddlBuf )) == NULL ){
+ iErrorStop = 110;
+ iRc = XB_NO_MEMORY;
+ throw( iRc );
+ }
+ cp = np->cpBlockData;
+ }
+ if(( iRc = ReadBlock( ulBlockNo, GetBlockSize(), cp )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+ if( iOpt == 0 )
+ return iRc;
+ np->ulBlockNo = ulBlockNo;
+ np->iCurKeyNo = 0;
+ if( iOpt == 1 )
+ AppendNodeChain( vpTag, np );
+ else if( iOpt == 2 ){
+ std::cout << "Future use stub. xbIxbase::GetBlock() option 2 not coded.\n";
+ iErrorStop = 130;
+ iRc = XB_INVALID_OPTION;
+ throw iRc;
+ // SetCurNode( vpTag, np );
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::GetBlock() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ if( np ) NodeFree( np );
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+//! @brief Get pointer to current tag.
+/*!
+ \returns Pointer to current tag.
+*/
+
+void *xbIx::GetCurTag() const {
+ return vpCurTag;
+}
+/***********************************************************************/
+//! @brief Get pointer to dbf.
+/*!
+ \returns Pointer to dbf.
+*/
+xbDbf *xbIx::GetDbf() const {
+ return this->dbf;
+}
+/***********************************************************************/
+//! @brief Get the first key for the current tag.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetFirstKey(){
+ return GetFirstKey( vpCurTag, 0 );
+}
+
+/***********************************************************************/
+//! @brief Get the first key for a given tag.
+/*!
+ \param vpTag Tag for get first key operation.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetFirstKey( void *vpTag ){
+ return GetFirstKey( vpTag, 0 );
+}
+/***********************************************************************/
+//! @brief Get the last key for the current tag.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetLastKey(){
+ return GetLastKey( 0, vpCurTag, 0 );
+}
+/***********************************************************************/
+//! @brief Get the last key for a given tag.
+/*!
+ \param vpTag Tag for get last key operation.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetLastKey( void *vpTag ){
+ return GetLastKey( 0, vpTag, 0 );
+}
+
+/***********************************************************************/
+//! @brief Get the file lock status.
+/*!
+ \returns xbTrue - Index file is locked.<br>xbFalse - Index file is not locked.
+*/
+xbBool xbIx::GetLocked() const {
+ return bLocked;
+}
+
+/***********************************************************************/
+//! @brief Get the key count for number of keys on a node.
+/*!
+ \param np Given node for key count.
+ \returns Number of keys on the node.
+*/
+xbInt32 xbIx::GetKeyCount( xbIxNode *np ) const {
+ // assumes the first four bytes of the block is a four byte number
+ // representing the number of keys contained on the block
+ return eGetInt32( np->cpBlockData );
+}
+/***********************************************************************/
+//! @brief Get key data for a given key number.
+/*!
+ \param np Given node for key retrieval.
+ \param iKeyNo Which key to pull.
+ \param iKeyItemLen Length of key plus pointers.
+ \returns Pointer to a given key.
+*/
+char * xbIx::GetKeyData( xbIxNode *np, xbInt16 iKeyNo, xbInt16 iKeyItemLen ) const {
+ if( !np ) return NULL;
+ char *p = np->cpBlockData;
+ xbUInt32 ulKeyCnt = eGetUInt32( p );
+ if( iKeyNo < 0 || iKeyNo > (xbInt16) ulKeyCnt ) return NULL;
+ xbInt16 iOffset = 12 + (iKeyNo * iKeyItemLen);
+ p+=iOffset;
+ return p;
+}
+/***********************************************************************/
+//! @brief Get the next key for the current tag.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetNextKey(){
+ return GetNextKey( vpCurTag, 0 );
+}
+/***********************************************************************/
+//! @brief Get the next key for the given tag.
+/*!
+ \param vpTag Tag for next key operation.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetNextKey( void *vpTag ){
+ return GetNextKey( vpTag, 0 );
+}
+/***********************************************************************/
+//! @brief Get the prev key for the current tag.
+/*!
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetPrevKey(){
+ return GetPrevKey( vpCurTag, 0 );
+}
+/***********************************************************************/
+//! @brief Get the previous key for the given tag.
+/*!
+ \param vpTag Tag for previous key operation.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::GetPrevKey( void *vpTag ){
+ return GetPrevKey( vpTag, 0 );
+}
+/***********************************************************************/
+//! @brief Free an index node
+/*!
+ \param ixNode Pointer to index node to free.
+ \returns void
+*/
+void xbIx::NodeFree( xbIxNode *ixNode ){
+ if( ixNode ){
+ if( ixNode->cpBlockData ){
+ free( ixNode->cpBlockData );
+ ixNode->cpBlockData = NULL;
+ }
+ free( ixNode );
+ ixNode = NULL;
+ }
+}
+/***********************************************************************/
+//! @brief Open an index file.
+/*!
+ MDX files are opened automatically and don't need opened.
+ NDX files that are associated with the DBF file are opened automatically.
+
+ Non production indexes that haven't been opened will need to be opened to be used.
+ \param sFileName Index file name to open.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbIx::Open( const xbString & sFileName ){
+
+ // There are no locking requirements when opening an NDX index
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+ /* copy the file name to the class variable */
+ this->SetFileName( sFileName );
+
+ if( !FileExists()){
+ iErrorStop = 10;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+ /* open the file */
+ if(( iRc = xbFopen( dbf->GetOpenMode(), dbf->GetShareMode())) != XB_NO_ERROR ){
+ iErrorStop = 20;
+ throw iRc;
+ }
+ if(( iRc = ReadHeadBlock()) != XB_NO_ERROR ){
+ iErrorStop = 40;
+ throw iRc;
+ }
+ SetCurTag( (xbInt16) 0 ); // default the first tag as the current tag
+ }
+
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIx::Open( %s ) Exception Caught. Error Stop = [%d] iRc = [%d]", sFileName.Str(), iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+/***********************************************************************/
+//! @brief Set the current tag.
+/*!
+ \param vpCurTag Pointer to tag to set as current.
+ \returns void
+*/
+void xbIx::SetCurTag( void *vpCurTag ){
+ this->vpCurTag = vpCurTag;
+}
+/***********************************************************************/
+//! @brief Set the dbf pointer.
+/*!
+ \param dbf Dbf pointer to set.
+ \returns void
+*/
+void xbIx::SetDbf( xbDbf *dbf ){
+ this->dbf = dbf;
+}
+/***********************************************************************/
+//! @brief Set the file lock status.
+/*!
+ \param bLocked xbTrue - Set to locked.<br>xbFalse - Set to unlocked.
+ \returns void
+*/
+void xbIx::SetLocked( xbBool bLocked ){
+ this->bLocked = bLocked;
+}
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_INDEX_SUPPORT */