summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rwxr-xr-xsrc/core/xbbcd.cpp5
-rwxr-xr-xsrc/core/xbblockread.cpp271
-rwxr-xr-xsrc/core/xbdbf.cpp154
-rwxr-xr-xsrc/core/xbdbf3.cpp8
-rwxr-xr-xsrc/core/xbdbf4.cpp19
-rwxr-xr-xsrc/core/xbexp.cpp31
-rwxr-xr-xsrc/core/xbfile.cpp286
-rwxr-xr-xsrc/core/xbfilter.cpp50
-rwxr-xr-xsrc/core/xbixmdx.cpp50
-rwxr-xr-xsrc/core/xbixndx.cpp3
-rwxr-xr-xsrc/core/xblog.cpp4
-rwxr-xr-xsrc/core/xbssv.cpp111
-rwxr-xr-xsrc/core/xbstring.cpp71
-rwxr-xr-xsrc/core/xbtblmgr.cpp85
-rwxr-xr-xsrc/core/xbxbase.cpp54
15 files changed, 998 insertions, 204 deletions
diff --git a/src/core/xbbcd.cpp b/src/core/xbbcd.cpp
index ff64110..f86e74f 100755
--- a/src/core/xbbcd.cpp
+++ b/src/core/xbbcd.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -268,7 +268,6 @@ xbInt16 xbBcd::Compare( const xbBcd &bcdIn ){
return -1;
}
-
/***********************************************************************/
unsigned char xbBcd::GetEncDigitsNoSign() const {
unsigned char c = bcd.cEncDigits << 1;
@@ -277,7 +276,7 @@ unsigned char xbBcd::GetEncDigitsNoSign() const {
/***********************************************************************/
unsigned xbBcd::GetSign() const {
//return bcd.Sign;
- return bcd.cEncDigits >> 7;
+ return (unsigned) bcd.cEncDigits >> 7;
}
/***********************************************************************/
unsigned xbBcd::GetSigDigits() const {
diff --git a/src/core/xbblockread.cpp b/src/core/xbblockread.cpp
new file mode 100755
index 0000000..09076b1
--- /dev/null
+++ b/src/core/xbblockread.cpp
@@ -0,0 +1,271 @@
+/* xbblockread.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022,2023 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
+
+This module handles block read methods. Block reading is used for performance improvement
+during sequential access processing.
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_BLOCKREAD_SUPPORT
+
+namespace xb{
+
+/************************************************************************/
+xbBlockRead::xbBlockRead( xbDbf * d ) {
+ pBlock = NULL;
+ ulBlkSize = 0;
+ ulFirstBlkRec = 0;
+ ulRecCnt = 0;
+ ulMaxRecs = 0;
+ bEof = xbFalse;
+ this->dbf = d;
+ tFmTime = 0;
+}
+/************************************************************************/
+xbBlockRead::~xbBlockRead(){
+ if( pBlock ){
+ free( pBlock );
+ pBlock = NULL;
+ }
+}
+
+/************************************************************************/
+//! @brief Dump read block internals to stdout.
+/*!
+ Dump the current read block internals to stdout.
+*/
+
+
+#ifdef XB_DEBUG_SUPPORT
+void xbBlockRead::DumpReadBlockInternals(){
+ std::cout << "------- DumpBlockInternals ---------" << std::endl;
+ std::cout << "Dflt Blk Size = [" << dbf->GetXbasePtr()->GetDefaultBlockReadSize()
+ << "]" << std::endl;
+ std::cout << "Dbf Record Count = [" << dbf->GetRecordCount() << "]" << std::endl;
+ std::cout << "Dbf Record Len = [" << dbf->GetRecordLen() << "]" << std::endl;
+ std::cout << "ulBlkSize = [" << ulBlkSize << "]" << std::endl;
+ std::cout << "ulMaxRecs = [" << ulMaxRecs << "]" << std::endl;
+ std::cout << "ulFirstBlkRec = [" << ulFirstBlkRec << "]" << std::endl;
+ std::cout << "ulRecCnt = [" << ulRecCnt << "]" << std::endl;
+ std::cout << "bEof = [" << bEof << "]" << std::endl;
+}
+#endif // XB_DEBUG_SUPPORT
+/************************************************************************/
+//! @brief Get the first record number in the current block.
+/*!
+ Retrieve the first record numer in the current block.<br>
+
+ \returns First record number in the current block.
+*/
+
+xbUInt32 xbBlockRead::GetBlockFirstRecNo() const{
+ return ulFirstBlkRec;
+}
+/************************************************************************/
+//! @brief Get record for specified record number.
+/*!
+ Retrieve a record from read block buffer and copy it into the record buffer.
+ If the current record is not in the current block, the routine calls
+ GetBlockForRecNo to load the currect block from disk.<br><br>
+ For performance reasons, this method assumes a valid record number has been
+ passed.<br><br>
+
+ \param ulRecNo - Record number to retrieve.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbBlockRead::GetRecord( xbUInt32 ulRecNo ){
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ // std::cout << "xbBlockRead::GetRecord( " << ulRecNo << ")\n";
+
+ try{
+ if( !( ulRecNo >= ulFirstBlkRec && ulRecNo < (ulFirstBlkRec + ulRecCnt))){
+ if(( iRc = GetBlockForRecNo( ulRecNo )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+ char *s = pBlock;
+ s += (ulRecNo - ulFirstBlkRec) * dbf->GetRecordLen();
+ char *t = dbf->RecBuf;
+ xbUInt32 ulRecLen = dbf->GetRecordLen();
+ for( xbUInt32 l = 0; l < ulRecLen; l++ ){
+ *t = *s;
+ t++;
+ s++;
+ }
+ dbf->ulCurRec = ulRecNo;
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbBlockRead::GetBlockForRecNo() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/************************************************************************/
+//! @brief Get record for specified record number.
+/*!
+ Retrieve a block containing specified record. This routine calculates the
+ correct block in the DBF file, updates the internal block fields and retrieves
+ the block of records from disk and loads into the block buffer.<br><br>
+
+ \param ulRecNo - Record number to retrieve.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbBlockRead::GetBlockForRecNo( xbUInt32 ulRecNo ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+ xbUInt32 ulDbfRecCnt = dbf->GetRecordCount();
+
+ // calc to determine block number for the requested record, 0 based offset
+ xbUInt32 ulBlockNo = (xbUInt32)(ulRecNo / ulMaxRecs);
+ if( ulRecNo % ulMaxRecs == 0 ) ulBlockNo--;
+
+ // calc the first record
+ ulFirstBlkRec = (ulBlockNo * ulMaxRecs);
+
+ // calc the record count
+ if(( ulFirstBlkRec + ulMaxRecs) > ulDbfRecCnt ){
+ ulRecCnt = ulDbfRecCnt - ulFirstBlkRec;
+ bEof = xbTrue;
+ } else {
+ ulRecCnt = ulMaxRecs;
+ bEof = xbFalse;
+ }
+
+ // position accordingly
+ xbInt64 ulStartPos = dbf->GetHeaderLen() + ((xbInt64) ulFirstBlkRec * dbf->GetRecordLen());
+ if(( dbf->xbFseek( ulStartPos, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ iRc = XB_SEEK_ERROR;
+ throw iRc;
+ }
+
+ if(( dbf->GetFileMtime( tFmTime )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+ // read it
+ if(( dbf->xbFread( (void *) pBlock, ulRecCnt * dbf->GetRecordLen(), 1 )) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+
+ ulFirstBlkRec++; // zero offset in the routine, regular record number from ths point forward
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbBlockRead::GetBlockForRecNo() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+
+/************************************************************************/
+//! @brief Get the current block size.
+/*!
+ Retrieve the current block size.<br><br>
+
+ \returns Current Block Size.
+*/
+
+xbUInt32 xbBlockRead::GetBlockSize() const{
+ return ulBlkSize;
+}
+
+/************************************************************************/
+//! @brief Get the current block record count.
+/*!
+ Retrieve the current number of records loaded in the block.<br><br>
+
+ \returns Current Block Size.
+*/
+
+xbUInt32 xbBlockRead::GetBlockRecCnt() const {
+ return ulRecCnt;
+}
+
+/************************************************************************/
+//! @brief Init the block processing for a iven DBF file.
+/*!
+ Initialize the settings for a given DBF file.<br>
+ This routine may adjust the block size as needed to eliminate unused
+ memory or adjust it bigger if too small.
+
+ \param ulRecNo - ulBlockSize - Block size to allocate. If 0 or missing, it uses default block size of 32K.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbBlockRead::Init(xbUInt32 ulBlockSize ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+
+ // calculate the block size
+ if( ulBlockSize == 0 )
+ ulBlkSize = dbf->GetXbasePtr()->GetDefaultBlockReadSize();
+
+ // if not big enough to handle more than one record, bump it up to something meaningful
+ if( ulBlkSize < (xbUInt32)(dbf->GetRecordLen() * 2 ))
+ ulBlkSize = (xbUInt32) dbf->GetRecordLen() * 10;
+
+ ulMaxRecs = (xbUInt32) ulBlkSize / dbf->GetRecordLen();
+ ulBlkSize = ulMaxRecs * dbf->GetRecordLen();
+
+ // allocate memory for the block
+ if(( pBlock = (char *) calloc( 1, ulBlkSize )) == NULL ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbBlockRead::Init() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/************************************************************************/
+//! @brief Set the block size.
+/*!
+ St block size for this DBF file.<br>.
+
+ \param ulBlkSize - Block Size.
+ \returns XB_NO_ERROR
+*/
+
+xbInt16 xbBlockRead::SetBlockSize( xbUInt32 ulBlkSize ){
+ this->ulBlkSize = ulBlkSize;
+ return XB_NO_ERROR;
+}
+
+/************************************************************************/
+} /* namespace */
+#endif /* XB_BLOCKREAD_SUPPORT */ \ No newline at end of file
diff --git a/src/core/xbdbf.cpp b/src/core/xbdbf.cpp
index 3d13369..4033ef9 100755
--- a/src/core/xbdbf.cpp
+++ b/src/core/xbdbf.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -24,10 +24,16 @@ namespace xb{
\param x Pointer to xbXbase
*/
xbDbf::xbDbf( xbXBase * x ) : xbFile( x ){
- xbase = x;
- SchemaPtr = NULL;
- RecBuf = NULL;
- RecBuf2 = NULL;
+ xbase = x;
+ SchemaPtr = NULL;
+ RecBuf = NULL;
+ RecBuf2 = NULL;
+
+ #ifdef XB_BLOCKREAD_SUPPORT
+ pRb = NULL;
+ bBlockReadEnabled = xbFalse; // batch read switch, if xbTrue, then ON
+ #endif // XB_BLOCKREAD_SUPPORT
+
InitVars();
}
/************************************************************************/
@@ -77,7 +83,7 @@ void xbDbf::InitVars()
#ifdef XB_INF_SUPPORT
llInfData.Clear();
- #endif // XB_INF_SUPPORT
+ #endif // XB_INF_SUPPORT
}
/************************************************************************/
@@ -104,6 +110,16 @@ xbDbf::~xbDbf(){
free( RecBuf2 );
RecBuf2 = NULL;
}
+ if( RecBuf ){
+ free( RecBuf );
+ RecBuf = NULL;
+ }
+
+ #ifdef XB_BLOCKREAD_SUPPORT
+ if( bBlockReadEnabled )
+ DisableBlockReadProcessing();
+ #endif // XB_BLOCKREAD_SUPPORT
+
Close();
}
/************************************************************************/
@@ -1952,6 +1968,18 @@ xbInt16 xbDbf::GetFirstKey(){
}
/************************************************************************/
+//! @brief GetHeaderLen for dbf
+/*!
+
+ Returns the length of the header portion of the dbf file
+ \returns Length of header protion of dbf file
+
+*/
+xbUInt16 xbDbf::GetHeaderLen() const {
+ return uiHeaderLen;
+}
+
+/************************************************************************/
//! @brief GetLastKey for tag.
/*!
@@ -2054,6 +2082,32 @@ xbInt16 xbDbf::Find( xbDouble &dKey ){
#endif // XB_INDEX_SUPPORT
/************************************************************************/
+//! @brief Return true if dbf file empty or positioned to the first record
+/*!
+ \returns Returns true if dbf file is empty or positioned on the first record.
+*/
+xbBool xbDbf::GetBof() {
+/*
+ if( GetRecordCount() == 0 || GetCurRecNo() == 1 )
+ return xbTrue;
+ else
+ */
+ return xbFalse;
+}
+/************************************************************************/
+//! @brief Return true if dbf file empty or positioned to the last record
+/*!
+ \returns Returns true if dbf file is empty or positioned on the last record.
+*/
+xbBool xbDbf::GetEof() {
+ xbUInt32 ulRecCnt = GetRecordCount();
+
+ if( ulRecCnt == 0 || GetCurRecNo() == ulRecCnt )
+ return xbTrue;
+ else
+ return xbFalse;
+}
+/************************************************************************/
//! @brief Return the current record number.
/*!
\returns Returns the current record number.
@@ -2428,15 +2482,23 @@ xbInt16 xbDbf::GetRecord( xbUInt32 ulRecNo ){
iErrorStop = 120;
throw iRc;
}
- }
- }
+ }
+ }
+
+ // std::cout << "xbdbf::GetRecord: " << ulRecNo << " " << ulNoOfRecs << "\n";
if( ulRecNo > ulNoOfRecs || ulRecNo == 0L ){
iErrorStop = 130;
iRc = XB_INVALID_RECORD;
throw iRc;
}
+ #ifdef XB_BLOCKREAD_SUPPORT
+ if( bBlockReadEnabled )
+ return pRb->GetRecord( ulRecNo );
+ #endif // XB_BLOCK_READ_SUPPORT
+
+
if(( xbFseek( (uiHeaderLen+(( (xbInt64) ulRecNo-1L ) * uiRecordLen )), SEEK_SET )) != XB_NO_ERROR ){
iErrorStop = 140;
iRc = XB_SEEK_ERROR;
@@ -2475,9 +2537,6 @@ char * xbDbf::GetRecordBuf( xbInt16 iOpt ) const {
return RecBuf;
}
-
-
-
/************************************************************************/
//! @brief Get the current number of records in the dbf data file.
/*!
@@ -3211,12 +3270,12 @@ xbInt16 xbDbf::Open( const xbString & sTableName, const xbString & sAlias ){
xbLinkListNode<xbString> * llN = llInfData.GetHeadNode();
for( xbUInt32 i = 0; i < llNodeCnt; i++ ){
s2 = llN->GetKey();
- #ifdef XB_NDX_SUPPORT
+ #ifdef XB_NDX_SUPPORT
if(( iRc = OpenIndex( "NDX", s2 )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc ;
}
- #endif // XB_NDX_SUPPORT
+ #endif // XB_NDX_SUPPORT
llN = llN->GetNextNode();
}
}
@@ -3270,7 +3329,6 @@ xbInt16 xbDbf::OpenIndex( const xbString &sIxType, const xbString &sFileName ){
#ifdef XB_MDX_SUPPORT
} else if( sType == "MDX" ){
-
pIx = new xbIxMdx( this );
if(( iRc = pIx->Open( sFileName )) != XB_NO_ERROR ){
iErrorStop = 120;
@@ -4209,4 +4267,72 @@ xbInt16 xbDbf::Zap(){
return iRc;
}
/************************************************************************/
+#ifdef XB_BLOCKREAD_SUPPORT
+// block read processing is designed to provide a way to rapidly retrieve
+// all the records from a .DBF file in sequential order.
+
+// It is not designed for doing any read/write processing or data retrieval based on a tag sort.
+// It is designed for doing a fast sequentil block read out of a table
+
+
+xbInt16 xbDbf::DisableBlockReadProcessing(){
+
+ if( bBlockReadEnabled ){
+ bBlockReadEnabled = xbFalse;
+ delete pRb;
+ pRb = NULL;
+ }
+ return XB_NO_ERROR;
+}
+
+xbBool xbDbf::GetBlockReadStatus() const {
+ return bBlockReadEnabled;
+}
+
+xbInt16 xbDbf::EnableBlockReadProcessing(){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+
+ if( !bBlockReadEnabled ){
+ if( iDbfStatus == XB_UPDATED ){
+ if( GetAutoCommit() == 1 ){
+ if(( iRc = Commit()) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ } else {
+ if(( iRc = Abort()) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ }
+ pRb = new xbBlockRead( this );
+ if( !pRb ){
+ iErrorStop = 120;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+ if(( iRc = pRb->Init()) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+
+ bBlockReadEnabled = xbTrue;
+ }
+
+ } catch( xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbdbf::EnableBlockReadProcessing() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+#endif // XB_BLOCKREAD_SUPPORT
+/************************************************************************/
} /* namespace */ \ No newline at end of file
diff --git a/src/core/xbdbf3.cpp b/src/core/xbdbf3.cpp
index 504542f..d57be3c 100755
--- a/src/core/xbdbf3.cpp
+++ b/src/core/xbdbf3.cpp
@@ -261,7 +261,7 @@ xbInt16 xbDbf3::CreateTable( const xbString & sTableName, const xbString & sAlia
catch( xbInt16 rc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf3::CreateTable() Exception Caught Error Stop = %d rc = %d", iErrorStop, rc );
+ sMsg.Sprintf( "xbdbf3::CreateTable() Exception Caught Error Stop = [%d] rc = [%d]", iErrorStop, rc );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( rc ));
@@ -453,7 +453,7 @@ xbInt16 xbDbf3::Open( const xbString & sTableName, const xbString & sAlias,
catch ( xbInt16 iRc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf3::Open() Exception Caught Error Stop = %d iRc = %d ShareMode = %d OpenMode = %d", iErrorStop, iRc, iShareMode, iOpenMode );
+ sMsg.Sprintf( "xbdbf3::Open() Exception Caught Error Stop = [%d] iRc = [%d] ShareMode = [%d] OpenMode = [%d]", iErrorStop, iRc, iShareMode, iOpenMode );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
xbFclose();
@@ -623,14 +623,14 @@ xbInt16 xbDbf3::Rename( const xbString sNewName ){
xbTblList *tle = xbase->GetTblListEntry( this );
if( tle ){
// std::cout << "setting [" << GetFqFileName().Str() << "][" << sNewNameWoExt.Str() << "]\n";
- tle->psTblName->Set( GetFqFileName().Str());
+ tle->psFqTblName->Set( GetFqFileName().Str());
tle->psTblAlias->Set( sNewNameWoExt.Str());
}
}
catch ( xbInt16 iRc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf3::Rename() Exception Caught Error Stop = %d iRc = %d", iErrorStop, iRc );
+ sMsg.Sprintf( "xbdbf3::Rename() Exception Caught Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
diff --git a/src/core/xbdbf4.cpp b/src/core/xbdbf4.cpp
index 2b49be9..59ba39a 100755
--- a/src/core/xbdbf4.cpp
+++ b/src/core/xbdbf4.cpp
@@ -180,10 +180,10 @@ xbInt16 xbDbf4::CreateTable( const xbString &sTableName, const xbString &sAlias,
ulCurRec = 0L;
uiHeaderLen = 33 + iNoOfFields * 32;
xbDate d;
- cUpdateYY = (char) (d.YearOf() - 1900);
- cUpdateMM = (char) d.MonthOf();
- cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
-
+ cUpdateYY = (char) (d.YearOf() - 1900);
+ cUpdateMM = (char) d.MonthOf();
+ cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
+ cIndexFlag = 0;
// Default language driver to 0x1b
cLangDriver = 0x1b;
@@ -264,7 +264,7 @@ xbInt16 xbDbf4::CreateTable( const xbString &sTableName, const xbString &sAlias,
catch( xbInt16 rc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf4::CreateTable() Exception Caught Error Stop = %d rc = %d", iErrorStop, rc );
+ sMsg.Sprintf( "xbdbf4::CreateTable() Exception Caught Error Stop = [%d] rc = [%d]", iErrorStop, rc );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( rc ));
@@ -452,6 +452,9 @@ xbInt16 xbDbf4::Open( const xbString & sTableName, const xbString & sAlias,
#endif
#ifdef XB_MDX_SUPPORT
+
+// printf( "cIndexFlag [%x]\n", cIndexFlag );
+
if( cIndexFlag ){
// create the file name
xbString sIxFileName = GetFqFileName();
@@ -471,7 +474,7 @@ xbInt16 xbDbf4::Open( const xbString & sTableName, const xbString & sAlias,
catch ( xbInt16 iRc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf4::Open() Exception Caught Error Stop = %d iRc = %d ShareMode = %d OpenMode = %d", iErrorStop, iRc, iShareMode, iOpenMode );
+ sMsg.Sprintf( "xbdbf4::Open() Exception Caught Error Stop = [%d] iRc = [%d] ShareMode = [%d] OpenMode = [%d]", iErrorStop, iRc, iShareMode, iOpenMode );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
xbFclose();
@@ -726,7 +729,7 @@ xbInt16 xbDbf4::Rename( const xbString sNewName ){
// rename the table in the table list
xbTblList *tle = xbase->GetTblListEntry( this );
if( tle ){
- tle->psTblName->Set( GetFqFileName().Str());
+ tle->psFqTblName->Set( GetFqFileName().Str());
tle->psTblAlias->Set( sNewNameWoExt.Str());
}
@@ -735,7 +738,7 @@ xbInt16 xbDbf4::Rename( const xbString sNewName ){
catch ( xbInt16 iRc )
{
xbString sMsg;
- sMsg.Sprintf( "xbdbf4::Rename() Exception Caught Error Stop = %d iRc = %d", iErrorStop, iRc );
+ sMsg.Sprintf( "xbdbf4::Rename() Exception Caught Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
diff --git a/src/core/xbexp.cpp b/src/core/xbexp.cpp
index 23bc7c6..deea53d 100755
--- a/src/core/xbexp.cpp
+++ b/src/core/xbexp.cpp
@@ -669,10 +669,22 @@ xbInt16 xbExp::GetTokenDatabaseField( xbExpToken &t ){
}
// look for ->
- // remove the field name from before the ->
+ // remove the table name from before the ->
if( strncmp( s, "->", 2 ) == 0 ){
ulTokenLen2+=2;
s+=2;
+
+/*
+ if( strncmp( s, "->", 2 ) == 0 || strncmp( s, ".", 1 ) == 0){
+ if( *s == '.' ){
+ ulTokenLen2+=1;
+ s+=1;
+ } else {
+ ulTokenLen2+=2;
+ s+=2;
+ }
+*/
+
// go past white space
while( *s && !IsTokenSeparator( *s ) && IsWhiteSpace( *s )) {
ulTokenLen2++;
@@ -1489,6 +1501,7 @@ xbInt16 xbExp::ParseExpressionField( xbExpToken &t, xbExpNode *n ){
try{
xbUInt32 lPos;
+
if(( lPos = t.sToken.Pos( "->" )) > 0 ){
// table name is part of the token
xbString sTableName = t.sToken;
@@ -1496,6 +1509,22 @@ xbInt16 xbExp::ParseExpressionField( xbExpToken &t, xbExpNode *n ){
sFieldName = t.sToken;
sFieldName.Mid( lPos + 2, t.sToken.Len() - lPos - 1 );
pDbf = (xbDbf *) xbase->GetDbfPtr( sTableName );
+
+
+/*
+ // updated 1/2/23 to support either table.field or table->field
+ if((( lPos = t.sToken.Pos( "->" )) > 0) || (( lPos = t.sToken.Pos( "." )) > 0) ){
+ // table name is part of the token
+ xbString sTableName = t.sToken;
+ sTableName.Left( lPos-1 );
+ sFieldName = t.sToken;
+ if( t.sToken[lPos] == '.' )
+ sFieldName.Mid( lPos + 1, t.sToken.Len() - lPos );
+ else // ->
+ sFieldName.Mid( lPos + 2, t.sToken.Len() - lPos - 1 );
+ pDbf = (xbDbf *) xbase->GetDbfPtr( sTableName );
+*/
+
} else {
// table name is not part of the token
pDbf = dbf;
diff --git a/src/core/xbfile.cpp b/src/core/xbfile.cpp
index 937c16f..3b798a2 100755
--- a/src/core/xbfile.cpp
+++ b/src/core/xbfile.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -49,6 +49,119 @@ xbFile::~xbFile(){
}
/************************************************************************/
+//! @brief Create Home Folders.
+/*!
+ Create xbase64 log and data folders in the home directory for current usre.
+
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+xbInt16 xbFile::SetHomeFolders(){
+
+ xbInt16 iErrorStop = 0;
+ xbInt16 iRc = XB_NO_ERROR;
+ xbString sHomeDir;
+ char cPathSeperator;
+ xbString sDflt;
+
+ try{
+
+ GetHomeDir( sHomeDir );
+ //std::cout << "CreateHomeFolders() home dir = [" << sHomeDir.Str() << "]\n";
+
+ if( FileExists( sHomeDir ) == xbFalse ){
+ iErrorStop = 100;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+
+ #ifdef WIN32
+ cPathSeperator = '\\';
+ #else
+ cPathSeperator = '/';
+ #endif
+ sDflt.Sprintf( ".%c", cPathSeperator );
+ // set the default folders just in case later steps fail
+ xbase->SetDataDirectory( sDflt );
+ #ifdef XB_LOGGING_SUPPORT
+ xbase->SetLogDirectory( sDflt );
+ #endif
+
+ if( sHomeDir[sHomeDir.Len()] != cPathSeperator )
+ sHomeDir += cPathSeperator;
+
+ xbString sWork( sHomeDir );
+ sWork += "xbase64";
+
+ if( FileExists( sWork ) == xbFalse ){
+ #ifdef WIN32
+ if( CreateDirectory( sWork.Str(), NULL ) == 0 ){
+ iErrorStop = 130;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #else
+ // 0777 mode is correct, the mode will be modified by the user's umask
+ if( mkdir( sWork.Str(), 0777 ) == -1 ){
+ iErrorStop = 140;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #endif
+ }
+
+ #ifdef XB_LOGGING_SUPPORT
+ sWork.Sprintf( "%sxbase64%clogs", sHomeDir.Str(), cPathSeperator );
+ // std::cout << "logdir = " << sWork.Str() << "\n";
+
+ if( FileExists( sWork ) == xbFalse ){
+ #ifdef WIN32
+ if( CreateDirectory( sWork.Str(), NULL ) == 0 ){
+ iErrorStop = 110;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #else
+ if( mkdir( sWork.Str(), 0777 ) == -1 ){
+ iErrorStop = 120;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #endif
+ }
+ xbase->SetLogDirectory( sWork );
+ #endif // XB_LOGGING_SUPPORT
+
+ sWork.Sprintf( "%sxbase64%cdata", sHomeDir.Str(), cPathSeperator );
+ // std::cout << "datadir = " << sWork.Str() << "\n";
+ if( FileExists( sWork ) == xbFalse ){
+ #ifdef WIN32
+ if( CreateDirectory( sWork.Str(), NULL ) == 0 ){
+ iErrorStop = 130;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #else
+ if( mkdir( sWork.Str(), 0777 ) == -1 ){
+ iErrorStop = 140;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #endif
+ }
+ xbase->SetDataDirectory( sWork );
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbFile::CreateHomeFolders() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/************************************************************************/
//! @brief Create a unique file name.
/*!
Given a directory and file extension as inputs, create a unique file name.
@@ -1445,7 +1558,7 @@ xbInt16 xbFile::xbFputs( const xbString & s ){
/*!
\param p Pointer to data to write
\param size size of write
- \param nmemb Number of times to write it
+ \param nmemb Number of times to read it
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
@@ -1899,69 +2012,39 @@ void xbFile::SetLockRetryCount( xbInt16 iLockRetries ) {
}
#endif
+
+
/***********************************************************************/
#ifdef XB_DEBUG_SUPPORT
-//! @brief Debugging routine - dump a block to the log file.
+//! @brief Debugging routine - dump mem to the log file.
/*!
- This routine dumps a block to a file in the log file. This is
+ This routine dumps data from meemory to the log file. This is
primarily used for debugging and analysis purposes.
- \param ulBlockNo Block number to write
+ \param p Pointer to data to write
\param lBlxkSize Size of block
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
-xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
+xbInt16 xbFile::DumpMemToDisk( char *p, size_t lSize ){
xbInt16 iRc = 0;
xbInt16 iErrorStop = 0;
-
- xbUInt32 ulStartBlock;
- xbUInt32 ulEndBlock;
-
- char *p = 0x00;
-
xbString sDir;
xbString sFn;
- char *buf = NULL;
- FILE *fpd = NULL;
- try{
- iErrorStop = 100;
- if( ulBlockNo == 0 ){
- ulStartBlock = 0;
- xbUInt64 ullFileSizeulBlockNo;
- if(( iRc = GetFileSize( ullFileSizeulBlockNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- ulEndBlock = (xbUInt32) (ullFileSizeulBlockNo / lBlkSize);
- } else {
- ulStartBlock = ulBlockNo;
- ulEndBlock = ulBlockNo;
- }
-
- if(( buf = (char *) malloc( lBlkSize )) == NULL ){
- iErrorStop = 120;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- sDir = GetDefaultLogDirectory();
- char cLastChar = sDir[sDir.Len()];
+ FILE *fpd = NULL;
- for( xbUInt32 l = ulStartBlock; l < ulEndBlock; l++ ){
+ try{
- if(( iRc = ReadBlock( l, lBlkSize, buf )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
+ sDir = GetLogDirectory();
+ char cLastChar = sDir[sDir.Len()];
// build logfile name
if( cLastChar != '/' && cLastChar != '\\' )
- sFn.Sprintf( "%s/Blockdump.B%ld", sDir.Str(), l);
+ sFn.Sprintf( "%s/MemDump.txt", sDir.Str());
else
- sFn.Sprintf( "%sBlockDump.%ld", sDir.Str(), l);
+ sFn.Sprintf( "%sMemDump.txt", sDir.Str());
// open the dump file for append
#ifdef HAVE__FSOPEN_F
@@ -1969,17 +2052,17 @@ xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
#else
if(( fpd = fopen( sFn.Str(), "w+b")) == NULL ){
#endif
- iErrorStop = 140;
+ iErrorStop = 100;
iRc = XB_OPEN_ERROR;
throw iRc;
}
+ int i;
// dump the block to the file
- p = buf;
- for( size_t l = 0; l < lBlkSize; l++ ){
- //if( fputc( *p, fpd ) != *p ){
- if( fputc( *p, fpd ) == EOF ){
- iErrorStop = 150;
+ for( size_t l = 0; l < lSize; l++ ){
+ i = *p;
+ if( fputc( i, fpd ) == EOF ){
+ iErrorStop = 110;
iRc = XB_WRITE_ERROR;
throw iRc;
}
@@ -1988,6 +2071,103 @@ xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
// close the dump file
fclose( fpd );
}
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbFile::DumpBlockToDisk() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ if( fpd )
+ fclose( fpd );
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+//! @brief Debugging routine - dump a block to the log file.
+/*!
+ This routine dumps a block to the log file. This is
+ primarily used for debugging and analysis purposes.
+
+ \param ulBlockNo Block number to write
+ \param lBlxkSize Size of block
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ xbUInt32 ulStartBlock;
+ xbUInt32 ulEndBlock;
+
+ char *p = 0x00;
+
+ xbString sDir;
+ xbString sFn;
+ char *buf = NULL;
+ FILE *fpd = NULL;
+ try{
+
+ if( ulBlockNo == 0 ){
+ ulStartBlock = 0;
+ xbUInt64 ullFileSizeulBlockNo;
+ if(( iRc = GetFileSize( ullFileSizeulBlockNo )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ ulEndBlock = (xbUInt32) (ullFileSizeulBlockNo / lBlkSize);
+ } else {
+ ulStartBlock = ulBlockNo;
+ ulEndBlock = ulBlockNo;
+ }
+
+ if(( buf = (char *) malloc( lBlkSize )) == NULL ){
+ iErrorStop = 110;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+
+ sDir = GetLogDirectory();
+ char cLastChar = sDir[sDir.Len()];
+
+ for( xbUInt32 l = ulStartBlock; l < ulEndBlock; l++ ){
+
+ if(( iRc = ReadBlock( l, lBlkSize, buf )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+
+ // build logfile name
+ if( cLastChar != '/' && cLastChar != '\\' )
+ sFn.Sprintf( "%s/BlockDump.B%ld", sDir.Str(), l);
+ else
+ sFn.Sprintf( "%sBlockDump.%ld", sDir.Str(), l);
+
+ // open the dump file for append
+ #ifdef HAVE__FSOPEN_F
+ if(( fpd = _fsopen( sFn.Str(), "w+b", 0x40 )) == NULL ){
+ #else
+ if(( fpd = fopen( sFn.Str(), "w+b")) == NULL ){
+ #endif
+ iErrorStop = 130;
+ iRc = XB_OPEN_ERROR;
+ throw iRc;
+ }
+
+ // dump the block to the file
+ p = buf;
+ for( size_t l = 0; l < lBlkSize; l++ ){
+ //if( fputc( *p, fpd ) != *p ){
+ if( fputc( *p, fpd ) == EOF ){
+ iErrorStop = 140;
+ iRc = XB_WRITE_ERROR;
+ throw iRc;
+ }
+ p++;
+ }
+ // close the dump file
+ fclose( fpd );
+ }
// free the buffer
if( buf )
@@ -1995,10 +2175,7 @@ xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
}
catch (xbInt16 iRc ){
xbString sMsg;
- if( iErrorStop == 160 )
- sMsg.Sprintf( "xbFile::DumpBlockToDisk() Exception Caught. Error Stop = [%d] iRc = [%d] c=[%c][%x]", iErrorStop, iRc, *p, *p );
- else
- sMsg.Sprintf( "xbFile::DumpBlockToDisk() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ sMsg.Sprintf( "xbFile::DumpBlockToDisk() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
if( buf )
@@ -2007,7 +2184,6 @@ xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
fclose( fpd );
}
return iRc;
-
}
#endif
/***********************************************************************/
diff --git a/src/core/xbfilter.cpp b/src/core/xbfilter.cpp
index 507a9e7..0fb643d 100755
--- a/src/core/xbfilter.cpp
+++ b/src/core/xbfilter.cpp
@@ -26,8 +26,7 @@ This module handles uda (user data area) methods
namespace xb{
/************************************************************************/
-xbFilter::xbFilter( xbXBase *xbase, xbDbf *dbf ) {
- this->xbase = xbase;
+xbFilter::xbFilter( xbDbf *dbf ) {
this->dbf = dbf;
this->exp = NULL;
lLimit = 0; // max number of responses
@@ -63,6 +62,12 @@ void xbFilter::ResetQryCnt(){
}
/************************************************************************/
+xbInt16 xbFilter::Set( const char *sFilter ) {
+ xbString sFilt( sFilter );
+ return Set( sFilt );
+}
+
+/************************************************************************/
xbInt16 xbFilter::Set( xbString &sFilter ) {
xbInt16 iRc = XB_NO_ERROR;
@@ -72,7 +77,7 @@ xbInt16 xbFilter::Set( xbString &sFilter ) {
if( exp )
delete exp;
- exp = new xbExp( xbase, dbf );
+ exp = new xbExp( dbf->GetXbasePtr(), dbf );
if(( iRc = exp->ParseExpression( sFilter.Str() )) != XB_NO_ERROR ){
iErrorStop = 100;
throw iRc;
@@ -88,8 +93,8 @@ xbInt16 xbFilter::Set( xbString &sFilter ) {
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::SetExpression() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -141,8 +146,8 @@ xbInt16 xbFilter::GetFirstRecord( xbInt16 iOption ) {
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetFirstRecord() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -196,8 +201,8 @@ xbInt16 xbFilter::GetNextRecord( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetNextRecord() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -251,8 +256,8 @@ xbInt16 xbFilter::GetPrevRecord( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetPrevRecord() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -304,8 +309,8 @@ xbInt16 xbFilter::GetLastRecord( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetLastRecord() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -363,8 +368,8 @@ xbInt16 xbFilter::GetFirstRecordIx( xbInt16 iOption ) {
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetFirstRecordIx() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -419,8 +424,8 @@ xbInt16 xbFilter::GetNextRecordIx( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetNextRecordIx() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -475,8 +480,8 @@ xbInt16 xbFilter::GetPrevRecordIx( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetPrevRecordIx() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
@@ -491,7 +496,6 @@ xbInt16 xbFilter::GetLastRecordIx( xbInt16 iOption ){
iErrorStop = 100;
throw iRc;
}
-
lCurQryCnt = 0;
if(( iRc = dbf->GetCurIx()->GetLastKey( dbf->GetCurTag(), iOption )) != XB_NO_ERROR ){
if( iRc == XB_EOF )
@@ -501,7 +505,6 @@ xbInt16 xbFilter::GetLastRecordIx( xbInt16 iOption ){
throw iRc;
}
}
-
xbBool bFound = xbFalse;
while( !bFound && iRc == XB_NO_ERROR ){
if(( iRc = exp->ProcessExpression()) != XB_NO_ERROR ){
@@ -528,12 +531,11 @@ xbInt16 xbFilter::GetLastRecordIx( xbInt16 iOption ){
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbFilter::GetLastRecordIx() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( xbase->GetErrorMessage( iRc ));
+ dbf->GetXbasePtr()->WriteLogMessage( sMsg.Str() );
+ dbf->GetXbasePtr()->WriteLogMessage( dbf->GetXbasePtr()->GetErrorMessage( iRc ));
}
return iRc;
}
-
#endif // XB_INDEX_SUPPORT
diff --git a/src/core/xbixmdx.cpp b/src/core/xbixmdx.cpp
index 95f342c..135cde8 100755
--- a/src/core/xbixmdx.cpp
+++ b/src/core/xbixmdx.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -108,7 +108,7 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
} else {
// land here with a full leaf node
- //std::cout << "Section B begin split leaf node\n";
+ // std::cout << "Section B begin split leaf node\n";
iHeadNodeUpdateOpt = 1;
npRightNode = AllocateIxNode( npTag, GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor );
@@ -122,7 +122,7 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
ulNewRightChild = npRightNode->ulBlockNo * (xbUInt32) iBlockFactor;
}
- //std::cout << "ulNewRightChild = " << ulNewRightChild << "\n";
+ // std::cout << "ulNewRightChild = " << ulNewRightChild << "\n";
if(( iRc = xbIxMdx::SplitNodeL( npTag, npTag->npCurNode, npRightNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
iErrorStop = 130;
@@ -169,7 +169,8 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
// section D - if cur node is split root, create new root
if(( npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor ) == npTag->ulRootPage ){
- // std::cout << "Section D begin\n";
+
+ // std::cout << "Section D begin right node = " << npRightNode << "\n";
if(( iRc = AddKeyNewRoot( npTag, npTag->npCurNode, npRightNode )) != XB_NO_ERROR ){
iErrorStop = 160;
@@ -179,9 +180,10 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
if( npRightNode )
npRightNode = FreeNodeChain( npRightNode );
- //std::cout << "Section D end\n";
+ // std::cout << "Section D end\n";
} else {
+
// std::cout << "Section E, put key in parent\n";
if(( iRc = InsertNodeI( (void *) vpTag, (xbIxNode *) npParent, (xbInt16) npParent->iCurKeyNo, BlockToPage( npRightNode->ulBlockNo ))) != XB_NO_ERROR ){
iErrorStop = 170;
@@ -284,8 +286,8 @@ xbInt16 xbIxMdx::AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *np
// std::cout << "AddKeyNewRoot - LeftBlock = " << npLeft->ulBlockNo << "\n";
// std::cout << "AddKeyNewRoot - RightBlock = " << npRight->ulBlockNo << "\n";
- pLastKey = (char *) malloc( (size_t) npTag->iKeyLen );
+ pLastKey = (char *) malloc( (size_t) npTag->iKeyLen );
if(( iRc = GetLastKeyForBlockNo( npTag, npLeft->ulBlockNo, pLastKey )) != XB_NO_ERROR ){
iErrorStop = 110;
throw iRc;
@@ -301,10 +303,17 @@ xbInt16 xbIxMdx::AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *np
// set the key
pTrg+= 4;
+ // std::cout << "AddKeyNewRoot - key [" << pLastKey << "] len = [" << strlen( pLastKey) << "]\n";
memcpy( pTrg, pLastKey, (size_t) npTag->iKeyLen );
// set the right node number
- pTrg+= (npTag->iKeyLen);
+ //pTrg+= (npTag->iKeyLen);
+ // pTrg+= (npTag->iKeyItemLen)-4;
+
+ pTrg+= npTag->iKeyItemLen - 4;
+
+ //pTrg-=4;
+
ePutUInt32( pTrg, npRight->ulBlockNo * (xbUInt32) iBlockFactor );
// write out the new block
@@ -598,15 +607,17 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
iErrorStop = 100;
throw iRc;
}
- bLocked = xbTrue;
+ bLocked = xbTrue;
}
#endif
memset( npTag->cpKeyBuf2, 0x00, (size_t) npTag->iKeyLen );
+ // memset( npTag->cpKeyBuf2, 0x00, (size_t) npTag->iKeyItemLen );
cKeyType = GetKeyType( vpTag );
pPrevKeyBuf = (char *) calloc( 1, (size_t) npTag->iKeyLen );
iRc = GetFirstKey( vpTag, 0 );
+
memcpy( pPrevKeyBuf, GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
// for each key in the index, make sure it is trending in the right direction
@@ -719,7 +730,7 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
free( pPrevKeyBuf );
if( iErrorStop == 160 ){
- sMsg.Sprintf( "xbIxNdx::CheckTagIntegrity() Missing index entry for record [%d]", ulThisRecNo );
+ sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Missing index entry for record [%d]", ulThisRecNo );
xbase->WriteLogMessage( sMsg, iOpt );
}
}
@@ -1171,8 +1182,13 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
tte->cKeyType2 = tte->cKeyType;
tte->iKeyItemLen = tte->iKeyLen + 4;
+ while(( tte->iKeyItemLen % 4 ) != 0 ) tte->iKeyItemLen++;
tte->iKeysPerBlock = (xbInt16) (GetBlockSize() - 12) / tte->iKeyItemLen;
+
+ //std::cout << "-------------- create tag info\n";
+ //std::cout << "keylen=" << tte->iKeyLen << " iKeyItemLen = " << tte->iKeyItemLen << " keys per block calc = " << tte->iKeysPerBlock << "\n";
+
tte->cKeyFmt3 = CalcTagKeyFmt( *tte->exp );
// printf( "ulRootPage=[%d] cKeyFmt2=[%d] cKeyType2=[%d] iKeyLen=[%d]iKeysPerBlock=[%d]\n", tte->ulRootPage, tte->cKeyFmt2, tte->cKeyType2, tte->iKeyLen, tte->iKeysPerBlock );
@@ -2657,6 +2673,7 @@ xbInt16 xbIxMdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw = 0 ){
// convert the tag pointer to mdx tag pointer
xbMdxTag * mpTag = (xbMdxTag *) vpTag;
+
try{
// clear out any history
if( mpTag->npNodeChain ){
@@ -2668,6 +2685,7 @@ xbInt16 xbIxMdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw = 0 ){
iErrorStop = 100;
throw iRc;
}
+
// lRootPage is available
if(( iRc = GetBlock( vpTag, (mpTag->ulRootPage / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
iErrorStop = 110;
@@ -2683,8 +2701,7 @@ xbInt16 xbIxMdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw = 0 ){
return iRc;
}
- while( !IsLeaf( vpTag, mpTag->npCurNode )) // go down the chain looking for a leaf node
- {
+ while( !IsLeaf( vpTag, mpTag->npCurNode )){ // go down the chain looking for a leaf node
if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
@@ -2878,7 +2895,7 @@ xbInt16 xbIxMdx::GetLastKey( xbUInt32 ulBlockNo, void *vpTag, xbInt16 iRetrieveS
}
mpTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
+ ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
xbUInt32 ulKeyPtr = 0;
while( !IsLeaf( vpTag, mpTag->npCurNode )){ // go down the chain looking for a leaf node
@@ -3559,6 +3576,11 @@ xbInt16 xbIxMdx::InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xb
pSrc = pLastKey;
for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
*pTrg++ = *pSrc++;
+
+ pTrg = pNewKeyPos;
+ //pTrg+= npTag->iKeyItemLen - 4;
+ pTrg+= npTag->iKeyItemLen;
+
ePutUInt32( pTrg, ulPtr);
ePutInt32( npNode->cpBlockData, ++lKeyCnt );
@@ -4683,7 +4705,7 @@ xbInt16 xbIxMdx::SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
}
catch (xbInt16 iRc ){
xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::SplitNodeI() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ sMsg.Sprintf( "xbIxMdx::SplitNodeI() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
}
@@ -4712,7 +4734,7 @@ xbInt16 xbIxMdx::SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
-xbInt16 xbIxMdx::SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
+xbInt16 xbIxMdx::SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 ulPtr ){
xbInt16 iRc = XB_NO_ERROR;
diff --git a/src/core/xbixndx.cpp b/src/core/xbixndx.cpp
index dcec5f9..9d946dd 100755
--- a/src/core/xbixndx.cpp
+++ b/src/core/xbixndx.cpp
@@ -342,7 +342,7 @@ xbInt16 xbIxNdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
iErrorStop = 100;
throw iRc;
}
- bLocked = xbTrue;
+ bLocked = xbTrue;
}
#endif
@@ -425,7 +425,6 @@ xbInt16 xbIxNdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
sMsg.Sprintf( "CheckTagIntegrity() Index entry count [%ld] matches dbf record count [%ld]", ulIxCnt, ulDbfCnt );
xbase->WriteLogMessage( sMsg, iOpt );
}
-
if( pPrevKeyBuf )
free( pPrevKeyBuf );
diff --git a/src/core/xblog.cpp b/src/core/xblog.cpp
index ea7c9d6..6031c9e 100755
--- a/src/core/xblog.cpp
+++ b/src/core/xblog.cpp
@@ -25,8 +25,8 @@ namespace xb{
//! @brief Constructor.
xbLog::xbLog() : xbFile( NULL ){
- SetDirectory( GetDefaultLogDirectory());
- SetFileName ( GetDefaultLogFileName());
+ SetDirectory( GetLogDirectory());
+ SetFileName ( GetLogFileName());
bLoggingStatus = xbFalse;
lLogSize = 50000;
diff --git a/src/core/xbssv.cpp b/src/core/xbssv.cpp
index 252daab..d3e1070 100755
--- a/src/core/xbssv.cpp
+++ b/src/core/xbssv.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -15,8 +15,6 @@ Email Contact:
#include "xbase.h"
-
-
namespace xb{
const xbErrorMessage xbErrorMessages[] = {
@@ -26,6 +24,7 @@ const xbErrorMessage xbErrorMessages[] = {
{ XB_DUP_TABLE_OR_ALIAS, "Duplicate Alias/Table Name" },
{ XB_INVALID_NODELINK, "Invalid Node Link" },
{ XB_KEY_NOT_UNIQUE, "Key Not Unique" },
+ { XB_MEMCPY_ERROR, "Memory copy failure" },
{ XB_FILE_EXISTS, "File Already Exists" },
{ XB_ALREADY_OPEN, "Database already open" },
{ XB_DBF_FILE_NOT_OPEN, "DBF File Not Open" },
@@ -49,6 +48,8 @@ const xbErrorMessage xbErrorMessages[] = {
{ XB_INVALID_TABLE_NAME, "Invalid Table Name" },
{ XB_EMPTY, "Empty Table or Index" },
{ XB_LIMIT_REACHED, "Limit Reached" },
+ { XB_BLOCKREAD_NOT_ENABLED, "Block Read Mode is not enabled" },
+ { XB_DIRECTORY_ERROR, "Directory Read/Write error" },
{ XB_INVALID_FIELD_TYPE, "Unknown Field Type" },
{ XB_INVALID_FIELD_NO, "Invalid Field Number" },
{ XB_INVALID_DATA, "Invalid Data" },
@@ -89,12 +90,13 @@ xbBool xbSsv::bDefaultAutoCommit = xbTrue;
xbString xbSsv::sDataDirectory = PROJECT_DATA_DIR;
#else
xbString xbSsv::sDataDirectory = PROJECT_DATA_DIR;
-#endif
+#endif //
#ifdef XB_LOGGING_SUPPORT
-xbString xbSsv::sDefaultLogDirectory = PROJECT_LOG_DIR;
-xbString xbSsv::sDefaultLogFileName = PROJECT_DFLT_LOGFILE;
-#endif
+xbString xbSsv::sLogDirectory = PROJECT_LOG_DIR;
+//xbString xbSsv::sLogDirectory = "";
+xbString xbSsv::sLogFileName = PROJECT_DFLT_LOGFILE;
+#endif // XB_LOGGING_SUPPORT
#ifdef XB_LOCKING_SUPPORT
xbInt32 xbSsv::lDefaultLockWait = 100;
@@ -104,18 +106,21 @@ xbInt16 xbSsv::iDefaultLockFlavor = 1;
xbBool xbSsv::bMultiUser = xbTrue;
#else
xbBool xbSsv::bMultiUser = xbFalse;
-#endif
+#endif // XB_LOCKING_SUPPORT
#if defined (XB_NDX_SUPPORT) || defined (XB_MDX_SUPPORT)
xbInt16 xbSsv::iUniqueKeyOpt = XB_HALT_ON_DUPKEY;
// is one of XB_HALT_ON_DUPKEY || XB_EMULATE_DBASE
-#endif
+#endif // defined (XB_NDX_SUPPORT) || defined (XB_MDX_SUPPORT)
#ifdef XB_MDX_SUPPORT
xbInt16 xbSsv::iCreateMdxBlockSize = 1024; // 1024 is DBase 7 default size for MDX index blocks
-#endif
+#endif // XB_MDX_SUPPORT
+#ifdef XB_BLOCKREAD_SUPPORT
+xbUInt32 xbSsv::ulDefaultBlockReadSize = 32768; // 32K buffer for block DBF datafile reads
+#endif // XB_BLOCKREAD_SUPPORT
/*************************************************************************/
//! @brief Class Constructor.
@@ -139,7 +144,6 @@ void xbSsv::BitDump( char c ) const {
xbBool xbSsv::BitSet( unsigned char c, xbInt16 iBitNo ) const {
return c & 1 << iBitNo;
}
-
/*************************************************************************/
//! @brief Display error message on console for a given error number.
/*!
@@ -164,7 +168,6 @@ void xbSsv::DisplayError( xbInt16 iErrorCode ) const {
xbBool xbSsv::GetDefaultAutoCommit() const {
return bDefaultAutoCommit;
}
-
/*************************************************************************/
//! @brief Get the current data directory.
/*!
@@ -184,19 +187,6 @@ xbString &xbSsv::GetDataDirectory() const {
xbString & xbSsv::GetDefaultDateFormat() const {
return sDefaultDateFormat;
}
-
-/*************************************************************************/
-// @brief Get the default file format version.
-/*
- \returns 3 - Dbase III file format<br>
- 4 - Dbase IV file format<br>
-*/
-
-/*
-xbInt16 xbSsv::GetDefaultFileVersion() const {
- return iDefaultFileVersion;
-}
-*/
/*************************************************************************/
//! @brief Get the Endian type.
/*!
@@ -206,7 +196,6 @@ xbInt16 xbSsv::GetDefaultFileVersion() const {
xbInt16 xbSsv::GetEndianType() const {
return iEndianType;
}
-
/*************************************************************************/
//! @brief Get an error message.
/*!
@@ -230,7 +219,25 @@ const char * xbSsv::GetErrorMessage( xbInt16 iErrorCode ) const{
}
return "";
}
+/*************************************************************************/
+//! @brief Get home directory.
+/*!
+ \param sHomeDirOut - Output home directory for current user.
+ \returns void
+*/
+
+void xbSsv::GetHomeDir( xbString &sHomeDirOut ){
+ #ifdef WIN32
+ sHomeDirOut.Sprintf( "%s%s", getenv( "HOMEDRIVE" ), getenv( "HOMEPATH" ));
+ #else
+ sHomeDirOut.Sprintf( "%s", getenv( "HOME" ));
+ sHomeDirOut.Trim();
+ if( sHomeDirOut == "" )
+ sHomeDirOut.Sprintf( "%s", getpwuid( getuid())->pw_dir );
+ #endif
+ sHomeDirOut.Trim();
+}
/*************************************************************************/
//! @brief Set the data directory.
/*!
@@ -240,7 +247,6 @@ const char * xbSsv::GetErrorMessage( xbInt16 iErrorCode ) const{
void xbSsv::SetDataDirectory( const xbString &sDataDirectory ){
this->sDataDirectory = sDataDirectory;
-
#ifdef WIN32
this->sDataDirectory.SwapChars( '/', '\\' );
#else
@@ -302,57 +308,53 @@ void xbSsv::SetEndianType() {
/*!
\returns Returns the log file name.
*/
-xbString & xbSsv::GetDefaultLogFileName() const {
- return sDefaultLogFileName;
+xbString & xbSsv::GetLogFileName() const {
+ return sLogFileName;
}
-
/*************************************************************************/
//! @brief Get the default log directory.
/*!
\returns Returns the log directory.
*/
-xbString & xbSsv::GetDefaultLogDirectory() const {
- return sDefaultLogDirectory;
+xbString & xbSsv::GetLogDirectory() const {
+ return sLogDirectory;
}
/*************************************************************************/
//! @brief Set the default log directory name.
/*!
- \param sDefaultLogDirectory Name of desired log directory.
+ \param sLogDirectory Name of desired log directory.
*/
-void xbSsv::SetDefaultLogDirectory( const xbString &sDefaultLogDirectory ){
-
- this->sDefaultLogDirectory = sDefaultLogDirectory;
+void xbSsv::SetLogDirectory( const xbString &sLogDirectoryIn ){
+ this->sLogDirectory = sLogDirectoryIn;
#ifdef WIN32
- this->sDefaultLogDirectory.SwapChars( '/', '\\' );
+ this->sLogDirectory.SwapChars( '/', '\\' );
#else
- this->sDefaultLogDirectory.SwapChars( '\\', '/' );
+ this->sLogDirectory.SwapChars( '\\', '/' );
#endif
-
}
#else
-xbString & xbSsv::GetDefaultLogFileName() const {
+xbString & xbSsv::GetLogFileName() const {
return sNullString;
}
-xbString & xbSsv::GetDefaultLogDirectory() const {
+xbString & xbSsv::GetLogDirectory() const {
return sNullString;
}
-void xbSsv::SetDefaultLogDirectory( const xbString &sDefaultLogDirectory ){
+void xbSsv::SetLogDirectory( const xbString &sLogDirectory ){
return;
}
#endif
-
/*************************************************************************/
#ifdef XB_LOCKING_SUPPORT
@@ -541,6 +543,29 @@ xbInt16 xbSsv::SetUniqueKeyOpt( xbInt16 iOpt ){
}
#endif
/************************************************************************/
+#ifdef XB_BLOCKREAD_SUPPORT
+
+//! @brief Get Default Read Block Size
+/*!
+ This routine returns the default read block size used when allocating
+ buffer space for block reads of table data. Initial setting is 32768 bytes.
+*/
+xbUInt32 xbSsv::GetDefaultBlockReadSize() const {
+ return ulDefaultBlockReadSize;
+}
+
+
+//! @brief Set Default Read Block Size
+/*!
+ This routine sets the default read block size used when allocating
+ buffer space for block reads of table data. Initial setting is 32768 bytes.
+*/
+void xbSsv::SetDefaultBlockReadSize( xbUInt32 ulDfltBlockReadSize ){
+ ulDefaultBlockReadSize = ulDfltBlockReadSize;
+}
+
+#endif // XB_BLOCKREAD_SUPPORT
+/************************************************************************/
diff --git a/src/core/xbstring.cpp b/src/core/xbstring.cpp
index 81e67b8..701e50e 100755
--- a/src/core/xbstring.cpp
+++ b/src/core/xbstring.cpp
@@ -1267,6 +1267,45 @@ xbString &xbString::PadRight( char c, xbUInt32 ulNewLen ){
//! @brief Determine position of a given character
/*!
\param c Seek character
+ \param ulStartPos starting position for search, first position is 1
+ \returns Position within string. Returns 0 if not found.
+*/
+xbUInt32 xbString::Pos(char c, xbUInt32 ulStartPos ) const {
+
+ if (data == NULL)
+ return 0;
+ char *p = data;
+
+ if( ulStartPos >= size )
+ return 0;
+
+ xbUInt32 iPos = 0;
+ while( (iPos+1) < ulStartPos ){
+ p++;
+ iPos++;
+ }
+ xbBool bFound = 0;
+ while( *p && !bFound && iPos < ( size - 1 )){
+ if( *p == c )
+ bFound = 1;
+ else {
+ iPos++;
+ p++;
+ }
+ }
+
+ if( bFound )
+ return iPos + 1;
+ else
+ return 0;
+}
+
+
+
+/************************************************************************/
+//! @brief Determine position of a given character
+/*!
+ \param c Seek character
\returns Position within string. Returns 0 if not found.
*/
xbUInt32 xbString::Pos(char c) const {
@@ -1375,41 +1414,51 @@ xbString &xbString::Replace( const char *sReplace, const char *sReplaceWith, xbI
xbBool bDone = xbFalse;
xbUInt32 ulPos;
- xbUInt32 ulNewSize;
+ xbUInt32 ulNewLen;
+ xbUInt32 ulReplaceWithLen;
+ xbUInt32 ulRsLen; // size of right side of string after replaced data
xbUInt32 ulSp2;
char *sBuf2;
+ const char *s; // source ptr
+ char *t; // target ptr
+
while( !bDone ){
ulPos = Pos( sReplace );
if( ulPos == 0 ){
bDone = xbTrue;
} else {
- ulNewSize = this->size + sizeof( sReplaceWith ) - sizeof( sReplace );
- sBuf2 = (char *) calloc( 1, ulNewSize );
+ ulReplaceWithLen = (xbUInt32) strlen( sReplaceWith );
+ ulNewLen = this->size + ulReplaceWithLen - (xbUInt32) strlen( sReplace );
+ sBuf2 = (char *) calloc( 1, ulNewLen );
// copy part1
+ t = sBuf2;
+ s = data;
for( xbUInt32 ul = 0; ul < ulPos-1; ul++ )
- sBuf2[ul] = data[ul];
+ *t++ = *s++;
// copy part2
- strcat( sBuf2, sReplaceWith );
+ s = sReplaceWith;
+ for( xbUInt32 ul = 0; ul < ulReplaceWithLen; ul++ )
+ *t++ = *s++;
// copy part3
- ulSp2 = ulPos + strlen( sReplace );
- char *p = data;
- p+= (ulSp2 - 1);
- strcat( sBuf2, p );
+ ulSp2 = ulPos + (xbUInt32) strlen( sReplace );
+ s = data;
+ s+= (ulSp2 - 1);
+ ulRsLen = (xbUInt32) strlen( s );
+ for( xbUInt32 ul = 0; ul < ulRsLen; ul++ )
+ *t++ = *s++;
if( iOption )
bDone = xbTrue;
free(data);
data = sBuf2;
-
}
}
-
return *this;
}
diff --git a/src/core/xbtblmgr.cpp b/src/core/xbtblmgr.cpp
index f154dc6..2fe6a8c 100755
--- a/src/core/xbtblmgr.cpp
+++ b/src/core/xbtblmgr.cpp
@@ -22,20 +22,19 @@ Email Contact:
namespace xb{
/*************************************************************************/
-
xbTblMgr::xbTblMgr(){
TblList = NULL;
iOpenTableCount = 0;
}
/*************************************************************************/
-
xbTblMgr::~xbTblMgr(){
xbTblList *l;
if( TblList ){
while( TblList ){
l = TblList;
TblList = TblList->pNext;
+ delete l->psFqTblName;
delete l->psTblName;
delete l->psTblAlias;
free( l );
@@ -44,47 +43,74 @@ xbTblMgr::~xbTblMgr(){
}
/*************************************************************************/
-
-xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sTblName ){
- return AddTblToTblList( d, sTblName, "" );
+xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sFqTblName ){
+ return AddTblToTblList( d, sFqTblName, "" );
}
/*************************************************************************/
+xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sFqTblName, const xbString & sTblAlias ) {
+
+ // Set the Fq (fully qualified name)
+ // Pull the table name from the FQ name
+ // Set the Alias to the table name if the alias name is not provided
-xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sTblName, const xbString & sTblAlias ) {
xbTblList *i, *s, *t;
xbInt16 iRc = 0;
xbInt16 iErrorStop = 0;
+ xbString sTblName;
xbString sAlias;
+ xbString sTemp;
+ xbString sFqTemp;
+ xbUInt32 iSlashPos;
+
+ // std::cout << "AddTblToTblList fq in = [" << sFqTblName.Str() << "] alias in =[" << sTblAlias.Str() << "]\n";
try{
- if( sTblName.Len() == 0 ){
+ if( sFqTblName.Len() == 0 ){
iErrorStop = 100;
iRc = XB_INVALID_TABLE_NAME;
throw iRc;
}
- if( sTblAlias.Len() == 0 ){
+ sTblName = sFqTblName;
+ sTblName.SwapChars( '\\', '/' );
+ iSlashPos = sTblName.GetLastPos( '/' );
+
+ // std::cout << "slashpos = " << iSlashPos << "\n";
+
+
+ if( iSlashPos > 0 ){
+ sTblName.Ltrunc( iSlashPos ); // remove the directory part from the table name
+ sFqTemp = sFqTblName;
+ } else{
+ sFqTemp.Sprintf( "%s%s", GetDataDirectory().Str(), sFqTblName.Str()); // add the dir part to the FQ name
+ }
+
+ xbUInt32 iDbfPos = sFqTemp.Pos( ".DBF" );
+ if( iDbfPos == 0 )
+ sFqTemp += ".DBF";
+ else
+ sTblName.Resize( sTblName.Len() - 3 );
+
+ if( sTblAlias.Len() == 0 )
sAlias = sTblName;
- sAlias.SwapChars( '\\', '/' );
- xbUInt32 iPos = sAlias.GetLastPos( '/' );
- if( iPos > 0 ) /* get rid of the directory part of the name */
- sAlias.Ltrunc( iPos );
- } else {
+ else
sAlias = sTblAlias;
- }
+
+ //std::cout << "fq=[" << sFqTemp.Str() << "] tblname = [" << sTblName.Str() << "] alias = [" << sAlias.Str() << "]\n";
if((i = (xbTblList *) calloc(1, sizeof(xbTblList))) == NULL){
iErrorStop = 110;
iRc = XB_NO_MEMORY;
throw iRc;
}
- i->psTblName = new xbString( sTblName );
- i->psTblAlias = new xbString( sAlias );
- i->pDbf = d;
- i->pNext = NULL;
+ i->psFqTblName = new xbString( sFqTemp );
+ i->psTblName = new xbString( sTblName );
+ i->psTblAlias = new xbString( sAlias );
+ i->pDbf = d;
+ i->pNext = NULL;
// insert new table into the list of open tables, sorted by table name
s = NULL;
@@ -97,7 +123,7 @@ xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sTblName, const xb
if( t && (strcmp( t->psTblAlias->Str(), sAlias.Str()) == 0 )){
iErrorStop = 120;
- delete i->psTblName;
+ delete i->psFqTblName;
delete i->psTblAlias;
free( i );
iRc = XB_DUP_TABLE_OR_ALIAS;
@@ -131,7 +157,7 @@ xbInt16 xbTblMgr::DisplayTableList() const {
else{
while( l ){
iTblCnt++;
- std::cout << iTblCnt << " Table=[" << l->psTblName->Str() << "] Alias=[" << l->psTblAlias->Str() << "]" << std::endl;
+ std::cout << iTblCnt << " FqFileName=[" << l->psFqTblName->Str() << "] TableName=[" << l->psTblName->Str() << "] Alias=[" << l->psTblAlias->Str() << "]" << std::endl;
l = l->pNext;
}
}
@@ -149,6 +175,7 @@ xbInt16 xbTblMgr::DisplayTableList() const {
xbDbf *xbTblMgr::GetDbfPtr(const xbString& sTblAlias) const {
+
xbTblList *t;
t = TblList;
xbString s;
@@ -159,14 +186,26 @@ xbDbf *xbTblMgr::GetDbfPtr(const xbString& sTblAlias) const {
s.Set( sTblAlias );
while( t ){
- if( s == t->psTblAlias->Str())
+ if( s == t->psTblAlias->Str()){
+ return t->pDbf;
+ }
+ t = t->pNext;
+ }
+
+ t = TblList;
+ while( t ){
+ std::cout << "s = [" << s.Str() << "] tbl name = [" << t->psTblName->Str() << "]\n";
+ if( s == t->psTblName->Str()){
+ std::cout << "found\n";
return t->pDbf;
+ }
t = t->pNext;
}
+
t = TblList;
while( t ){
- if( sTblAlias == t->psTblName->Str())
+ if( sTblAlias == t->psFqTblName->Str())
return t->pDbf;
t = t->pNext;
}
@@ -227,6 +266,7 @@ xbInt16 xbTblMgr::RemoveTblFromTblList( const xbString & sTblAlias ) {
else
TblList = i->pNext;
+ delete i->psFqTblName;
delete i->psTblName;
delete i->psTblAlias;
free( i );
@@ -254,6 +294,7 @@ xbInt16 xbTblMgr::RemoveTblFromTblList( xbDbf *pTbl ) {
else
TblList = i->pNext;
+ delete i->psFqTblName;
delete i->psTblName;
delete i->psTblAlias;
free( i );
diff --git a/src/core/xbxbase.cpp b/src/core/xbxbase.cpp
index 7443b26..20b7fcc 100755
--- a/src/core/xbxbase.cpp
+++ b/src/core/xbxbase.cpp
@@ -24,6 +24,10 @@ xbXBase::xbXBase() {
#ifdef XB_LOGGING_SUPPORT
xLog = new xbLog();
#endif
+
+ xbFile f( this );
+ f.SetHomeFolders();
+
}
/*************************************************************************/
//! @brief Class Deconstructor.
@@ -69,6 +73,53 @@ xbInt16 xbXBase::CloseAllTables(){
}
return iRc;
}
+
+
+
+/*************************************************************************/
+//! @brief Parse commmand line options for a given parm request
+/*!
+ \param lArgc Value passed from main( argc, argv[] )
+ \param sArgv Valued passed from main
+ \param sOptRqst Option to search for in the arguments list
+ \param sParmOut String token immediately to the right of the the option request, if found
+ \returns 0 - paramater request not found<br> 1 - Parameter found
+*/
+
+xbInt16 xbXBase::GetCmdLineOpt( xbInt32 lArgc, char **sArgv, const char *sOptRqst, xbString &sParmOut ){
+ xbString sOpt( sOptRqst );
+ return GetCmdLineOpt( lArgc, sArgv, sOpt, sParmOut );
+}
+
+/*************************************************************************/
+//! @brief Parse commmand line options for a given parm request
+/*!
+ \param lArgc Value passed from main( argc, argv[] )
+ \param sArgv Valued passed from main
+ \param sOptRqst Option to search for in the arguments list
+ \param sParmOut String token immediately to the right of the the option request, if found
+ \returns 0 - paramater request not found<br> 1 - Parameter found
+*/
+
+xbInt16 xbXBase::GetCmdLineOpt( xbInt32 lArgc, char **sArgv, xbString &sOptRqst, xbString &sParmOut ){
+
+ xbInt16 iFound = 0;
+ sParmOut = "";
+ if( lArgc < 2 ) // first string is the program name
+ return iFound;
+
+ xbInt32 i = 1;
+ while( iFound == 0 && i < lArgc ){
+ if( sOptRqst == sArgv[i] ){
+ iFound = 1;
+ if( i < (lArgc-1))
+ sParmOut = sArgv[i+1];
+ }
+ i++;
+ }
+ return iFound;
+}
+
/*************************************************************************/
#ifdef XB_LOGGING_SUPPORT
//! @brief Get fully qualified log file name.
@@ -109,6 +160,7 @@ xbBool xbXBase::GetLogStatus() const {
\return void
*/
void xbXBase::SetLogFileName( const xbString & sLogFileName ){
+
xLog->SetFileName( sLogFileName );
}
@@ -550,7 +602,7 @@ xbDbf* xbXBase::Open( const xbString &sTableName, xbInt16 &iRc ){
\param iOpenMode - XB_READ_WRITE or XB_READ
\param iShareMode - XB_SINGLE_USER or XB_MULTI_USER
\param iRequestVersion 0 - Highest available
- 4 - Version four dbf
+ 4 - Version four dbf
3 - Version three dbf
\param iRc - Return code from open request
\returns param dbf - Output pointer to dbf file opened or null if error