summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rwxr-xr-xsrc/core/xbblockread.cpp14
-rwxr-xr-xsrc/core/xbdate.cpp341
-rwxr-xr-xsrc/core/xbdbf.cpp267
-rwxr-xr-xsrc/core/xbdbf3.cpp3
-rwxr-xr-xsrc/core/xbdbf4.cpp5
-rwxr-xr-xsrc/core/xbexp.cpp102
-rwxr-xr-xsrc/core/xbexpnode.cpp2
-rwxr-xr-xsrc/core/xbfields.cpp77
-rwxr-xr-xsrc/core/xbfile.cpp268
-rwxr-xr-xsrc/core/xbfilter.cpp2
-rwxr-xr-xsrc/core/xbfuncs.cpp7
-rwxr-xr-xsrc/core/xbixbase.cpp2
-rwxr-xr-xsrc/core/xbixmdx.cpp259
-rwxr-xr-xsrc/core/xbixndx.cpp54
-rwxr-xr-xsrc/core/xbixtdx.cpp661
-rwxr-xr-xsrc/core/xblog.cpp25
-rwxr-xr-xsrc/core/xbmemo.cpp2
-rwxr-xr-xsrc/core/xbmemo3.cpp16
-rwxr-xr-xsrc/core/xbmemo4.cpp5
-rwxr-xr-xsrc/core/xbssv.cpp115
-rwxr-xr-xsrc/core/xbstring.cpp163
-rwxr-xr-xsrc/core/xbtag.cpp2
-rwxr-xr-xsrc/core/xbtblmgr.cpp5
-rwxr-xr-xsrc/core/xbuda.cpp2
-rwxr-xr-xsrc/core/xbxbase.cpp78
25 files changed, 1782 insertions, 695 deletions
diff --git a/src/core/xbblockread.cpp b/src/core/xbblockread.cpp
index 09076b1..7e2c5fc 100755
--- a/src/core/xbblockread.cpp
+++ b/src/core/xbblockread.cpp
@@ -50,10 +50,14 @@ xbBlockRead::~xbBlockRead(){
#ifdef XB_DEBUG_SUPPORT
void xbBlockRead::DumpReadBlockInternals(){
+
+ xbUInt32 ulRecCnt;
+ dbf->GetRecordCnt( ulRecCnt );
+
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 Count = [" << ulRecCnt << "]" << std::endl;
std::cout << "Dbf Record Len = [" << dbf->GetRecordLen() << "]" << std::endl;
std::cout << "ulBlkSize = [" << ulBlkSize << "]" << std::endl;
std::cout << "ulMaxRecs = [" << ulMaxRecs << "]" << std::endl;
@@ -136,7 +140,12 @@ xbInt16 xbBlockRead::GetBlockForRecNo( xbUInt32 ulRecNo ){
xbInt16 iErrorStop = 0;
try{
- xbUInt32 ulDbfRecCnt = dbf->GetRecordCount();
+ xbUInt32 ulDbfRecCnt;
+
+ if(( iRc = dbf->GetRecordCnt( ulDbfRecCnt )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
// calc to determine block number for the requested record, 0 based offset
xbUInt32 ulBlockNo = (xbUInt32)(ulRecNo / ulMaxRecs);
@@ -183,7 +192,6 @@ xbInt16 xbBlockRead::GetBlockForRecNo( xbUInt32 ulRecNo ){
return iRc;
}
-
/************************************************************************/
//! @brief Get the current block size.
/*!
diff --git a/src/core/xbdate.cpp b/src/core/xbdate.cpp
index ba0fdf1..54834ac 100755
--- a/src/core/xbdate.cpp
+++ b/src/core/xbdate.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.
@@ -25,22 +25,36 @@ int xbDate::iAggregatedDaysInMonths[2][13];
//! @brief Constructor.
xbDate::xbDate() {
- Sysdate();
+ sDate8.Set( "" );
SetDateTables();
}
/*************************************************************************/
//! @brief Constructor.
/*!
+ \param iInitOpt - Constructor to use to initialize date static variables
+ Called by the main xbXbase::xbXBase constructor
+*/
+
+xbDate::xbDate( xbUInt16 ) {
+
+ SetDateTables();
+ Sysdate();
+}
+/*************************************************************************/
+//! @brief Constructor.
+/*!
\param sDate8In - Input date.
*/
xbDate::xbDate( const xbString & sDate8In ) {
+
if( DateIsValid( sDate8In ))
sDate8.Set( sDate8In );
else
- Sysdate();
- SetDateTables();
+ sDate8.Set( "" );
+
+ // SetDateTables();
}
/*************************************************************************/
@@ -53,8 +67,9 @@ xbDate::xbDate( const char * sDate8In ) {
if( DateIsValid( sDate8In ))
sDate8.Set( sDate8In );
else
- Sysdate();
- SetDateTables();
+ sDate8.Set( "" );
+
+ // SetDateTables();
}
/*************************************************************************/
@@ -63,7 +78,7 @@ xbDate::xbDate( const char * sDate8In ) {
\param lJulDate - Input julian date.
*/
xbDate::xbDate( xbInt32 lJulDate ) {
- SetDateTables();
+ // SetDateTables();
JulToDate8( lJulDate );
}
@@ -81,68 +96,76 @@ void xbDate::operator=( const xbDate & dt ){
/*************************************************************************/
//! @brief operator +=
/*!
- This routine adds lDays to the date
+ This routine adds lDays to the date if the date is not null.
\param lDays - Number of days to add to the date.
*/
void xbDate::operator+=( xbInt32 lDays ){
- JulToDate8( JulianDays() + lDays );
+ if( !IsNull() )
+ JulToDate8( JulianDays() + lDays );
}
/*************************************************************************/
//! @brief operator -=
/*!
- This routine subtracts lDays from the date.
+ This routine subtracts lDays from the date if the date is not null.
\param lDays - Number of days to subtract from the date.
*/
void xbDate::operator-=( xbInt32 lDays ){
- JulToDate8( JulianDays() - lDays );
+ if( !IsNull() )
+ JulToDate8( JulianDays() - lDays );
}
/*************************************************************************/
//! @brief operator ++
/*!
- This routine adds one day to the date field.
+ This routine adds one day to the date field if the date is not null.
*/
void xbDate::operator++(xbInt32){
- *this+=1;
+ if( !IsNull() )
+ *this+=1;
}
/*************************************************************************/
//! @brief operator --
/*!
- This routine subtracts one day from the date field.
+ This routine subtracts one day from the date field if the date is not null.
*/
void xbDate::operator--(xbInt32){
- *this-=1;
- return;
+ if( !IsNull())
+ *this-=1;
}
/*************************************************************************/
//! @brief operator -
/*!
This routine subtracts one date from another date returning the difference.
- \param dt - Date to subtract.
- \returns Number of days
+ \param dt - Date to subtract
+ \returns Number of days difference or zero if one of the dates is null.
*/
xbInt32 xbDate::operator-( const xbDate &dt ) const{
- return JulianDays() - dt.JulianDays();
+ if( !IsNull() && !dt.IsNull() )
+ return JulianDays() - dt.JulianDays();
+ else
+ return 0;
}
/*************************************************************************/
//! @brief operator +
/*!
- This routine adds additional days to a date field.
+ This routine adds additional days to a valid date field.
\param lCount - Number of days to add.
\returns New date in CCYYMMDD format.
*/
const char *xbDate::operator+( xbInt32 lCount ){
- JulToDate8( JulianDays() + lCount );
+ if( !IsNull() )
+ JulToDate8( JulianDays() + lCount );
return sDate8.Str();
}
/*************************************************************************/
//! @brief operator -
/*!
- This routine subtracts days from a date field.
+ This routine subtracts days from a valid date field.
\param lCount - Number of days to subtract.
\returns New date in CCYYMMDD format.
*/
const char *xbDate::operator-( xbInt32 lCount ){
- JulToDate8( JulianDays() - lCount );
+ if( !IsNull() )
+ JulToDate8( JulianDays() - lCount );
return sDate8;
}
/*************************************************************************/
@@ -232,13 +255,14 @@ xbBool xbDate::operator>=( const xbDate &dt ) const {
/*!
This routine calculates a century for a given year. It uses an 80/20
rolling date window to calculate the century.
-
+
\param iCalcYear - Two digit year to calculate a century for.
\returns Century calculated for the two digit year.
*/
xbInt16 xbDate::CalcRollingCenturyForYear( xbInt16 iCalcYear ) const {
xbDate d;
+ d.Sysdate();
xbInt16 iThisYear = d.YearOf();
xbInt16 iThisCentury = d.CenturyOf();
iThisYear -= (iThisCentury * 100);
@@ -254,14 +278,18 @@ xbInt16 xbDate::CalcRollingCenturyForYear( xbInt16 iCalcYear ) const {
/*************************************************************************/
//! @brief Get century for date.
/*!
- \returns This routine returns the century from the date.
+ \returns the century from the valid date.\ or 0 for a null date.
*/
xbInt16 xbDate::CenturyOf() const {
- char Century[3];
- Century[0] = sDate8[1];
- Century[1] = sDate8[2];
- Century[2] = 0x00;
- return( atoi( Century ));
+ if( !IsNull() ){
+ char Century[3];
+ Century[0] = sDate8[1];
+ Century[1] = sDate8[2];
+ Century[2] = 0x00;
+ return( atoi( Century ));
+ } else {
+ return 0;
+ }
}
/*************************************************************************/
//! @brief Get the day of the week.
@@ -271,22 +299,24 @@ xbInt16 xbDate::CenturyOf() const {
*/
xbInt16 xbDate::CharDayOf( xbString &sOutCharDay ) {
- struct tm tblock;
- char buf[25];
-
- tblock.tm_year = YearOf() - 1900;
- tblock.tm_mon = MonthOf() - 1;
- tblock.tm_mday = DayOf( XB_FMT_MONTH );
- tblock.tm_hour = 0;
- tblock.tm_min = 0;
- tblock.tm_sec = 1;
- tblock.tm_isdst = -1;
- if( mktime( &tblock ) == -1 ){
- sOutCharDay = "" ;
- return XB_INVALID_DATE;
- } else {
- strftime( buf, 25, "%A", &tblock );
- sOutCharDay = buf;
+ if( !IsNull()){
+ struct tm tblock;
+ char buf[25];
+
+ tblock.tm_year = YearOf() - 1900;
+ tblock.tm_mon = MonthOf() - 1;
+ tblock.tm_mday = DayOf( XB_FMT_MONTH );
+ tblock.tm_hour = 0;
+ tblock.tm_min = 0;
+ tblock.tm_sec = 1;
+ tblock.tm_isdst = -1;
+ if( mktime( &tblock ) == -1 ){
+ sOutCharDay = "" ;
+ return XB_INVALID_DATE;
+ } else {
+ strftime( buf, 25, "%A", &tblock );
+ sOutCharDay = buf;
+ }
}
return XB_NO_ERROR;;
}
@@ -297,21 +327,24 @@ xbInt16 xbDate::CharDayOf( xbString &sOutCharDay ) {
\returns XB_INVALID_DATE<br>XB_NO_ERROR
*/
xbInt16 xbDate::CharMonthOf( xbString &sOutCharMonth ) {
- struct tm tblock;
- char buf[25];
- tblock.tm_year = YearOf() - 1900;
- tblock.tm_mon = MonthOf() - 1;
- tblock.tm_mday = DayOf( XB_FMT_MONTH );
- tblock.tm_hour = 0;
- tblock.tm_min = 0;
- tblock.tm_sec = 1;
- tblock.tm_isdst = -1;
- if( mktime( &tblock ) == -1 ){
- sOutCharMonth = "";
- return XB_INVALID_DATE;
- } else {
- strftime( buf, 25, "%B", &tblock );
- sOutCharMonth = buf;
+
+ if( !IsNull()){
+ struct tm tblock;
+ char buf[25];
+ tblock.tm_year = YearOf() - 1900;
+ tblock.tm_mon = MonthOf() - 1;
+ tblock.tm_mday = DayOf( XB_FMT_MONTH );
+ tblock.tm_hour = 0;
+ tblock.tm_min = 0;
+ tblock.tm_sec = 1;
+ tblock.tm_isdst = -1;
+ if( mktime( &tblock ) == -1 ){
+ sOutCharMonth = "";
+ return XB_INVALID_DATE;
+ } else {
+ strftime( buf, 25, "%B", &tblock );
+ sOutCharMonth = buf;
+ }
}
return XB_NO_ERROR;
}
@@ -387,45 +420,48 @@ xbBool xbDate::DateIsValid( const xbString &sDateIn ) const {
xbInt16 xbDate::DayOf( xbInt16 iFormat ) const {
- xbInt16 iOutDay = 0;
- char sDay[3];
- xbInt16 iDay, iMonth, iYear, iDay2;
-
- // check for valid format switch
- if( iFormat!=XB_FMT_WEEK && iFormat!=XB_FMT_MONTH && iFormat!=XB_FMT_YEAR )
- return XB_INVALID_OPTION;
-
- if( iFormat == XB_FMT_WEEK ){
- //DayOf( XB_FMT_MONTH, iDay );
- iDay = DayOf( XB_FMT_MONTH );
- iMonth = MonthOf();
- iYear = YearOf();
-
- // The following formula uses Zeller's Congruence to determine the day of the week
- if( iMonth > 2 ) // init to February
- iMonth -= 2;
- else {
- iMonth += 10;
- iYear--;
- }
- iDay2 = ((13 * iMonth - 1) / 5) + iDay + ( iYear % 100 ) +
- (( iYear % 100 ) / 4) + ((iYear /100 ) / 4 ) - 2 *
- ( iYear / 100 ) + 77 ;
+ if( !IsNull()){
+ xbInt16 iOutDay = 0;
+ char sDay[3];
+ xbInt16 iDay, iMonth, iYear, iDay2;
+
+ // check for valid format switch
+ if( iFormat!=XB_FMT_WEEK && iFormat!=XB_FMT_MONTH && iFormat!=XB_FMT_YEAR )
+ return XB_INVALID_OPTION;
+
+ if( iFormat == XB_FMT_WEEK ){
+ //DayOf( XB_FMT_MONTH, iDay );
+ iDay = DayOf( XB_FMT_MONTH );
+ iMonth = MonthOf();
+ iYear = YearOf();
+
+ // The following formula uses Zeller's Congruence to determine the day of the week
+ if( iMonth > 2 ) // init to February
+ iMonth -= 2;
+ else {
+ iMonth += 10;
+ iYear--;
+ }
+ iDay2 = ((13 * iMonth - 1) / 5) + iDay + ( iYear % 100 ) +
+ (( iYear % 100 ) / 4) + ((iYear /100 ) / 4 ) - 2 *
+ ( iYear / 100 ) + 77 ;
- iOutDay = iDay2 - 7 * ( iDay2 / 7 );
- iOutDay == 6 ? iOutDay = 0 : iOutDay++;
- }
- else if( iFormat == XB_FMT_MONTH ){
- sDay[0] = sDate8[7];
- sDay[1] = sDate8[8];
- sDay[2] = 0x00;
- iOutDay = atoi( sDay );
+ iOutDay = iDay2 - 7 * ( iDay2 / 7 );
+ iOutDay == 6 ? iOutDay = 0 : iOutDay++;
+ }
+ else if( iFormat == XB_FMT_MONTH ){
+ sDay[0] = sDate8[7];
+ sDay[1] = sDate8[8];
+ sDay[2] = 0x00;
+ iOutDay = atoi( sDay );
+ } else {
+ iOutDay = iAggregatedDaysInMonths[IsLeapYear()][MonthOf()-1] + DayOf( XB_FMT_MONTH );
+ }
+ return iOutDay;
} else {
- iOutDay = iAggregatedDaysInMonths[IsLeapYear()][MonthOf()-1] + DayOf( XB_FMT_MONTH );
+ return 0;
}
- return iOutDay;
}
-
/*************************************************************************/
#ifdef XB_DEBUG_SUPPORT
//! @brief Dump date information to stdout.
@@ -466,7 +502,6 @@ void xbDate::DumpDateTables(){
*/
xbInt16 xbDate::CTOD( const xbString &sCtodInDate ){
-
if( sCtodInDate[1] != ' ' && ( sCtodInDate[3] == '\\' || sCtodInDate[3] == '/') ){
char yy[3];
yy[0] = sCtodInDate[7];
@@ -518,6 +553,9 @@ xbInt16 xbDate::FormatDate( const xbString &sFmtIn, xbString &sOutFmtDate ){
xbString sWrkFmt;
sOutFmtDate = "";
+ if( IsNull())
+ return XB_NO_ERROR;
+
/* use format for this specific string if available, else use default format */
if( strlen( sFmtIn ) > 0 )
sWrkFmt = sFmtIn;
@@ -600,6 +638,8 @@ const char * xbDate::Str() const{
\returns xbTrue - Is leapyear.<br> xbFalse - Not a leap year.
*/
xbBool xbDate::IsLeapYear() const {
+ if( IsNull() )
+ return xbFalse;
xbInt16 iYear = YearOf();
if(( iYear % 4 == 0 && iYear % 100 != 0 ) || iYear % 400 == 0 )
return xbTrue;
@@ -619,15 +659,30 @@ xbBool xbDate::IsLeapYear( xbInt16 iYear ) const {
return xbFalse;
}
/*************************************************************************/
+//! @brief Determine if date is null date
+/*!
+ \returns xbTrue - If null date.<br> xbFalse - Not a null date.
+*/
+xbBool xbDate::IsNull() const {
+ if( sDate8.Len() < 8 )
+ return xbTrue;
+ else
+ return xbFalse;
+}
+/*************************************************************************/
//! @brief Calculate julian days for a given date.
/*!
\returns The number of days since 01/01/0001 + JUL_OFFSET.
*/
xbInt32 xbDate::JulianDays() const{
- xbInt32 ly = YearOf() - 1;
- xbInt32 lDays = ly * 365L + ly / 4L - ly / 100L + ly / 400L;
- lDays += DayOf( XB_FMT_YEAR );
- return lDays + JUL_OFFSET;
+ if( !IsNull()){
+ xbInt32 ly = YearOf() - 1;
+ xbInt32 lDays = ly * 365L + ly / 4L - ly / 100L + ly / 400L;
+ lDays += DayOf( XB_FMT_YEAR );
+ return lDays + JUL_OFFSET;
+ } else {
+ return 0;
+ }
}
/*************************************************************************/
//! @brief Convert the number of julian days to gregorian date.
@@ -637,24 +692,23 @@ xbInt32 xbDate::JulianDays() const{
*/
xbInt16 xbDate::JulToDate8( xbInt32 lJulDays )
{
- lJulDays -= JUL_OFFSET;
- // calculate the year
- xbInt16 iYear = (xbInt16)(lJulDays / 365.24 );
- lJulDays -= (iYear * 365L) + (iYear / 4L) - (iYear / 100L) + (iYear / 400L);
- iYear++;
- while( lJulDays <= 0 ){
- iYear--;
- lJulDays += (365L + IsLeapYear( iYear ));
- }
- // this for loop calculates the month by comparing the number of days remaining to one of the tables
- xbInt16 iIsLeap = IsLeapYear(iYear);
- xbInt16 iMonth = 1;
- while( ((xbInt16) lJulDays > iAggregatedDaysInMonths[iIsLeap][iMonth]) && (iMonth < 12) )
- iMonth++;
-
- lJulDays -= iAggregatedDaysInMonths[iIsLeap][iMonth-1];
- sDate8.Sprintf( "%04d%02d%02ld", iYear, iMonth, lJulDays );
- return XB_NO_ERROR;
+ lJulDays -= JUL_OFFSET;
+ // calculate the year
+ xbInt16 iYear = (xbInt16)(lJulDays / 365.24 );
+ lJulDays -= (iYear * 365L) + (iYear / 4L) - (iYear / 100L) + (iYear / 400L);
+ iYear++;
+ while( lJulDays <= 0 ){
+ iYear--;
+ lJulDays += (365L + IsLeapYear( iYear ));
+ }
+ // this for loop calculates the month by comparing the number of days remaining to one of the tables
+ xbInt16 iIsLeap = IsLeapYear(iYear);
+ xbInt16 iMonth = 1;
+ while( ((xbInt16) lJulDays > iAggregatedDaysInMonths[iIsLeap][iMonth]) && (iMonth < 12) )
+ iMonth++;
+ lJulDays -= iAggregatedDaysInMonths[iIsLeap][iMonth-1];
+ sDate8.Sprintf( "%04d%02d%02ld", iYear, iMonth, lJulDays );
+ return XB_NO_ERROR;
}
/*************************************************************************/
//! @brief Set the date to the last day of month for a given date.
@@ -663,7 +717,8 @@ xbInt16 xbDate::JulToDate8( xbInt32 lJulDays )
\returns XB_NO_ERROR
*/
xbInt16 xbDate::LastDayOfMonth(){
- sDate8.Sprintf( "%4.4d%2.2d%2.2d", YearOf(), MonthOf(), iDaysInMonths[IsLeapYear()][MonthOf()]);
+ if( !IsNull())
+ sDate8.Sprintf( "%4.4d%2.2d%2.2d", YearOf(), MonthOf(), iDaysInMonths[IsLeapYear()][MonthOf()]);
return XB_NO_ERROR;
};
/*************************************************************************/
@@ -672,27 +727,33 @@ xbInt16 xbDate::LastDayOfMonth(){
\returns The month of the date.
*/
xbInt16 xbDate::MonthOf() const {
- xbInt16 iOutMonth;
- char month[3];
- month[0] = sDate8[5];
- month[1] = sDate8[6];
- month[2] = 0x00;
- iOutMonth = atoi( month );
- return iOutMonth;
+ if( !IsNull()){
+ xbInt16 iOutMonth;
+ char month[3];
+ month[0] = sDate8[5];
+ month[1] = sDate8[6];
+ month[2] = 0x00;
+ iOutMonth = atoi( month );
+ return iOutMonth;
+ } else {
+ return 0;
+ }
}
/*************************************************************************/
//! @brief Set the date.
/*!
\param sDateIn - Input date.
- \returns XB_NO_ERROR<br>XB_INVALID_DATE
+ \returns XB_NO_ERROR
*/
xbInt16 xbDate::Set( const xbString & sDateIn ){
+
if( DateIsValid( sDateIn )){
sDate8 = sDateIn;
- return XB_NO_ERROR;
+ } else {
+ sDate8 = ""; // set to null date if invalid date
}
- return XB_INVALID_DATE;
+ return XB_NO_ERROR;
}
/*************************************************************************/
//! @brief This routine sets up static data tables on startup.
@@ -790,13 +851,17 @@ xbInt16 xbDate::Sysdate(){
\returns The year of the date.
*/
xbInt16 xbDate::YearOf() const {
- char year[5];
- year[0] = sDate8[1];
- year[1] = sDate8[2];
- year[2] = sDate8[3];
- year[3] = sDate8[4];
- year[4] = 0x00;
- xbInt16 iOutYear = atoi( year );
- return iOutYear;
+ if( !IsNull()){
+ char year[5];
+ year[0] = sDate8[1];
+ year[1] = sDate8[2];
+ year[2] = sDate8[3];
+ year[3] = sDate8[4];
+ year[4] = 0x00;
+ xbInt16 iOutYear = atoi( year );
+ return iOutYear;
+ } else {
+ return 0;
+ }
};
} /* namespace */ \ No newline at end of file
diff --git a/src/core/xbdbf.cpp b/src/core/xbdbf.cpp
index 4033ef9..8904a6d 100755
--- a/src/core/xbdbf.cpp
+++ b/src/core/xbdbf.cpp
@@ -159,12 +159,14 @@ xbInt16 xbDbf::Abort(){
//! @brief Add an index to the internal list of indices for this table.
/*!
The index list is used during any table update process to update any open
- index file. Index files can contain one or more tags.
+ index file. Index files can contain one or more tags. Temporary tags
+ are not included here because they are created after a table is open
+ and will be deleted when the table is closed.
\param ixIn Pointer to index object for a given index file.
- \param sFmt NDX or MDX.
+ \param sFmt NDX, MDX or TDX.
\returns <a href="xbretcod_8h.html">Return Codes</a>
-
+
*/
xbInt16 xbDbf::AddIndex( xbIx * ixIn, const xbString &sFmt ){
@@ -295,6 +297,7 @@ xbInt16 xbDbf::AppendRecord(){
// calculate the latest header information
xbDate d;
+ d.Sysdate();
cUpdateYY = (char) d.YearOf() - 1900;
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
@@ -411,7 +414,7 @@ xbInt16 xbDbf::AppendRecord(){
\param sIxType Currently only NDX. Future versions will support additional non prod index types.
\param sIxName The index name.
\param iOpt 0 - Add index to .INF if not already there<br>
- 1 - Remove index from .INF if there
+ 1 - Remove index from .INF if exists
\returns <a href="xbretcod_8h.html">Return Codes</a>
@@ -534,7 +537,7 @@ xbInt16 xbDbf::BlankRecord()
This method is used to check an index tag's intgerity.
\param iTagOpt 0 - Check current tag<br>
- 1 - Check all tag<br>
+ 1 - Check all tags<br>
\param iOutputOpt Output message destination<br>
0 = stdout<br>
@@ -585,21 +588,41 @@ xbInt16 xbDbf::CheckTagIntegrity( xbInt16 iTagOpt, xbInt16 iOutputOpt ){
\param iTagOpt 0 - Reindex current tag<br>
1 - Reindex all tags<br>
+ 2 - Reindex for tag identified by vpTag
+ \param iErrorOpt 0 - Don't delete tag on reindex failure<br>
+ 1 - Delete tag on reindex failure
+ \param vpTag if option 2 used, pointer to tag to reindex
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
-xbInt16 xbDbf::Reindex( xbInt16 iTagOpt ){
+xbInt16 xbDbf::Reindex( xbInt16 iTagOpt, xbInt16 iErrorOpt, xbIx **ppIx, void **vppTag ){
xbInt16 iRc = XB_NO_ERROR;
xbInt16 iErrorStop = 0;
void *vp;
+ xbString sType;
+ xbString sTagName;
+
+ if( iTagOpt < 0 || iTagOpt > 2 || (iTagOpt == 2 && (!ppIx || !vppTag )))
+ return XB_INVALID_OPTION;
+
+
+ #ifdef XB_BLOCKREAD_SUPPORT
+ xbBool bOriginalBlockReadSts = GetBlockReadStatus();
+ #endif
+
try{
+
+ #ifdef XB_BLOCKREAD_SUPPORT
+ if( !bOriginalBlockReadSts )
+ EnableBlockReadProcessing();
+ #endif
+
if( iTagOpt == 0 ){
if( pCurIx ){
- iRc = pCurIx->Reindex( &vpCurIxTag );
- if( iRc != XB_NO_ERROR ){
+ if(( iRc = pCurIx->Reindex( &vpCurIxTag )) != XB_NO_ERROR ){
iErrorStop = 100;
throw iRc;
}
@@ -608,7 +631,7 @@ xbInt16 xbDbf::Reindex( xbInt16 iTagOpt ){
return XB_INVALID_TAG;
}
- } else {
+ } else if( iTagOpt == 1 ) {
xbLinkListNode<xbTag *> *llN = GetTagList();
xbTag *pTag;
@@ -622,6 +645,19 @@ xbInt16 xbDbf::Reindex( xbInt16 iTagOpt ){
}
llN = llN->GetNextNode();
}
+ } else if( iTagOpt == 2 ){
+
+ // xbIx *pIx;
+ // pIx = *ppIx;
+ xbIx *pIx = *ppIx;
+ // void *vpTag;
+ // vpTag = *vppTag;
+ void *vpTag = *vppTag;
+
+ if(( iRc = pIx->Reindex( &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
}
}
catch (xbInt16 iRc ){
@@ -630,6 +666,12 @@ xbInt16 xbDbf::Reindex( xbInt16 iTagOpt ){
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
}
+
+ #ifdef XB_BLOCKREAD_SUPPORT
+ if( !bOriginalBlockReadSts )
+ DisableBlockReadProcessing();
+ #endif
+
return iRc;
}
@@ -939,10 +981,10 @@ xbInt16 xbDbf::CopyDbfStructure( xbDbf * dNewTable, const xbString &sNewTableNam
#ifdef XB_INDEX_SUPPORT
//! @brief Create a new tag (index) for this dbf file (table).
/*!
- This routine creates a new tag (index) on a dbf file. The library currently supports NDX and MDX
+ This routine creates a new tag (index) on a dbf file. The library currently supports NDX, MDX ans TDX.
indices. If you don't have a specific need for an NDX file, use MDX.
- \param sIxType "MDX" or "NDX".
+ \param sIxType "MDX", "NDX" or "NTX".
\param sName Index or tag name.
\param sKey Index key expression,
\param sFilter Filter expression. Not applicable for NDX indices.
@@ -1002,6 +1044,8 @@ xbInt16 xbDbf::CreateTag( const xbString &sIxType, const xbString &sName, const
}
*pIxOut = ixNdx;
+
+
// Set the current tag if one not already set
if( sCurIxType == "" ){
sCurIxType = "NDX";
@@ -1031,6 +1075,7 @@ xbInt16 xbDbf::CreateTag( const xbString &sIxType, const xbString &sName, const
ixMdx = (xbIxMdx *) ixList->ix;
bMdxFound = xbTrue;
}
+ ixList = ixList->next;
}
if( !bMdxFound )
@@ -1061,7 +1106,53 @@ xbInt16 xbDbf::CreateTag( const xbString &sIxType, const xbString &sName, const
pCurIx = ixMdx;
vpCurIxTag = ixMdx->GetTag(0);
}
+ #endif
+
+ #ifdef XB_TDX_SUPPORT
+ } else if( sIxType == "TDX" ){
+
+ if( GetVersion() == 3 ){ // TDX indexes were version 4 and higher
+ iErrorStop = 140;
+ iRc = XB_INVALID_INDEX;
+ throw iRc;
+ }
+ xbIxTdx *ixTdx;
+ xbString s;
+ // look through the index list and see if there is an mdx pointer we can grab
+ xbBool bTdxFound = xbFalse;
+ xbIxList *ixList = GetIxList();
+ while( ixList && !bTdxFound ){
+ s = ixList->sFmt->Str();
+ if( s == "TDX" ){
+ ixTdx = (xbIxTdx *) ixList->ix;
+ bTdxFound = xbTrue;
+ }
+ ixList = ixList->next;
+ }
+ if( !bTdxFound )
+ ixTdx = new xbIxTdx( this );
+
+ if(( iRc = ixTdx->CreateTag( sName, sKey, sFilter, iDescending, iUnique, iOverLay, vpTagOut )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+ if( !bTdxFound ){
+ if(( iRc = AddIndex( ixTdx, "TDX" )) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ }
+ *pIxOut = ixTdx;
+
+ // set the current tag if one not already set
+ if( sCurIxType == "" ){
+
+ sCurIxType = "TDX";
+ pCurIx = ixTdx;
+ vpCurIxTag = ixTdx->GetTag(0);
+ }
+
#endif
} else {
@@ -1192,17 +1283,23 @@ xbInt16 xbDbf::DeleteAllIndexFiles(){
// close any open index files, delete it, remove from the ix list
while( ixList ){
+
+ // next two lines for debugging
+ ixList->ix->GetFileNamePart( sIxName );
ixList->ix->Close();
- ixList->ix->xbRemove();
+ if(( iRc = ixList->ix->xbRemove()) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
#ifdef XB_INF_SUPPORT
// if XB_INF_SUPPORT is enabled, all open non prod indices should be in here
- if( *ixList->sFmt != "MDX" ){ // production indices not stored in .INF dataset
+ if( *ixList->sFmt != "MDX" && *ixList->sFmt != "TDX" ){ // production and temp indices not stored in .INF dataset
if(( iRc = ixList->ix->GetFileNamePart( sIxName )) != XB_NO_ERROR ){
- iErrorStop = 110;
+ iErrorStop = 120;
throw iRc;
}
if(( iRc = AssociateIndex( *ixList->sFmt, sIxName, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
+ iErrorStop = 130;
throw iRc;
}
}
@@ -1391,7 +1488,7 @@ xbInt16 xbDbf::DeleteTable(){
/*!
This routine deletes an index tag
- \param sIxType Either "NDX" or "MDX".<br>
+ \param sIxType Either "NDX", "MDX" or "TDX".<br>
\param sName Tag name to delete.<br>
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
@@ -1452,7 +1549,7 @@ xbInt16 xbDbf::DeleteTag( const xbString &sIxType, const xbString &sName ){
throw iRc;
}
- if( ixl->ix == pCurIx )
+ if( !ixList || ixl->ix == pCurIx )
SetCurTag( "", NULL, NULL );
}
@@ -1500,7 +1597,64 @@ xbInt16 xbDbf::DeleteTag( const xbString &sIxType, const xbString &sName ){
iErrorStop = 170;
throw iRc;
}
- if( ixl->ix == pCurIx )
+ if( !ixList || ixl->ix == pCurIx )
+ SetCurTag( "", NULL, NULL );
+ }
+ }
+ ixlPrev = ixl;
+ ixl = ixlNext;
+ }
+
+ if( !bDone )
+ return XB_INVALID_TAG;
+ #endif
+
+ #ifdef XB_TDX_SUPPORT
+ } else if( sIxType == "TDX" ){
+ xbIxList *ixl = ixList;
+ xbIxList *ixlNext;
+ xbIxList *ixlPrev = NULL;
+ xbBool bDone = xbFalse;
+ xbIxTdx *pTdx;
+ xbMdxTag *pMdxTag;
+ xbInt16 iTagCnt = 0;
+
+ while( ixl && !bDone ){
+ ixlNext = ixl->next;
+ pTdx = (xbIxTdx *) ixl->ix;
+ iTagCnt = pTdx->GetTagCount();
+ for( xbInt16 i = 0; i < iTagCnt && !bDone; i++ ){
+ pMdxTag = (xbMdxTag *) pTdx->GetTag( i );
+ if( pTdx->GetTagName( pMdxTag ) == sName ){
+ bDone = xbTrue;
+ iRc = pTdx->DeleteTag( pMdxTag );
+ if( iRc > 0 ){
+ // Successful delete of only tag in production mdx file - need to remove it from the list, update the dbf header
+ cIndexFlag = 0x00;
+ if(( iRc = WriteHeader( 1, 0 )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+ if(( iRc = RemoveIndex( ixl->ix )) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ if( ixlPrev == NULL ){
+ // std::cout << "setting ixList to null or should be\n";
+ ixList = ixlNext;
+ } else {
+ ixlPrev = ixlNext;
+ }
+ } else if( iRc < 0 ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+ if( ixList )
+ std::cout << "ixlist not null\n";
+ else
+ std::cout << "ixlist null\n";
+
+ if( !ixList || ixl->ix == pCurIx )
SetCurTag( "", NULL, NULL );
}
}
@@ -1513,6 +1667,8 @@ xbInt16 xbDbf::DeleteTag( const xbString &sIxType, const xbString &sName ){
#endif
+
+
} else {
iErrorStop = 180;
iRc = XB_INVALID_OPTION;
@@ -1562,15 +1718,19 @@ xbInt16 xbDbf::DeleteTag( const xbString &sIxType, const xbString &sName ){
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
-xbInt16 xbDbf::DumpHeader( xbInt16 iOption ) const {
+xbInt16 xbDbf::DumpHeader( xbInt16 iOption ){
int i;
int iMemoCtr = 0;
if( iOption < 1 || iOption > 4 )
return XB_INVALID_OPTION;
- if( iDbfStatus == XB_CLOSED )
- return XB_NOT_OPEN;
+ xbInt16 iRc = ReadHeader( xbTrue, 0 );
+ if( iRc != XB_NO_ERROR )
+ return iRc;
+
+// if( iDbfStatus == XB_CLOSED )
+// return XB_NOT_OPEN;
std::cout << "\nDatabase file " << GetFqFileName() << std::endl << std::endl;
@@ -1859,7 +2019,7 @@ xbUInt32 xbDbf::GetAppendLocked() const {
This routine returns the table setting if set, otherwise returns the system
level setting.
-
+
\returns Not 0 - Auto commit on for this table.<br>
0 - Auto commit off for this table.
*/
@@ -1920,8 +2080,10 @@ xbIx *xbDbf::GetCurIx() const {
/************************************************************************/
//! @brief Get pointer to current tag for the current index.
/*!
- An index file can have one or more tags. An NDX index has one tag.
- An MDX file can have up to 47 tags.
+ An index file can have one or more tags
+ NDX index files have one tag per file.
+ MDX index files can can have up to 47 tags per file.
+ TDX index files can can have up to 47 tags per file.
\returns Pointer to current tag.
*/
@@ -1932,7 +2094,8 @@ void *xbDbf::GetCurTag() const {
//! @brief Get the current index type.
/*!
\returns NDX for single tag index.<br>
- MDX for production multi tag index.
+ MDX for production multi tag index.<br>
+ TDX for temporary tag index.
*/
const xbString &xbDbf::GetCurIxType() const {
return sCurIxType;
@@ -2097,12 +2260,16 @@ xbBool xbDbf::GetBof() {
/************************************************************************/
//! @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.
+ \returns Returns true if error, dbf file is empty or positioned on the last record.
*/
xbBool xbDbf::GetEof() {
- xbUInt32 ulRecCnt = GetRecordCount();
+
+ // xbUInt32 ulRecCnt = GetRecordCount();
- if( ulRecCnt == 0 || GetCurRecNo() == ulRecCnt )
+ xbUInt32 ulRecCnt;
+ xbInt16 iRc = GetRecordCnt( ulRecCnt );
+
+ if( iRc != XB_NO_ERROR || ulRecCnt == 0 || GetCurRecNo() == ulRecCnt )
return xbTrue;
else
return xbFalse;
@@ -2542,6 +2709,7 @@ char * xbDbf::GetRecordBuf( xbInt16 iOpt ) const {
/*!
\returns Record count or <a href="xbretcod_8h.html">Return Codes</a>
*/
+/*
xbUInt32 xbDbf::GetRecordCount(){
xbUInt32 ulCnt;
@@ -2551,7 +2719,7 @@ xbUInt32 xbDbf::GetRecordCount(){
else
return ulCnt;
}
-
+*/
/************************************************************************/
//! @brief Get the current number of records in the dbf data file.
/*!
@@ -2626,8 +2794,8 @@ xbBool xbDbf::GetTableLocked() const {
This routine returns a list of tags for the file.<br>
The library is structured to support one or more files of the same or differing
- index types (NDX/MDX), with each file supporting one or more index tags.<br>
-
+ index types (NDX/MDX/TDX), with each file supporting one or more index tags.<br>
+
\returns Tag list for the file/table.
*/
xbLinkListNode<xbTag *> *xbDbf::GetTagList() const {
@@ -2944,6 +3112,19 @@ xbInt16 xbDbf::LockIndices( xbInt16 iLockFunction )
}
#endif
+ #ifdef XB_TDX_SUPPORT
+ if( *ixLI->sFmt == "TDX" ){
+ if( !ixLI->ix->GetLocked()){
+ if(( iRc = ixLI->ix->xbLock( XB_LOCK, LK4026531838, 1 )) != XB_NO_ERROR ){
+ ixLI->ix->xbLock( XB_UNLOCK, LK4026531838, 1 );
+ iErrorStop = 100;
+ throw iRc;
+ }
+ ixLI->ix->SetLocked( xbTrue );
+ }
+ }
+ #endif
+
} else if( iLockFunction == XB_UNLOCK ){
#ifdef XB_NDX_SUPPORT
@@ -2970,6 +3151,18 @@ xbInt16 xbDbf::LockIndices( xbInt16 iLockFunction )
}
#endif
+ #ifdef XB_TDX_SUPPORT
+ if( *ixLI->sFmt == "MDX" ){
+ if( ixLI->ix->GetLocked()){
+ if(( iRc = ixLI->ix->xbLock( XB_UNLOCK, LK4026531838, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ ixLI->ix->SetLocked( xbFalse );
+ }
+ }
+ #endif
+
}
ixLI = ixLI->next;
}
@@ -3377,7 +3570,7 @@ xbInt16 xbDbf::OpenIndex( const xbString &sIxType, const xbString &sFileName ){
xbInt16 xbDbf::Pack()
{
xbUInt32 ulDeletedRecCnt;
- return Pack( ulDeletedRecCnt );
+ return Pack( ulDeletedRecCnt );
}
@@ -3484,6 +3677,7 @@ xbInt16 xbDbf::Pack( xbUInt32 &ulDeletedRecCnt )
// update header record count
xbDate d;
+ d.Sysdate();
cUpdateYY = (char) d.YearOf() - 1900;
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
@@ -3520,7 +3714,6 @@ xbInt16 xbDbf::Pack( xbUInt32 &ulDeletedRecCnt )
}
}
#endif // XB_MEMO_SUPPORT
-
}
catch (xbInt16 iRc ){
if( iRc != XB_LOCK_FAILED ){
@@ -3665,6 +3858,7 @@ xbInt16 xbDbf::PutRecord(xbUInt32 ulRecNo)
// update latest header date if changed
xbDate d;
+ d.Sysdate();
if( (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();
@@ -3716,9 +3910,9 @@ xbInt16 xbDbf::PutRecord(xbUInt32 ulRecNo)
LockHeader( XB_UNLOCK );
LockAppend( XB_UNLOCK );
LockRecord( XB_UNLOCK, ulRecNo );
- #ifdef XB_INDEX_SUPPORT
+ #ifdef XB_INDEX_SUPPORT
LockIndices( XB_UNLOCK );
- #endif // XB_INDEX_SUPPORT
+ #endif // XB_INDEX_SUPPORT
}
#endif // XB_LOCKING_SUPPORT
@@ -3972,7 +4166,7 @@ xbInt16 xbDbf::SetCurTag( const xbString &sTagName ){
//! @brief Set the current tag for the dbf file.
/*!
- \param sIxType - One of "NDX" or MDX",
+ \param sIxType - One of "NDX", MDX or TDX",
\param pIx - Pointer to index object.
\param vpTag - Pointer to tag object.
\returns <a href="xbretcod_8h.html">Return Codes</a>
@@ -4206,6 +4400,7 @@ xbInt16 xbDbf::Zap(){
#endif
xbDate d;
+ d.Sysdate();
cUpdateYY = (char) d.YearOf() - 1900;
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
diff --git a/src/core/xbdbf3.cpp b/src/core/xbdbf3.cpp
index d57be3c..926cc0d 100755
--- a/src/core/xbdbf3.cpp
+++ b/src/core/xbdbf3.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.
@@ -180,6 +180,7 @@ xbInt16 xbDbf3::CreateTable( const xbString & sTableName, const xbString & sAlia
ulCurRec = 0L;
uiHeaderLen = 33 + iNoOfFields * 32;
xbDate d;
+ d.Sysdate();
cUpdateYY = (char) (d.YearOf() - 1900);
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
diff --git a/src/core/xbdbf4.cpp b/src/core/xbdbf4.cpp
index 59ba39a..a1f770e 100755
--- a/src/core/xbdbf4.cpp
+++ b/src/core/xbdbf4.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.
@@ -180,6 +180,7 @@ xbInt16 xbDbf4::CreateTable( const xbString &sTableName, const xbString &sAlias,
ulCurRec = 0L;
uiHeaderLen = 33 + iNoOfFields * 32;
xbDate d;
+ d.Sysdate();
cUpdateYY = (char) (d.YearOf() - 1900);
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
@@ -510,7 +511,7 @@ xbInt16 xbDbf4::Open( const xbString & sTableName, const xbString & sAlias,
/************************************************************************/
//! @brief Rename table.
/*!
- This routine renames a give table, associated memo and inf files
+ This routine renames a table, associated memo, mdx and inf files
\param sNewName - New file name.
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
diff --git a/src/core/xbexp.cpp b/src/core/xbexp.cpp
index deea53d..b2d4db9 100755
--- a/src/core/xbexp.cpp
+++ b/src/core/xbexp.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2017,2021,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2017,2021,2022,2023 Gary A Kunkel
The xb64 software library is covered under
the terms of the GPL Version 3, 2007 license.
@@ -1097,12 +1097,12 @@ xbBool xbExp::IsOperator( const xbString & sExpression ){
}
/*************************************************************************/
-//! Is Token seperator
-/*! This method determines if the next token is a seperator.
+//! Is Token separator
+/*! This method determines if the next token is a separator.
\param sExpression - String expression to be evaluated.
- \returns xbTrue - Is a token seperator.<br>
- xbFalse - Is not a token seperator.
+ \returns xbTrue - Is a token separator.<br>
+ xbFalse - Is not a token separator.
*/
char xbExp::IsTokenSeparator( char c ){
if( c == '-' || c == '+' || c == '*' || c == '/' || c == '$' || c == '#' ||
@@ -1205,12 +1205,13 @@ xbInt16 xbExp::ParseExpression( xbDbf *dbf, const xbString &sExpression ){
*/
xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
- xbExpNode *n;
+ xbExpNode *n = NULL;
xbExpNode *nLastNode = NULL; // pointer to the last node processed
xbExpToken t;
xbInt16 iRc = XB_NO_ERROR;
xbInt16 iErrorStop = 0;
xbString s;
+ xbBool bNewNode = xbFalse;
try {
@@ -1249,6 +1250,7 @@ xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
case XB_EXP_CONSTANT:
n = new xbExpNode( t.sToken, t.cNodeType );
+ bNewNode = xbTrue;
if(( iRc = ParseExpressionConstant( t, n )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
@@ -1257,6 +1259,7 @@ xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
case XB_EXP_FUNCTION:
n = new xbExpNode( t.cNodeType );
+ bNewNode = xbTrue;
if(( iRc = ParseExpressionFunction( t, n, iWeight )) != XB_NO_ERROR ){
iErrorStop = 130;
throw iRc;
@@ -1265,6 +1268,7 @@ xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
case XB_EXP_FIELD:
n = new xbExpNode( t.cNodeType );
+ bNewNode = xbTrue;
if(( iRc = ParseExpressionField( t, n )) != XB_NO_ERROR ){
iErrorStop = 140;
throw iRc;
@@ -1275,6 +1279,7 @@ xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
case XB_EXP_PRE_OPERATOR:
case XB_EXP_POST_OPERATOR:
n = new xbExpNode( t.sToken, t.cNodeType );
+ bNewNode = xbTrue;
if(( iRc = ParseExpressionOperator( t, n, iWeight )) != XB_NO_ERROR ){
iErrorStop = 150;
throw iRc;
@@ -1429,6 +1434,8 @@ xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){
}
}
catch (xbInt16 iRc ){
+ if( bNewNode && n )
+ delete n;
xbString sMsg;
sMsg.Sprintf( "xbexp::ParseExpression() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg.Str() );
@@ -1933,7 +1940,9 @@ xbInt16 xbExp::ProcessExpression( xbInt16 iRecBufSw ){
throw iRc;
}
if( sWork1 == " " ){
- nWork->SetResult( (xbDouble) 21474835648 ); // dbase sets a date value in ndx to this if spaces on dbf record
+ // std::cout << "xbExp::ProcessExpression() line 1938 sWork is spaces\n";
+ //nWork->SetResult( (xbDouble) 21474835648 ); // dbase sets a date value in both ndx and mdx index files to this if spaces on dbf record
+ nWork->SetResult( (xbDouble) XB_NULL_DATE );
} else {
dtWork1.Set( sWork1 );
nWork->SetResult( (xbDouble) dtWork1.JulianDays() );
@@ -2423,7 +2432,6 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
xbString sMsg;
try{
-
n->GetNodeText( sOperator );
nChild1 = n->GetChild( 0 );
if( !n->IsUnaryOperator())
@@ -2532,10 +2540,19 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
if( nChild1->GetReturnType() == XB_EXP_CHAR )
n->SetResult((xbBool)(nChild1->GetStringResult() > nChild2->GetStringResult()));
- else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+
+ else if( nChild1->GetReturnType() == XB_EXP_NUMERIC )
n->SetResult((xbBool)(nChild1->GetNumericResult() > nChild2->GetNumericResult()));
- else {
+ else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+ n->SetResult((xbBool)( d1 > d2));
+ // n->SetResult((xbBool)(nChild1->GetNumericResult() > nChild2->GetNumericResult()));
+
+ } else {
iErrorStop = 410;
iRc = XB_PARSE_ERROR;
throw iRc;
@@ -2546,10 +2563,18 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
if( nChild1->GetReturnType() == XB_EXP_CHAR )
n->SetResult((xbBool)(nChild1->GetStringResult() >= nChild2->GetStringResult()));
- else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+ else if( nChild1->GetReturnType() == XB_EXP_NUMERIC )
n->SetResult((xbBool)(nChild1->GetNumericResult() >= nChild2->GetNumericResult()));
- else {
+ else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+ n->SetResult((xbBool)( d1 >= d2));
+ //n->SetResult((xbBool)(nChild1->GetNumericResult() >= nChild2->GetNumericResult()));
+
+ } else {
iErrorStop = 420;
iRc = XB_PARSE_ERROR;
throw iRc;
@@ -2558,13 +2583,23 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
else if( sOperator == "<" ){
- if( nChild1->GetReturnType() == XB_EXP_CHAR )
+ if( nChild1->GetReturnType() == XB_EXP_CHAR ){
n->SetResult((xbBool)( nChild1->GetStringResult() < nChild2->GetStringResult()));
- else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+ } else if( nChild1->GetReturnType() == XB_EXP_NUMERIC ){
n->SetResult((xbBool)( nChild1->GetNumericResult() < nChild2->GetNumericResult()));
- else {
+ } else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+
+ n->SetResult((xbBool)( d1 < d2));
+
+ // std::cout << "xbexp() line 2567 [" << nChild1->GetNumericResult() << "][" << nChild2->GetNumericResult() << "]\n";
+
+ } else {
iErrorStop = 430;
iRc = XB_PARSE_ERROR;
throw iRc;
@@ -2576,10 +2611,18 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
if( nChild1->GetReturnType() == XB_EXP_CHAR )
n->SetResult((xbBool)( nChild1->GetStringResult() <= nChild2->GetStringResult()));
- else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+ else if( nChild1->GetReturnType() == XB_EXP_NUMERIC )
n->SetResult((xbBool)( nChild1->GetNumericResult() <= nChild2->GetNumericResult()));
- else {
+ else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+ n->SetResult((xbBool)( d1 <= d2));
+ // n->SetResult((xbBool)( nChild1->GetNumericResult() <= nChild2->GetNumericResult()));
+
+ } else {
iErrorStop = 440;
iRc = XB_PARSE_ERROR;
throw iRc;
@@ -2591,10 +2634,18 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
if( nChild1->GetReturnType() == XB_EXP_CHAR )
n->SetResult((xbBool)( nChild1->GetStringResult() != nChild2->GetStringResult()));
- else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+ else if( nChild1->GetReturnType() == XB_EXP_NUMERIC )
n->SetResult((xbBool)( nChild1->GetNumericResult() != nChild2->GetNumericResult()));
- else {
+ else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+ n->SetResult((xbBool)( d1 != d2));
+ // n->SetResult((xbBool)( nChild1->GetNumericResult() != nChild2->GetNumericResult()));
+
+ } else {
iErrorStop = 450;
iRc = XB_PARSE_ERROR;
throw iRc;
@@ -2623,15 +2674,24 @@ xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){
sChld2.Rtrim();
n->SetResult((xbBool)( sChld1 == sChld2 ));
- } else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE )
+ } else if( nChild1->GetReturnType() == XB_EXP_NUMERIC ){
n->SetResult((xbBool)( nChild1->GetNumericResult() == nChild2->GetNumericResult()));
- else {
+ } else if( nChild1->GetReturnType() == XB_EXP_DATE ){
+ xbDouble d1 = nChild1->GetNumericResult();
+ xbDouble d2 = nChild2->GetNumericResult();
+ if( d1 == XB_NULL_DATE ) d1 = 0;
+ if( d2 == XB_NULL_DATE ) d2 = 0;
+ n->SetResult((xbBool)( d1 == d2));
+ // n->SetResult((xbBool)( nChild1->GetNumericResult() == nChild2->GetNumericResult()));
+
+ } else {
iErrorStop = 470;
iRc = XB_PARSE_ERROR;
throw iRc;
}
+
} else {
iErrorStop = 500;
iRc = XB_PARSE_ERROR;
diff --git a/src/core/xbexpnode.cpp b/src/core/xbexpnode.cpp
index 77a8c33..d11e8cc 100755
--- a/src/core/xbexpnode.cpp
+++ b/src/core/xbexpnode.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2017,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2017,2022,2023 Gary A Kunkel
The xb64 software library is covered under
the terms of the GPL Version 3, 2007 license.
diff --git a/src/core/xbfields.cpp b/src/core/xbfields.cpp
index e683d9c..85ac145 100755
--- a/src/core/xbfields.cpp
+++ b/src/core/xbfields.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.
@@ -87,8 +87,8 @@ xbInt16 xbDbf::GetDateField( xbInt16 iFieldNo, xbDate &dtFieldValue ) const{
xbInt16 iRc;
if(( iRc = GetField( iFieldNo, s )) != XB_NO_ERROR )
return iRc;
- dtFieldValue.Set( s );
- return XB_NO_ERROR;
+ return dtFieldValue.Set( s );
+ // return XB_NO_ERROR;
}
/************************************************************************/
@@ -106,8 +106,8 @@ xbInt16 xbDbf::GetDateField( const xbString &sFieldName, xbDate &dtFieldValue )
xbInt16 iRc;
if(( iRc = GetField( sFieldName, s )) != XB_NO_ERROR )
return iRc;
- dtFieldValue.Set( s );
- return XB_NO_ERROR;
+ return dtFieldValue.Set( s );
+ // return XB_NO_ERROR;
}
/************************************************************************/
@@ -163,6 +163,7 @@ xbInt16 xbDbf::GetField( xbInt16 iFieldNo, xbString &sFieldValue, xbInt16 iRecBu
return XB_NO_ERROR;
}
+
/************************************************************************/
//! @brief Get decimal for field name.
/*!
@@ -605,6 +606,68 @@ xbInt16 xbDbf::GetMemoFieldLen( const xbString &sFieldName, xbUInt32 &ulMemoFiel
#endif // XB_MEMO_SUPPORT
/************************************************************************/
+//! @brief Get field null status
+/*!
+ \param iFieldNo Number of field to retrieve.
+ \param bIsNull Output field value. If field is all spaces on record buffer, returns true.
+ \returns The field routines return one of:<br>
+ XB_NO_ERROR<br>XB_INVALID_DATA<br>XB_INVALID_FIELD_NO<br>XB_INVALID_FIELD_NAME<br>
+ XB_INVALID_FIELD_TYPE<br>XB_INVALID_DATA
+*/
+xbInt16 xbDbf::GetNullSts( xbInt16 iFieldNo, xbBool &bIsNull ) const {
+ return GetNullSts( iFieldNo, bIsNull, 0 );
+}
+
+/************************************************************************/
+//! @brief Get field null status
+/*!
+ \param iFieldName Field Name of field to retrieve.
+ \param bIsNull Output field value. If field is all spaces on record buffer, returns true.
+ \returns The field routines return one of:<br>
+ XB_NO_ERROR<br>XB_INVALID_DATA<br>XB_INVALID_FIELD_NO<br>XB_INVALID_FIELD_NAME<br>
+ XB_INVALID_FIELD_TYPE<br>XB_INVALID_DATA
+*/
+
+xbInt16 xbDbf::GetNullSts( const xbString &sFieldName, xbBool &bIsNull ) const {
+ return GetNullSts( GetFieldNo( sFieldName ), bIsNull, 0 );
+}
+
+/************************************************************************/
+//! @brief Get field null status
+/*!
+ \param iFieldNo Number of field to retrieve.
+ \param bIsNull Output field value. If field is all spaces on record buffer, returns true.
+ \param iRecBufSw 0 - Record buffer with any updates.<br>1 - Record buffer with original data.
+ \returns The field routines return one of:<br>
+ XB_NO_ERROR<br>XB_INVALID_DATA<br>XB_INVALID_FIELD_NO<br>XB_INVALID_FIELD_NAME<br>
+ XB_INVALID_FIELD_TYPE<br>XB_INVALID_DATA
+*/
+
+xbInt16 xbDbf::GetNullSts( xbInt16 iFieldNo, xbBool &bIsNull, xbInt16 iRecBufSw ) const
+{
+ if( iFieldNo < 0 || iFieldNo >= iNoOfFields ) {
+ return XB_INVALID_FIELD_NO;
+ }
+ bIsNull = xbTrue;
+ char *p;
+ if( iRecBufSw )
+ p = (char *) SchemaPtr[iFieldNo].pAddress2;
+ else
+ p = (char *) SchemaPtr[iFieldNo].pAddress;
+
+ xbUInt32 ulLen = SchemaPtr[iFieldNo].cFieldLen;
+ xbUInt32 ul = 0;
+
+ while( ul < ulLen && bIsNull ){
+ if( *p++ != ' ' )
+ bIsNull = xbFalse;
+ else
+ ul++;
+ }
+ return XB_NO_ERROR;
+}
+
+/************************************************************************/
//! @brief Get unsigned long field for field number.
/*!
\param iFieldNo Number of field to retrieve.
@@ -625,13 +688,11 @@ xbInt16 xbDbf::GetULongField( xbInt16 iFieldNo, xbUInt32 & ulFieldValue ) const
iErrorStop = 100;
throw rc;
}
-
if( cFieldType != 'N' && cFieldType != 'F' && cFieldType != 'M' ){
iErrorStop = 110;
rc = XB_INVALID_FIELD_TYPE;
throw rc;
}
-
xbString sTemp;
if(( rc = GetField( iFieldNo, sTemp, 0 )) != XB_NO_ERROR ){
iErrorStop = 120;
@@ -645,14 +706,12 @@ xbInt16 xbDbf::GetULongField( xbInt16 iFieldNo, xbUInt32 & ulFieldValue ) const
}
ulFieldValue = strtoul( sTemp.Str(), NULL, 10 );
}
-
catch (xbInt16 rc ){
xbString sMsg;
sMsg.Sprintf( "xbDbf::GetULongField() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, rc );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( rc ));
}
-
return XB_NO_ERROR;
}
diff --git a/src/core/xbfile.cpp b/src/core/xbfile.cpp
index 3b798a2..6376e9a 100755
--- a/src/core/xbfile.cpp
+++ b/src/core/xbfile.cpp
@@ -49,119 +49,6 @@ 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.
@@ -171,15 +58,16 @@ xbInt16 xbFile::SetHomeFolders(){
\param sFqnOut A fully qualifed unique file name as output
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
+/*
xbInt16 xbFile::CreateUniqueFileName( const xbString & sDirIn, const xbString & sExtIn, xbString &sFqnOut ){
return CreateUniqueFileName( sDirIn, sExtIn, sFqnOut, 0 );
}
-
+*/
/************************************************************************/
//! @brief Create a unique file name.
/*!
Given a directory and file extension as inputs, create a unique file name.
-
+
\param sDirIn Directory
\param sExtIn File Extension
\param iOption 0 - look only for one file for a given directory and extension<br>
@@ -192,12 +80,16 @@ xbInt16 xbFile::CreateUniqueFileName( const xbString & sDirIn, const xbString &
xbBool bUniqueFileNameFound = xbFalse;
xbFile f( xbase);
- xbInt32 l = 1;
+ xbInt32 l = 1;
xbString sMemoFileName;
+ xbString sDir = sDirIn;
+ char c = GetPathSeparator();
+ if( sDirIn.Len() > 0 && sDirIn[sDirIn.Len()] != c )
+ sDir += c;
while( !bUniqueFileNameFound ){
- sFqnOut.Sprintf( "%sxbTmp%03d.%s", sDirIn.Str(), l, sExtIn.Str());
+ sFqnOut.Sprintf( "%sxbTmp%03d.%s", sDir.Str(), l, sExtIn.Str());
if( iOption == 1 && sExtIn == "DBF" ){
sMemoFileName.Sprintf( "%sxbTmp%03d.DBT", sDirIn.Str(), l );
}
@@ -693,7 +585,6 @@ const xbString & xbFile::GetDirectory() const {
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
-
xbInt16 xbFile::GetFileDirPart( xbString & sFileDirPartOut ) const {
return GetFileDirPart( sFqFileName, sFileDirPartOut );
}
@@ -1139,7 +1030,6 @@ xbInt16 xbFile::SetBlockSize( xbUInt32 ulBlockSize ){
\param sDirectory - Valid directory name
*/
-
void xbFile::SetDirectory( const xbString & sDirectory ){
this->sDirectory = sDirectory;
@@ -1242,6 +1132,136 @@ void xbFile::SetFqFileName( const xbString & sFqFileName ){
}
/************************************************************************/
+//! @brief Set Home Folders.
+/*!
+ Create xbase64 log, data and temp 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 cPathSeparator;
+ 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
+ cPathSeparator = '\\';
+ #else
+ cPathSeparator = '/';
+ #endif
+ sDflt.Sprintf( ".%c", cPathSeparator );
+ // 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()] != cPathSeparator )
+ sHomeDir += cPathSeparator;
+
+ 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(), cPathSeparator );
+ // 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(), cPathSeparator );
+ // 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
+ }
+
+ sWork.Sprintf( "%sxbase64%ctemp%c", sHomeDir.Str(), cPathSeparator, cPathSeparator );
+ // std::cout << "tempdir = " << sWork.Str() << "\n";
+ if( FileExists( sWork ) == xbFalse ){
+ #ifdef WIN32
+ if( CreateDirectory( sWork.Str(), NULL ) == 0 ){
+ iErrorStop = 150;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #else
+ if( mkdir( sWork.Str(), 0777 ) == -1 ){
+ iErrorStop = 160;
+ iRc = XB_DIRECTORY_ERROR;
+ throw iRc;
+ }
+ #endif
+ }
+ xbase->SetTempDirectory( 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 Write a block of data to file.
/*!
@@ -1744,6 +1764,7 @@ xbInt16 xbFile::xbRemove( const xbString & sFileNameIn ) {
xbInt16 xbFile::xbRemove( const xbString & sFileNameIn, xbInt16 iOption ) {
xbInt32 iRc = remove( sFileNameIn.Str());
+
if( iRc != 0 )
return XB_DELETE_FAILED;
@@ -1904,7 +1925,7 @@ xbInt16 xbFile::xbLock( xbInt16 iFunction, xbInt64 lOffset, size_t stLen ){
Qsplit lPos;
Qsplit lLen;
- lPos.Qword = lOffset;
+ lPos.Qword = (size_t) lOffset;
lLen.Qword = stLen;
do{
@@ -2037,7 +2058,9 @@ xbInt16 xbFile::DumpMemToDisk( char *p, size_t lSize ){
try{
- sDir = GetLogDirectory();
+ // sDir = GetLogDirectory();
+ sDir = xbase->GetLogDirectory();
+
char cLastChar = sDir[sDir.Len()];
// build logfile name
@@ -2127,7 +2150,8 @@ xbInt16 xbFile::DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlkSize ){
throw iRc;
}
- sDir = GetLogDirectory();
+// sDir = GetLogDirectory();
+ sDir = xbase->GetLogDirectory();
char cLastChar = sDir[sDir.Len()];
for( xbUInt32 l = ulStartBlock; l < ulEndBlock; l++ ){
diff --git a/src/core/xbfilter.cpp b/src/core/xbfilter.cpp
index 0fb643d..5c5f276 100755
--- a/src/core/xbfilter.cpp
+++ b/src/core/xbfilter.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.
diff --git a/src/core/xbfuncs.cpp b/src/core/xbfuncs.cpp
index a038611..f127211 100755
--- a/src/core/xbfuncs.cpp
+++ b/src/core/xbfuncs.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2017,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2017,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -611,12 +611,13 @@ xbInt16 xbXBase::RTRIM( const xbString &sIn, xbString &sOut ){
/*!
Expression function SPACE().
\param lCnt Input - Number of spaces.
- \param sOut Output - Output String.
+ \param sOut Output - Output string consisting of specified number of spaces.
\returns XB_NO_ERROR.
*/
xbInt16 xbXBase::SPACE( xbInt32 lCnt, xbString &sOut ){
sOut = "";
- sOut.PadLeft( ' ', (xbUInt32) lCnt );
+ for( xbInt32 i = 0; i < lCnt; i++ )
+ sOut += ' ';
return XB_NO_ERROR;
}
diff --git a/src/core/xbixbase.cpp b/src/core/xbixbase.cpp
index 8b64fd6..e2f929c 100755
--- a/src/core/xbixbase.cpp
+++ b/src/core/xbixbase.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.
diff --git a/src/core/xbixmdx.cpp b/src/core/xbixmdx.cpp
index 135cde8..0eef64b 100755
--- a/src/core/xbixmdx.cpp
+++ b/src/core/xbixmdx.cpp
@@ -92,11 +92,7 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
iErrorStop = 100;
throw iRc;
}
-
xbInt32 lKeyCnt = GetKeyCount( npTag->npCurNode );
-
- // std::cout << "xbIxMdx::AddKeys() lKeyCnt = " << lKeyCnt << " KeysPerBlock = " << npTag->iKeysPerBlock << " npBlockNo = " << npTag->npCurNode->ulBlockNo << "\n";
-
if( lKeyCnt < npTag->iKeysPerBlock ){
// Section A - add key to appropriate position if space available
// std::cout << "AddKey Section A begin\n";
@@ -104,12 +100,8 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
iErrorStop = 110;
throw iRc;
}
- //std::cout << "AddKey Section A end\n";
} else {
-
// land here with a full leaf node
- // std::cout << "Section B begin split leaf node\n";
-
iHeadNodeUpdateOpt = 1;
npRightNode = AllocateIxNode( npTag, GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor );
if( !npRightNode ){
@@ -122,26 +114,14 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
ulNewRightChild = npRightNode->ulBlockNo * (xbUInt32) iBlockFactor;
}
- // std::cout << "ulNewRightChild = " << ulNewRightChild << "\n";
-
if(( iRc = xbIxMdx::SplitNodeL( npTag, npTag->npCurNode, npRightNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
iErrorStop = 130;
throw iRc;
}
xbUInt32 ulTempBlockNo = npRightNode->ulBlockNo;
-
- //std::cout << "ulTempBlockNo = " << ulTempBlockNo << "\n";
- //std::cout << "key count left block " << GetKeyCount( npTag->npCurNode ) << "\n";
- //std::cout << "key count right block " << GetKeyCount( npRightNode ) << "\n";
-
-
- //std::cout << "Section B end\n";
-
// section C - go up the tree, splitting nodes as necessary
xbIxNode * npParent = npTag->npCurNode->npPrev;
-
-
while( npParent && GetKeyCount( npParent ) >= npTag->iKeysPerBlock ){
//std::cout << "Section C begin interior node is full\n";
npRightNode = FreeNodeChain( npRightNode );
@@ -165,23 +145,15 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
npParent = npParent->npPrev;
}
- // std::cout << "Past Section C Cur Node Block No = " << npTag->npCurNode->ulBlockNo << " root page = " << npTag->ulRootPage << "\n";
// section D - if cur node is split root, create new root
-
if(( npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor ) == npTag->ulRootPage ){
-
- // std::cout << "Section D begin right node = " << npRightNode << "\n";
-
if(( iRc = AddKeyNewRoot( npTag, npTag->npCurNode, npRightNode )) != XB_NO_ERROR ){
iErrorStop = 160;
throw iRc;
}
-
if( npRightNode )
npRightNode = FreeNodeChain( npRightNode );
- // std::cout << "Section D end\n";
-
} else {
// std::cout << "Section E, put key in parent\n";
@@ -213,8 +185,6 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
if( ulNewRightChild > 0 ){
-// std::cout << "ulRightChild was = " << npTag->ulRightChild << " changed to " << ulNewRightChild << "\n";
-
char cBuf[4];
ePutUInt32( cBuf, ulNewRightChild );
if(( iRc = xbFseek( ((npTag->ulTagHdrPageNo * 512) + 252), SEEK_SET )) != XB_NO_ERROR ){
@@ -225,7 +195,6 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
iErrorStop = 220;
throw iRc;
}
-// std::cout << "setting right child\n";
npTag->ulRightChild = ulNewRightChild;
}
@@ -243,7 +212,6 @@ xbInt16 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
}
return iRc;
}
-
/***********************************************************************/
void xbIxMdx::AppendNodeChain( void *vpTag, xbIxNode * npNode ){
xbMdxTag * mdxTag = (xbMdxTag *) vpTag;
@@ -282,11 +250,6 @@ xbInt16 xbIxMdx::AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *np
}
npTag->ulRootPage = npRoot->ulBlockNo;
- // std::cout << "AddKeyNewRoot - RootBlock = " << npRoot->ulBlockNo << "\n";
- // std::cout << "AddKeyNewRoot - LeftBlock = " << npLeft->ulBlockNo << "\n";
- // std::cout << "AddKeyNewRoot - RightBlock = " << npRight->ulBlockNo << "\n";
-
-
pLastKey = (char *) malloc( (size_t) npTag->iKeyLen );
if(( iRc = GetLastKeyForBlockNo( npTag, npLeft->ulBlockNo, pLastKey )) != XB_NO_ERROR ){
iErrorStop = 110;
@@ -303,17 +266,8 @@ 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->iKeyItemLen)-4;
-
pTrg+= npTag->iKeyItemLen - 4;
-
- //pTrg-=4;
-
ePutUInt32( pTrg, npRight->ulBlockNo * (xbUInt32) iBlockFactor );
// write out the new block
@@ -326,8 +280,6 @@ xbInt16 xbIxMdx::AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *np
// position the file
xbUInt32 ulPagePos = npTag->ulTagHdrPageNo * 512;
- // std::cout << "ulPagePos = " << ulPagePos << " root block no = " << npRoot->ulBlockNo << " \n";
-
// save the number to a buffer
char cBuf[4];
ePutUInt32( cBuf, npRoot->ulBlockNo * ((xbUInt32) iBlockFactor ));
@@ -375,9 +327,6 @@ xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt
xbIxNode *n = NULL;
try{
-
- // std::cout << "xbIxMdx::AllocateIxNode()\n";
-
if(( n = xbIx::AllocateIxNode( ulBufSize )) == NULL ){
iRc = XB_NO_MEMORY;
iErrorStop = 100;
@@ -387,10 +336,7 @@ xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt
p += 4;
if( ulFirstFreePage > 0 && bReuseEmptyNodes ){
- // we have an empty node we can reuse
-
- // std::cout << "Reusing node " << ulFirstFreePage << "\n";
-
+ // have an empty node we can reuse
n->ulBlockNo = PageToBlock( ulFirstFreePage );
if(( iRc = ReadBlock( n->ulBlockNo, GetBlockSize(), n->cpBlockData )) != XB_NO_ERROR ){
iRc = 110;
@@ -409,7 +355,6 @@ xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt
// memset cpBlockData to zeroes
memset( n->cpBlockData, 0x00, GetBlockSize());
-
} else {
n->ulBlockNo = ulPageCnt / (xbUInt32) iBlockFactor;
ulPageCnt += (xbUInt32) iBlockFactor;
@@ -419,9 +364,6 @@ xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt
if( ulBlock2 > 0 ){
ePutUInt32( p, ulBlock2 );
}
-
- // std::cout << "AllocateIxNode incremented the block to " << ulPageCnt << "\n";
- // std::cout << "AllocateIxNode new block number = " << n->ulBlockNo << "\n";
}
catch( xbInt16 iRc ){
xbString sMsg;
@@ -431,9 +373,7 @@ xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt
if( n )
n = FreeNodeChain( n );
}
-
return n;
-
}
/***********************************************************************/
//! @brief Calculate B-tree pointers.
@@ -496,8 +436,6 @@ void xbIxMdx::CalcBtreePointers(){
xbString s;
xbMdxTag *mpTag = mdxTagTbl;
for( xbInt16 i = 0; i < iTagUseCnt; i++ ){
-// s.Sprintf( "tag = [%d] parent = [%d] left = [%d] right = [%d]\n", i, iaParent[i], iaLeftChild[i], iaRightChild[i]);
-// std::cout << s;
mpTag->cLeftChild = (char ) iaLeftChild[i];
mpTag->cRightChild = (char ) iaRightChild[i];
mpTag->cParent = (char ) iaParent[i];
@@ -597,9 +535,7 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
xbBool bLocked = xbFalse;
#endif
-
try{
-// xbase->WriteLogMessage( "xbIxMdx::CheckTagIntegrity()", iOpt );
#ifdef XB_LOCKING_SUPPORT
if( dbf->GetAutoLock() && !dbf->GetTableLocked() ){
@@ -612,7 +548,6 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
#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 );
@@ -716,10 +651,8 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
xbase->WriteLogMessage( sMsg, iOpt );
}
-
if( pPrevKeyBuf )
free( pPrevKeyBuf );
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -734,7 +667,6 @@ xbInt16 xbIxMdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
xbase->WriteLogMessage( sMsg, iOpt );
}
}
-
#ifdef XB_LOCKING_SUPPORT
if( bLocked ){
dbf->LockTable( XB_UNLOCK );
@@ -795,7 +727,6 @@ xbInt16 xbIxMdx::Close(){
return iRc;
}
-
/***********************************************************************/
//! @brief Create key.
/*!
@@ -830,9 +761,6 @@ xbInt16 xbIxMdx::CreateKey( void *vpTag, xbInt16 iOpt ){
xbMdxTag *npTag = (xbMdxTag *) vpTag;
npTag->iKeySts = 0;
- // char *p0 = dbf->GetRecordBuf(0);
- // char *p1 = dbf->GetRecordBuf(1);
-
// do tag filter logic
if( npTag->cHasFilter ){
if(( iRc = npTag->filter->ProcessExpression( 0 )) != XB_NO_ERROR ){
@@ -843,8 +771,6 @@ xbInt16 xbIxMdx::CreateKey( void *vpTag, xbInt16 iOpt ){
iErrorStop = 110;
throw iRc;
}
- // std::cout << "cp1 f0 = " << bFilter0 << "\n";
- // printf( "del byte 0 [%x] 1 [%x]\n", *p0, *p1 );
} else {
bFilter0 = xbTrue;
}
@@ -922,10 +848,6 @@ xbInt16 xbIxMdx::CreateKey( void *vpTag, xbInt16 iOpt ){
npTag->iKeySts = XB_ADD_KEY;
}
}
-
-// std::cout << "xbIxMdx::CreateKey key sts = " << npTag->iKeySts << " iOpt = " << iOpt << " type = " << npTag->exp->GetReturnType() << " name = " << npTag->cTagName;
-// std::cout << " f0 = " << bFilter0 << " f1 = " << bFilter1 << "\n";
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -933,16 +855,15 @@ xbInt16 xbIxMdx::CreateKey( void *vpTag, xbInt16 iOpt ){
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
}
-
return iRc;
}
-
/***********************************************************************/
//! @brief Create new tag.
/*!
This routine creates a new tag. When complete, sets the cur tag pointer to
the newly created tag.
+
\param sName Tag Name, including .MDX suffix
\param sKey Key Expression
\param sFilter Filter expression.
@@ -960,11 +881,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
xbInt16 iErrorStop = 0;
xbMdxTag *tte = NULL;
-
- // std::cout << "CreateTag() name=[" << sName.Str() << "] key=[" << sKey.Str() << "] sFilter=[" << sFilter.Str() << "]\n";
- // std::cout << "TagUseCnt = " << iTagUseCnt << std::endl;
-
-
try{
// verify room for new tag
if( !( iTagUseCnt < 47 )){
@@ -1016,8 +932,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
throw iRc;
}
- // tte->filter->DumpTree( 1 );
-
if((tte->filter->GetReturnType()) != 'L' ){
iRc = XB_INVALID_TAG;
iErrorStop = 160;
@@ -1042,7 +956,7 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
}
xbDate d;
-
+ d.Sysdate();
if( iTagUseCnt == 0 ){
// first tag, new mdx file
// create the file name
@@ -1132,11 +1046,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
tte->cpKeyBuf = (char *) malloc( (size_t) tte->iKeyLen + 1 );
tte->cpKeyBuf2 = (char *) malloc( (size_t) tte->iKeyLen + 1 );
-// if( 0 ){
-// printf( "ulTagHdrPageNo=[%d] cTagName=[%-11s], cLeftChild=[%d] cRightChild=[%d] cParent=[%d] cKeyType=[%c]\n\n",
-// tte->ulTagHdrPageNo, tte->cTagName, tte->cLeftChild, tte->cRightChild, tte->cParent, tte->cKeyType );
-// }
-
// write the new tte entry here
char tteBuf[21];
memset( tteBuf, 0x00, 21 );
@@ -1158,7 +1067,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
throw iRc;
}
-
// Begin Tag Header
tte->ulRootPage = ulPageCnt;
tte->ulTagSize = (xbUInt32) iBlockFactor;
@@ -1185,15 +1093,8 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
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 );
-// printf( "iSecKeyType=[%d] iKeyItemLen=[%d] cUnique=[%d] \n", tte->iSecKeyType, tte->iKeyItemLen, tte->cUnique );
-
char *pBuf;
if(( pBuf = (char *) calloc( 1, (size_t) GetBlockSize())) == NULL ){
iErrorStop = 230;
@@ -1280,7 +1181,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
iTagUseCnt++;
cNextTag++;
-
if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
iErrorStop = 270;
throw iRc;
@@ -1350,9 +1250,6 @@ xbInt16 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const
tteWork = tteWork->next;
}
free( pBuf );
-
-// xbIx::SetCurTag( ( void *) tte );
-
}
catch (xbInt16 iRc ){
@@ -1447,13 +1344,6 @@ xbInt16 xbIxMdx::DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo
throw iRc;
}
- // do any empty node processing here
-// if( bReuseEmptyNodes ){
-// if( bLeaf && lKeyCnt == 1 ){
-// std::cout << "Empty node ready for reuse\n";
-// }
-// }
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -1486,8 +1376,6 @@ xbInt16 xbIxMdx::DeleteKey( void *vpTag ){
npTag->npNodeChain = NULL;
xbIxNode * npSaveCurNode = npTag->npCurNode;
- // std::cout << "xbIxMdx::DeleteKey()\n";
-
try{
xbString sMsg;
@@ -1502,7 +1390,6 @@ xbInt16 xbIxMdx::DeleteKey( void *vpTag ){
// as prev key, ascend tree looking for an interior node needing
// updated key value
-
xbInt32 lOrigKeyCnt = GetKeyCount( npTag->npCurNode );
if(( iRc = DeleteFromNode( npTag, npTag->npCurNode, npTag->npCurNode->iCurKeyNo )) != XB_NO_ERROR ){
iErrorStop = 110;
@@ -1591,7 +1478,7 @@ xbInt16 xbIxMdx::DeleteKey( void *vpTag ){
}
/***********************************************************************/
-//! @brief Dump a given block for a tag
+//! @brief Delete a given tag
/*!
\param vpTag Input tag ptr for tag to be deleted<br>
\returns <a href="xbretcod_8h.html">Return Codes</a><br>
@@ -2100,8 +1987,6 @@ xbInt16 xbIxMdx::DumpHeader( xbInt16 iOpt, xbInt16 iFmtOpt )
if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR )
return iRc;
-// std::cout << "xbIxMdx::DumpHeader options - " << iDestOpt << " fmtopt = " << iFmtOpt << "\n";
-
char c, tfv, cDisplayMask = 1;
cDisplayMask = cDisplayMask << 7;
if( iFmtOpt != 2 && iFmtOpt != 4 ){
@@ -2116,9 +2001,6 @@ xbInt16 xbIxMdx::DumpHeader( xbInt16 iOpt, xbInt16 iFmtOpt )
}
xbase->WriteLogMessage( s, iOpt );
-
-// std::cout << std::endl;
-// std::cout <<
s.Sprintf( "Create Date = %d/%d/%d", (int) cCreateMM, (int) cCreateDD, (int) cCreateYY % 100 );
xbase->WriteLogMessage( s, iOpt );
@@ -2724,9 +2606,6 @@ xbInt16 xbIxMdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw = 0 ){
throw iRc;
}
}
- // else {
- // throw iRc;
- // }
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -2766,23 +2645,16 @@ xbString &xbIxMdx::GetKeyFilter( const void * vpTag ) const{
xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- // std::cout << "GetKeyFilter() ";
if( mpTag->sFiltExp )
return *mpTag->sFiltExp;
-// std::cout << " not null\n";
else
return sNullString;
- // std::cout << " null\n";
-
-// next line causes seg faults
-// return *mpTag->sFiltExp;
}
/**************************************************************************************************/
xbInt16 xbIxMdx::GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *np, xbUInt32 &ulKeyPtr ) const {
xbInt16 iRc = XB_NO_ERROR;
-
xbInt16 iErrorStop = 0;
try{
@@ -3339,15 +3211,9 @@ xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iO
try{
-// std::cout << "xbIxMdx::HarvestEmptyNode() page= " << BlockToPage( npNode->ulBlockNo );
-// std::cout << " block = " << npNode->ulBlockNo << "\n";
-
if( mpTag->ulRootPage == BlockToPage( npNode->ulBlockNo ) && !bHarvestRoot ){
bRootPage = xbTrue;
-
-// std::cout << "special root page processing *****************\n";
}
-
memset( npNode->cpBlockData, 0x00, GetBlockSize());
char *pTrg = npNode->cpBlockData;
@@ -3356,7 +3222,6 @@ xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iO
ePutUInt32( pTrg, ulFirstFreePage );
}
-
if( bRootPage ){
if( mpTag->cHasKeys ){
@@ -3374,7 +3239,6 @@ xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iO
// might need to update left sibling and right sibling here.
// Fields don't seem to be updated consistently by other xbase tools,
// for now, not updating
-
}
} else {
@@ -3393,7 +3257,6 @@ xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iO
iErrorStop = 130;
throw iRc;
}
-
}
if( iOpt == 1 ){
@@ -3418,8 +3281,6 @@ xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iO
return iRc;
}
-
-
/***********************************************************************/
//! @brief Harvest Tag Nodes.
/*!
@@ -3523,9 +3384,7 @@ xbInt16 xbIxMdx::InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xb
xbInt16 iCopyLen;
xbInt16 iNewKeyPos = 8;
-
try{
-
xbInt32 lKeyCnt = GetKeyCount( npNode );
iNewKeyPos += (iSlotNo * npTag->iKeyItemLen);
char *pSrc = npNode->cpBlockData;
@@ -3642,12 +3501,6 @@ xbInt16 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, ch
try{
xbInt32 lKeyCnt = GetKeyCount( npNode );
-
-// std::cout << "InsertNodeL Keycount = " << lKeyCnt << "\n";
-// next line is correct, this aligns with db7
-// "4" is the four byte record number stored to the left of the key
-// xbInt16 iKeyPos = 4 + iSlotNo * npTag->iKeyItemLen;
-
iNewKeyPos += (iSlotNo * npTag->iKeyItemLen);
// length of number of keys that need to be moved to the right
@@ -3657,24 +3510,18 @@ xbInt16 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, ch
iCopyLen = 0;
// +8 is to include the first two 4 byte fields in the block
- // xbUInt32 ulRqdBufSize = (xbUInt32) (iKeyPos + (npTag->iKeyItemLen * 2) + iCopyLen + 8);
xbUInt32 ulRqdBufSize = (xbUInt32) ((lKeyCnt + 1) * npTag->iKeyItemLen) + 8;
-/*
- std::cout << "InsertNodeL CopyLen = " << iCopyLen << "\n";
- std::cout << "InsertNodeL iNewKeyPos = " << iNewKeyPos << "\n";
- std::cout << "InsertNodeL SlotNo = " << iSlotNo << "\n";
- std::cout << "InsertNodeL lKeyCnt = " << lKeyCnt << "\n";
- std::cout << "InsertNodeL node buf size = " << npNode->ulBufSize << "\n";
- std::cout << "InsertNodeL key item len = " << npTag->iKeyItemLen << "\n";
- std::cout << "InsertNodeL key len = " << npTag->iKeyLen << "\n";
- std::cout << "required buf size = " << ulRqdBufSize << "\n";
- std::cout << "InsertNodeL key buf strlen = " << strlen( npTag->cpKeyBuf ) << "\n";
-*/
-
if( ulRqdBufSize > npNode->ulBufSize ){
+
npNode->ulBufSize += (xbUInt32) npTag->iKeyItemLen;
npNode->cpBlockData = (char *) realloc( npNode->cpBlockData, (size_t) npNode->ulBufSize );
+
+ // init the newly acquired buffer space
+ char *p = npNode->cpBlockData;
+ p += (npNode->ulBufSize - (xbUInt32) npTag->iKeyItemLen);
+ memset( p, 0x00, (size_t) npTag->iKeyItemLen );
+
if( !npNode->cpBlockData ){
iErrorStop = 100;
iRc = XB_NO_MEMORY;
@@ -3688,10 +3535,6 @@ xbInt16 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, ch
pNewKeyPos += iNewKeyPos;
if( iSlotNo < lKeyCnt ) {
- // pKeyPos = npNode->cpBlockData;
- // pKeyPos += iKeyPos;
- // pKeyPos += iNewKeyPos;
- // pTrg = pKeyPos;
pTrg = pNewKeyPos;
pTrg += npTag->iKeyItemLen;
memmove( pTrg, pNewKeyPos, (size_t) iCopyLen );
@@ -3710,14 +3553,11 @@ xbInt16 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, ch
// update number of keys on the node
ePutInt32( npNode->cpBlockData, ++lKeyCnt );
-// std::cout << "lKeyCntA = " << GetKeyCount( npNode ) << "\n";
-
// determine length of node, zap everything to the right of it
xbUInt32 iStartPos = 8 + ((xbUInt32) lKeyCnt * (xbUInt32) npTag->iKeyItemLen );
xbUInt32 iClearLen = npNode->ulBufSize - iStartPos;
-// std::cout << "InsertNodeL SP = " << iStartPos << " clear len = " << iClearLen << " ulBufsize = " << npNode->ulBufSize << "\n";
char *p = npNode->cpBlockData;
p += iStartPos;
memset( p, 0x00, iClearLen );
@@ -3727,10 +3567,6 @@ xbInt16 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, ch
iErrorStop = 100;
throw iRc;
}
-
-// std::cout << "lKeyCntB = " << GetKeyCount( npNode ) << "\n";
-
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -3754,8 +3590,6 @@ inline xbBool xbIxMdx::IsLeaf( void *vpTag, xbIxNode *npNode ) const{
p+=8;
p+= mTag->iKeyItemLen * lNoOfKeys;
- // printf( "IsLeaf p = [%d] b1 = [%x] keylen = [%d]\n", eGetUInt32( p ), *p, mTag->iKeyItemLen );
-
if( eGetUInt32( p ) == 0 ){
// std::cout << "leaf node\n";
return true;
@@ -3773,8 +3607,6 @@ xbInt16 xbIxMdx::KeyExists( void * vpTag )
xbMdxTag *mpTag = (xbMdxTag *) vpTag;
xbInt16 iRc = FindKey( vpTag, mpTag->cpKeyBuf, mpTag->iKeyLen, 0 );
- // iRc == 0 ? return 1 : return 0;
-
if( iRc == 0 )
return 1;
else
@@ -3940,8 +3772,6 @@ xbInt16 xbIxMdx::LoadTagDetail( xbInt16 iOption, xbMdxTag *tte ){
// option 1 - Load the entire tag detail
// option 2 - Load the dynamic variables only
- // std::cout << "LoadTagDetail() iOption = " << iOption << "\n";
-
xbInt16 iRc = XB_NO_ERROR;
xbInt16 iErrorStop = 0;
size_t iReadSize;
@@ -4020,10 +3850,6 @@ xbInt16 xbIxMdx::LoadTagDetail( xbInt16 iOption, xbMdxTag *tte ){
p+=221;
tte->cKeyFmt3 = *p;
-//for( int i = 0; i < 5; i++ )
-// printf( "%d [%x]\n", i, *p++ );
-// p+=2;
-
if( tte->cHasFilter ){
p+=282;
tte->sFiltExp = new xbString();
@@ -4135,7 +3961,6 @@ xbInt16 xbIxMdx::LoadTagTable()
ttel->next = tte;
else
mdxTagTbl = tte;
- // tte->sKeyExp = new xbString();
ttel = tte;
tte->next = NULL;
@@ -4268,13 +4093,9 @@ xbInt16 xbIxMdx::PrintKey( void *vpTag, xbIxNode *npNode, xbInt16 iKeyNo, xbInt1
xbInt16 xbIxMdx::ReadHeadBlock( xbInt16 iOpt )
{
-
-
xbInt16 iRc = XB_NO_ERROR;
xbInt16 iErrorStop = 0;
-// std::cout << "ReadHeadBlock() option = " << iOpt << "\n";
-
try{
if( !FileIsOpen()){
iRc = XB_NOT_OPEN;
@@ -4367,8 +4188,6 @@ xbInt16 xbIxMdx::ReadHeadBlock( xbInt16 iOpt )
cUpdateMM = *p++;
cUpdateDD = *p;
}
-
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -4425,7 +4244,7 @@ xbInt16 xbIxMdx::Reindex( void **vpTag ){
iErrorStop = 100;
throw iRc;
}
- bLocked = xbTrue;
+ bLocked = xbTrue;
}
#endif
@@ -4476,13 +4295,6 @@ xbInt16 xbIxMdx::Reindex( void **vpTag ){
// create new file & add the tags
while( p ){
- //std::cout << "Reindex() linked list extract\n";
- //std::cout << "Tag Name = [" << p->sTagName << "]\n";
- //std::cout << "Key Exp = [" << p->sKeyExp->Str() << "]\n";
- //std::cout << "Filt Exp = [" << p->sFiltExp->Str() << "]\n";
- //std::cout << "bDesc = [" << p->bDesc << "]\n";
- //std::cout << "bUnique = [" << p->bUnique << "]\n";
-
if(( iRc = CreateTag( p->sTagName, p->sKeyExp->Str(), p->sFiltExp->Str(), p->bDesc, p->bUnique, xbTrue, vpTag )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
@@ -4550,6 +4362,7 @@ xbInt16 xbIxMdx::Reindex( void **vpTag ){
sMsg.Sprintf( "xbIxMdx::ReIndex() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ this->DeleteTag( mpTag );
}
#ifdef XB_LOCKING_SUPPORT
@@ -4594,39 +4407,6 @@ void xbIxMdx::SetReuseEmptyNodesSw( xbBool bEmptyNodesSw ) {
}
/***********************************************************************/
-//! @brief Set Tag Pointer.
-/*!
- Set binary tree pointer value. The MDX tags are stored with binary
- tree positions. This routine sets the value in memory.
- \param cPtr L - Left child.<br>
- R - Right child.<br>
- P - Parent.
- \param iWhich - Which tag to update
- \param cVal - Value to set.
- \returns void
-*/
-
-/*
-void xbIxMdx::SetTagPtr( char cPtr, xbInt16 iWhich, char cVal ){
-
- xbMdxTag *mpTag = (xbMdxTag *) GetTag( iWhich );
- if( mpTag ){
- switch( cPtr ){
- case 'L':
- mpTag->cLeftChild = cVal;
- break;
- case 'R':
- mpTag->cRightChild = cVal;
- break;
- case 'P':
- mpTag->cParent = cVal;
- break;
- }
- }
-}
-*/
-
-/***********************************************************************/
//! @brief Split an interior node
/*!
@@ -4662,7 +4442,6 @@ xbInt16 xbIxMdx::SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
char *pSrc;
char *pTrg;
-
try{
xbInt32 lKeyCnt = GetKeyCount( npLeft );
xbInt32 lNewLeftKeyCnt = (xbInt32) ((lKeyCnt + 1) * dSplitFactor);
@@ -4816,11 +4595,8 @@ xbInt16 xbIxMdx::TagSerialNo( xbInt16 iOption, xbMdxTag * mpTag ){
xbInt16 iErrorStop = 0;
try{
-
xbInt64 lPos = (mpTag->ulTagHdrPageNo * 512) + 20;
-// std::cout << "UpdateSerialNo offset = " << lPos << " option = " << iOption << "\n";
-
if( iOption != 2 ){
if(( iRc = xbFseek( lPos, SEEK_SET )) != XB_NO_ERROR ){
iErrorStop = 100;
@@ -4845,7 +4621,6 @@ xbInt16 xbIxMdx::TagSerialNo( xbInt16 iOption, xbMdxTag * mpTag ){
throw iRc;
}
}
-
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -4856,7 +4631,6 @@ xbInt16 xbIxMdx::TagSerialNo( xbInt16 iOption, xbMdxTag * mpTag ){
return iRc;
}
-
/***********************************************************************/
//! @brief UpdateTagKey
/*!
@@ -4881,9 +4655,6 @@ xbInt16 xbIxMdx::UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo ){
try{
// save off any needed fields for updating
xbUInt32 ulTagSizeSave = npTag->ulTagSize;
- // std::cout << "old size = " << ulTagSizeSave << " new size = " << npTag->ulTagSize << "\n";
- //std::cout << "UpdateTagKey - tag size was updated need to do something here - test \n";
-
if( cAction == 'D' || cAction == 'R' ){
// std::cout << "UpdateTagKey-delete going to DeleteKey \n";
@@ -4891,7 +4662,6 @@ xbInt16 xbIxMdx::UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo ){
iErrorStop = 100;
throw iRc;
}
- //std::cout << "UpdateTagKey-delete back from DeleteKey \n";
}
if( cAction == 'A' || cAction == 'R' ){
@@ -4941,7 +4711,8 @@ xbInt16 xbIxMdx::WriteHeadBlock( xbInt16 iOption ){
xbInt16 iErrorStop = 0;
try{
- xbDate d; // default is system date, today
+ xbDate d;
+ d.Sysdate(); // set to system date, today
cUpdateYY = (char) d.YearOf() - 1900;
cUpdateMM = (char) d.MonthOf();
cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
diff --git a/src/core/xbixndx.cpp b/src/core/xbixndx.cpp
index 9d946dd..b28dd9d 100755
--- a/src/core/xbixndx.cpp
+++ b/src/core/xbixndx.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.
@@ -309,8 +309,8 @@ xbInt16 xbIxNdx::CheckForDupKey( void *vpTag )
\param vpTag Tag to create key for.
\param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
+ 0 = Syslog<br>
+ 1 = Stdout<br>
2 = Both<br>
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
@@ -609,7 +609,8 @@ xbInt16 xbIxNdx::CreateTag( const xbString &sName, const xbString &sKey,
npTag->iUnique = iUnique;
npTag->ulRootBlock = 1L;
- npTag->ulTotalBlocks = 2l;
+ //npTag->ulTotalBlocks = 2l;
+ npTag->ulTotalBlocks = 2L;
npTag->sKeyExpression = sKey;
GetFileNamePart( npTag->sTagName );
@@ -2426,62 +2427,75 @@ xbInt16 xbIxNdx::Reindex( void **vpTag ){
xbInt16 iRc = XB_NO_ERROR;
xbInt16 iErrorStop = 0;
- //xbNdxTag * npTag;
- //vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
+ xbNdxTag *npTag = ndxTag;
try{
- xbString sFileName = GetFqFileName();
- xbString sKey; // = GetKeyExpression( vpTag );
- sKey.Set( GetKeyExpression( *vpTag ));
xbInt16 iUnique = GetUnique( *vpTag );
- xbString sFilter = "";
- void *vpTag2;
- if(( iRc = CreateTag( sFileName, sKey, sFilter, 0, iUnique, xbTrue, &vpTag2 )) != XB_NO_ERROR ){
+ npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
+ npTag->npCurNode = NULL;
+ npTag->ulRootBlock = 1L;
+ npTag->ulTotalBlocks = 2L;
+
+ if(( iRc = xbTruncate( 1024 )) != XB_NO_ERROR ){
iErrorStop = 100;
throw iRc;
}
+ if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ char buf[512];
+ memset( buf, 0x00, 512 );
+
+ if(( iRc = WriteBlock( 1, 0, buf )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+
xbUInt32 ulRecCnt = 0;
if(( iRc = dbf->GetRecordCnt( ulRecCnt )) != XB_NO_ERROR ){
- iErrorStop = 110;
+ iErrorStop = 130;
throw iRc;
}
for( xbUInt32 l = 1; l <= ulRecCnt; l++ ){
if(( iRc = dbf->GetRecord( l )) != XB_NO_ERROR ){
- iErrorStop = 120;
+ iErrorStop = 140;
throw iRc;
}
- if(( iRc = CreateKey( vpTag2, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
+ if(( iRc = CreateKey( npTag, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 150;
throw iRc;
}
if( iUnique ){
- iRc = CheckForDupKey( vpTag2 );
+ // iRc = CheckForDupKey( vpTag2 );
+ iRc = CheckForDupKey( npTag );
if( iRc != 0 ){
if( iRc < 0 ){
- iErrorStop = 140;
+ iErrorStop = 160;
throw iRc;
}
return XB_KEY_NOT_UNIQUE;
}
}
- if(( iRc = AddKey( vpTag2, l )) != XB_NO_ERROR ){
+ if(( iRc = AddKey( npTag, l )) != XB_NO_ERROR ){
iErrorStop = 150;
throw iRc;
}
}
- *vpTag = vpTag2;
+ *vpTag = npTag;
}
catch (xbInt16 iRc ){
xbString sMsg;
sMsg.Sprintf( "xbIxNdx::Reindex() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ this->DeleteTag( NULL ); // Don't leave the index in an incomplete state
}
return iRc;
}
diff --git a/src/core/xbixtdx.cpp b/src/core/xbixtdx.cpp
new file mode 100755
index 0000000..4137725
--- /dev/null
+++ b/src/core/xbixtdx.cpp
@@ -0,0 +1,661 @@
+/* xbixtdx.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 temporary index logic
+
+*/
+
+#include "xbase.h"
+
+
+
+#ifdef XB_TDX_SUPPORT
+
+
+namespace xb{
+
+/************************************************************************/
+xbIxTdx::xbIxTdx( xbDbf *dbf ) : xbIxMdx( dbf ) {
+//xbIxMdx::xbIxMdx( xbDbf *dbf ) : xbIx( dbf ){
+
+// std::cout << "xbIxTdx::Constructor()\n";
+
+ // Init(); not needed, called in xbMdx
+
+
+}
+
+/************************************************************************/
+xbIxTdx::~xbIxTdx() {
+
+// std::cout << "xbIxTdx::Destructor()\n";
+
+}
+
+/***********************************************************************/
+xbInt16 xbIxTdx::Close(){
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+
+std::cout << "xbIxTdx::Close\n";
+
+ try{
+ if(( iRc = xbIxMdx::Close()) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ if(( iRc = xbRemove()) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIxTdx::Close() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+//! @brief Create new tag.
+/*!
+ This routine creates a new tag. When complete, sets the cur tag pointer to
+ the newly created tag.
+
+
+ \param sName Tag Name, including .MDX suffix
+ \param sKey Key Expression
+ \param sFilter Filter expression.
+ \param iDescending
+ \param iUnique xbtrue - Unique.<br>xbFalse - Not unique.
+ \param iOverLay xbTrue - Overlay if file already exists.<br>xbFalse - Don't overlay.
+ \param vpTag Output from method Pointer to vptag pointer.
+ \returns <a href="xbretcod_8h.html">Return Codes</a>
+*/
+
+
+xbInt16 xbIxTdx::CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag ){
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbInt16 iErrorStop = 0;
+ xbMdxTag *tte = NULL;
+
+ std::cout << "xbIxTdx::CreateTag()\n";
+
+
+ // std::cout << "CreateTag() name=[" << sName.Str() << "] key=[" << sKey.Str() << "] sFilter=[" << sFilter.Str() << "]\n";
+ // std::cout << "TagUseCnt = " << iTagUseCnt << std::endl;
+
+
+ try{
+ // verify room for new tag
+ if( !( iTagUseCnt < 47 )){
+ iErrorStop = 100;
+ iRc = XB_LIMIT_REACHED;
+ throw iRc;
+ }
+
+ // verify valid tag name
+ xbString sWorker = sName;
+ sWorker.Trim();
+ if( sWorker.Len() > 10 ){
+ iErrorStop = 110;
+ iRc = XB_INVALID_TAG;
+ throw iRc;
+ }
+
+ // verify tag not already defined
+ if( iTagUseCnt > 0 ){
+ if( GetTag( sWorker )){
+ iErrorStop = 120;
+ iRc = XB_INVALID_TAG;
+ throw iRc;
+ }
+ }
+
+ // allocate a tag structure here
+ if(( tte = (xbMdxTag *) calloc( 1, (size_t) sizeof( xbMdxTag ))) == NULL ){
+ iErrorStop = 130;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+ *vpTag = tte;
+ tte->sTagName = new xbString( sWorker );
+
+ //set up the key expression
+ sWorker = sFilter;
+ sWorker.Trim();
+ if( sWorker.Len() > 0 ){
+ if( sWorker.Len() == 0 || sWorker.Len() > 220 ){
+ iRc = XB_INVALID_TAG;
+ iErrorStop = 140;
+ throw iRc;
+ }
+ tte->sFiltExp = new xbString( sWorker );
+ tte->filter = new xbExp( dbf->GetXbasePtr());
+ if(( iRc = tte->filter->ParseExpression( dbf, sWorker )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+
+ // tte->filter->DumpTree( 1 );
+
+ if((tte->filter->GetReturnType()) != 'L' ){
+ iRc = XB_INVALID_TAG;
+ iErrorStop = 160;
+ throw iRc;
+ }
+ tte->cHasFilter = 0x01;
+ }
+
+ //set up the key expression
+ sWorker = sKey;
+ sWorker.Trim();
+ if( sWorker.Len() == 0 || sWorker.Len() > 100 ){
+ iRc = XB_INVALID_TAG;
+ iErrorStop = 170;
+ throw iRc;
+ }
+ tte->sKeyExp = new xbString( sWorker );
+ tte->exp = new xbExp( dbf->GetXbasePtr());
+ if(( iRc = tte->exp->ParseExpression( dbf, sWorker )) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc;
+ }
+
+ xbDate d;
+ d.Sysdate();
+ if( iTagUseCnt == 0 ){
+ // first tag, new mdx file
+ // create the file name
+
+ // create temp file
+ xbString sIxFileName;
+ if(( iRc = CreateUniqueFileName( GetTempDirectory(), "TDX", sIxFileName )) != XB_NO_ERROR ){
+ iErrorStop = 190;
+ throw iRc;
+ }
+
+ // copy the file name to the class variable
+ this->SetFileName( sIxFileName );
+ if( FileExists() && !iOverlay ){
+ iErrorStop = 200;
+ iRc = XB_FILE_EXISTS;
+ throw iRc;
+ }
+
+ // first tag, need to create the file
+ if(( iRc = xbFopen( "w+b", dbf->GetShareMode())) != XB_NO_ERROR ){
+ iErrorStop = 210;
+ throw iRc;
+ }
+ cVersion = 2;
+ cCreateYY = (char) d.YearOf() - 1900;
+ cCreateMM = (char) d.MonthOf();
+ cCreateDD = (char) d.DayOf( XB_FMT_MONTH );
+
+ GetFileNamePart( sFileName );
+ sFileName.ToUpperCase();
+
+ SetBlockSize( (xbUInt32) dbf->GetCreateMdxBlockSize());
+ iBlockFactor = GetBlockSize() / 512;
+
+ cProdIxFlag = 0; // MDX is 1
+ cTagEntryCnt = 48;
+ iTagLen = 32;
+ ulPageCnt = 4;
+ ulFirstFreePage = 0;
+ ulNoOfBlockAvail = 0;
+ cNextTag = 1;
+ c1B = 0x1B;
+ cUpdateYY = cCreateYY;
+ cUpdateMM = cCreateMM;
+ cUpdateDD = cCreateDD;
+
+ if(( iRc = WriteHeadBlock( 0 )) != XB_NO_ERROR ){
+ iErrorStop = 220;
+ throw iRc;
+ }
+ }
+
+ // populate the tag table entry structure
+ tte->ulTagHdrPageNo = ulPageCnt;
+ ulPageCnt += (xbUInt32) iBlockFactor;
+ tte->sTagName->strncpy( tte->cTagName, 10 );
+
+ // cKeyFmt is always 0x10;
+ // tested 2+ZIPCD CITY+STATE or just standalone field - always 0x10
+ tte->cKeyFmt = 0x10; // = CalcTagKeyFmt( *tte->exp );
+
+ switch( tte->exp->GetReturnType()){
+ case XB_EXP_CHAR:
+ tte->cKeyType = 'C';
+ tte->iKeyLen = tte->exp->GetResultLen();
+ tte->iSecKeyType = 0;
+ break;
+
+ case XB_EXP_NUMERIC:
+ tte->cKeyType = 'N';
+ tte->iKeyLen = 12;
+ tte->iSecKeyType = 0;
+ break;
+
+ case XB_EXP_DATE:
+ tte->cKeyType = 'D';
+ tte->iKeyLen = 8;
+ tte->iSecKeyType = 1;
+ break;
+
+ default:
+ iErrorStop = 200;
+ iRc = XB_INVALID_INDEX;
+ throw iRc;
+ }
+
+ tte->cpKeyBuf = (char *) malloc( (size_t) tte->iKeyLen + 1 );
+ tte->cpKeyBuf2 = (char *) malloc( (size_t) tte->iKeyLen + 1 );
+
+// if( 0 ){
+// printf( "ulTagHdrPageNo=[%d] cTagName=[%-11s], cLeftChild=[%d] cRightChild=[%d] cParent=[%d] cKeyType=[%c]\n\n",
+// tte->ulTagHdrPageNo, tte->cTagName, tte->cLeftChild, tte->cRightChild, tte->cParent, tte->cKeyType );
+// }
+
+ // write the new tte entry here
+ char tteBuf[21];
+ memset( tteBuf, 0x00, 21 );
+
+ ePutUInt32( &tteBuf[0], tte->ulTagHdrPageNo );
+ for( xbUInt32 l = 0; l < tte->sTagName->Len() && l < 10; l++ ){
+ tteBuf[l+4] = tte->sTagName->GetCharacter(l+1);
+ }
+ tteBuf[15] = tte->cKeyFmt;
+ tteBuf[19] = 0x02; // appears to always be a 0x02
+ tteBuf[20] = tte->cKeyType;
+
+ if(( iRc = xbFseek( (iTagUseCnt * 32) + 544, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 230;
+ throw iRc;
+ }
+ if(( iRc = xbFwrite( tteBuf, 21, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 240;
+ throw iRc;
+ }
+
+
+ // Begin Tag Header
+ tte->ulRootPage = ulPageCnt;
+ tte->ulTagSize = (xbUInt32) iBlockFactor;
+ ulPageCnt += 2;
+ tte->cKeyFmt2 = 0x10;
+ if( iDescending )
+ tte->cKeyFmt2 += 0x08;
+ if( iUnique ){
+ tte->cKeyFmt2 += 0x40;
+ tte->cUnique = 0x01;
+ }
+
+ tte->cTag11 = 0x1B; // always 0x1b ?
+ tte->cSerialNo = 0x01; // version incremented with each tag update
+ tte->ulLeftChild = tte->ulRootPage;
+ tte->ulRightChild = tte->ulRootPage;
+
+ tte->cTagYY = (char) d.YearOf() - 1900;
+ tte->cTagMM = (char) d.MonthOf();
+ tte->cTagDD = (char) d.DayOf( XB_FMT_MONTH );
+
+ 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 );
+// printf( "iSecKeyType=[%d] iKeyItemLen=[%d] cUnique=[%d] \n", tte->iSecKeyType, tte->iKeyItemLen, tte->cUnique );
+
+ char *pBuf;
+ if(( pBuf = (char *) calloc( 1, (size_t) GetBlockSize())) == NULL ){
+ iErrorStop = 230;
+ iRc = XB_NO_MEMORY;
+ throw iRc;
+ }
+ char *wPtr;
+ wPtr = pBuf;
+ ePutUInt32( wPtr, tte->ulRootPage );
+
+ wPtr += 4;
+ ePutUInt32( wPtr, tte->ulTagSize );
+
+ wPtr += 4;
+ *wPtr = tte->cKeyFmt2;
+
+ wPtr++;
+ *wPtr = tte->cKeyType2;
+
+ wPtr += 2;
+ *wPtr = tte->cTag11;
+
+ wPtr += 1;
+ ePutInt16( wPtr, tte->iKeyLen );
+
+ wPtr += 2;
+ ePutInt16( wPtr, tte->iKeysPerBlock );
+
+ wPtr += 2;
+ ePutInt16( wPtr, tte->iSecKeyType );
+
+ wPtr += 2;
+ ePutInt16( wPtr, tte->iKeyItemLen );
+
+ wPtr += 2;
+ *wPtr = tte->cSerialNo;
+
+ wPtr += 3;
+ *wPtr = tte->cUnique;
+
+ wPtr++;
+ for( xbUInt32 l = 0; l < tte->sKeyExp->Len(); l++ )
+ *wPtr++ = tte->sKeyExp->GetCharacter(l+1);
+
+ wPtr = pBuf;
+
+ tte->cHasKeys = 0x00;
+ pBuf[246] = tte->cHasKeys;
+
+ wPtr += 248;
+ ePutUInt32( wPtr, tte->ulLeftChild );
+ wPtr += 4;
+ ePutUInt32( wPtr, tte->ulRightChild );
+
+ pBuf[257] = tte->cTagYY;
+ pBuf[258] = tte->cTagMM;
+ pBuf[259] = tte->cTagDD;
+ pBuf[480] = tte->cKeyFmt3;
+
+ if( sFilter.Len() > 0 ){
+ pBuf[245] = tte->cHasFilter;
+ wPtr = pBuf;
+ wPtr += 762;
+ for( xbUInt32 l = 0; l < sFilter.Len(); l++ )
+ *wPtr++ = sFilter.GetCharacter(l+1);
+ }
+
+ if(( iRc = xbFseek( tte->ulTagHdrPageNo * 512, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 250;
+ throw iRc;
+ }
+
+ if(( iRc = xbFwrite( pBuf, GetBlockSize(), 1 )) != XB_NO_ERROR ){
+ iErrorStop = 260;
+ throw iRc;
+ }
+
+ memset( pBuf, 0x00, GetBlockSize() );
+ if(( iRc = xbFwrite( pBuf, GetBlockSize(), 1 )) != XB_NO_ERROR ){
+ iErrorStop = 270;
+ throw iRc;
+ }
+
+ iTagUseCnt++;
+ cNextTag++;
+
+
+ if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
+ iErrorStop = 280;
+ throw iRc;
+ }
+
+ // add the new entry to the end of the list of tags
+ if( mdxTagTbl == NULL ){
+ mdxTagTbl = tte;
+ } else {
+ xbMdxTag *tteL = mdxTagTbl;
+ while( tteL->next )
+ tteL = tteL->next;
+ tteL->next = tte;
+ }
+
+ /* update the btree pointers */
+ CalcBtreePointers();
+ char bBuf[3];
+ xbMdxTag *tteWork = mdxTagTbl;
+
+ if(( iRc = xbFseek( 560, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 290;
+ throw iRc;
+ }
+ while( tteWork ){
+ bBuf[0] = tteWork->cLeftChild;
+ bBuf[1] = tteWork->cRightChild;
+ bBuf[2] = tteWork->cParent;
+
+ if(( iRc = xbFwrite( bBuf, 3, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 300;
+ throw iRc;
+ }
+ if( tteWork->next ){
+ if(( iRc = xbFseek( 29, SEEK_CUR )) != XB_NO_ERROR ){
+ iErrorStop = 310;
+ throw iRc;
+ }
+ }
+ tteWork = tteWork->next;
+ }
+ free( pBuf );
+
+ }
+
+ catch (xbInt16 iRc ){
+ if( tte ){
+ if( tte->cpKeyBuf )
+ free( tte->cpKeyBuf );
+ if( tte->cpKeyBuf2 )
+ free( tte->cpKeyBuf2 );
+ if( tte->exp )
+ delete tte->exp;
+ if( tte->filter )
+ delete tte->filter;
+ if( tte->sKeyExp )
+ delete tte->sKeyExp;
+ if( tte->sFiltExp )
+ delete tte->sFiltExp;
+ if( tte->sTagName )
+ delete tte->sTagName;
+ free( tte );
+ }
+ xbString sMsg;
+ sMsg.Sprintf( "xbIxTdx::CreateTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+};
+
+/***********************************************************************/
+//! @brief Delete a given tag
+/*!
+ \param vpTag Input tag ptr for tag to be deleted<br>
+ \returns <a href="xbretcod_8h.html">Return Codes</a><br>
+ 1 = Deleted entire MDX file, only had one tag
+
+*/
+
+xbInt16 xbIxTdx::DeleteTag( void *vpTag ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbMdxTag * mpTag = (xbMdxTag *) vpTag;
+ xbIxNode *n = NULL;
+ xbBool bLoneTag = xbFalse;
+
+ try{
+
+ if( !vpTag ){
+ iErrorStop = 100;
+ iRc = XB_INVALID_TAG;
+ throw iRc;
+ }
+
+ // char cSaveHasFilter = mpTag->cHasFilter;
+ // char cSaveKeyFmt3 = mpTag->cKeyFmt3;
+ // xbString sSaveKey = mpTag->sKeyExp->Str();
+
+ if( iTagUseCnt == 1 ){
+ // std::cout << "xbIxTdx::DeleteTag - one tag found, delete the mdx file\n";
+
+ // close the mdx file
+ if(( iRc = xbIxMdx::Close()) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+
+ // delete the file
+ xbRemove();
+
+ // init variables - needed?
+ // Init();
+ // iRc > 0 defines this as the only tag in an MDX file, MDX file deleted.
+ // signals to the calling process to drop the MDX file from the
+ // list of updateable indices.
+ bLoneTag = xbTrue;
+
+ } else {
+
+ // harvest tag nodes
+
+ if(( iRc = HarvestTagNodes( mpTag, xbTrue )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+
+ // remove an entry from tag table
+ // which tag is this?
+ xbInt16 iTagNo = 0;
+ xbMdxTag *mp = mdxTagTbl;
+ xbMdxTag *mpPrev = NULL;
+ while( mp && mp->ulTagHdrPageNo != mpTag->ulTagHdrPageNo ){
+ iTagNo++;
+ mpPrev = mp;
+ mp = mp->next;
+ }
+
+ // remove it from the linked list of tags
+ if( !mpPrev ){
+ mdxTagTbl = mp->next;
+ } else {
+ mpPrev->next = mp->next;
+ }
+ if( mp ){
+ if( mp->cpKeyBuf ) free( mp->cpKeyBuf );
+ if( mp->cpKeyBuf2 ) free( mp->cpKeyBuf2 );
+ if( mp->exp ) delete mp->exp;
+ if( mp->filter ) delete mp->filter;
+ if( mp->sKeyExp ) delete mp->sKeyExp;
+ if( mp->sFiltExp ) delete mp->sFiltExp;
+ if( mp->sTagName ) delete mp->sTagName;
+ free( mp );
+ }
+ xbInt32 iTarg = iTagNo * 32;
+ xbInt32 iSrc = iTarg + 32;
+ xbInt32 iLen = (iTagUseCnt - iTagNo) * 32;
+
+ if(( iRc = xbFseek( 544, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ char Buf[1536]; // 47 tags + 1 in case tag #47 is deleted
+ memset( Buf, 0x00, 1536 );
+ if(( iRc = xbFread( Buf, 1504, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+ char *pTrg = Buf;
+ pTrg += iTarg;
+ char *pSrc = Buf;
+ pSrc += iSrc;
+ for( xbInt32 i = 0; i < iLen; i++ )
+ *pTrg++ = *pSrc++;
+
+ if(( iRc = xbFseek( 544, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc;
+ }
+ if(( iRc = xbFwrite( Buf, 1504, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 190;
+ throw iRc;
+ }
+
+ iTagUseCnt--;
+ if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
+ iErrorStop = 200;
+ throw iRc;
+ }
+
+ // update the btree pointers
+ CalcBtreePointers();
+ char bBuf[3];
+ xbMdxTag *tteWork = mdxTagTbl;
+
+ if(( iRc = xbFseek( 560, SEEK_SET )) != XB_NO_ERROR ){
+ iErrorStop = 210;
+ throw iRc;
+ }
+ while( tteWork ){
+ bBuf[0] = tteWork->cLeftChild;
+ bBuf[1] = tteWork->cRightChild;
+ bBuf[2] = tteWork->cParent;
+
+ if(( iRc = xbFwrite( bBuf, 3, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 320;
+ throw iRc;
+ }
+ if( tteWork->next ){
+ if(( iRc = xbFseek( 29, SEEK_CUR )) != XB_NO_ERROR ){
+ iErrorStop = 330;
+ throw iRc;
+ }
+ }
+ tteWork = tteWork->next;
+ }
+ }
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbIxTdx::DeleteTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ if( n )
+ free( n );
+ }
+ if( bLoneTag && !iRc )
+ return 1;
+ else
+ return iRc;
+}
+
+/************************************************************************/
+
+
+
+/************************************************************************/
+} /* namespace */
+#endif /* XB_TDX_SUPPORT */ \ No newline at end of file
diff --git a/src/core/xblog.cpp b/src/core/xblog.cpp
index 6031c9e..9443006 100755
--- a/src/core/xblog.cpp
+++ b/src/core/xblog.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.
@@ -25,11 +25,15 @@ namespace xb{
//! @brief Constructor.
xbLog::xbLog() : xbFile( NULL ){
+
+ // std::cout << "xbLog::xbLog(1) Directory = [" << GetLogDirectory() << "]\n";
+ // std::cout << "xbLog::xbLog(1) Name = [" << GetLogFileName() << "]\n";
+
SetDirectory( GetLogDirectory());
SetFileName ( GetLogFileName());
bLoggingStatus = xbFalse;
- lLogSize = 50000;
+ lLogSize = 100000;
#ifdef XB_LOCKING_SUPPORT
iShareMode = XB_MULTI_USER;
@@ -49,7 +53,7 @@ xbLog::xbLog( const xbString & sLogFileName ) : xbFile( NULL ){
SetFileName( sLogFileName ); // no file path
bLoggingStatus = xbFalse;
- lLogSize = 50000;
+ lLogSize = 100000;
#ifdef XB_LOCKING_SUPPORT
iShareMode = XB_MULTI_USER;
@@ -95,6 +99,8 @@ void xbLog::LogSetLogSize( size_t lSize ){
\returns void
*/
void xbLog::LogSetStatus( xbBool bStatus ){
+ if( bLoggingStatus && !bStatus )
+ LogClose();
bLoggingStatus = bStatus;
}
/******************************************************************************/
@@ -104,6 +110,19 @@ void xbLog::LogSetStatus( xbBool bStatus ){
*/
xbInt16 xbLog::LogOpen(){
xbInt16 rc;
+
+// std::cout << "*****\nxbLog::LogOpen(1) GetLogDirectory = " << GetLogDirectory() << "\n";
+// std::cout << "xbLog::LogOpen(1) GetLogFileName = " << GetLogFileName() << "\n";
+// std::cout << "xbLog::GetFqFileName(1) = " << GetFqFileName() << "\n\n";
+
+ // 4.1.3 added next two lines for dynamic log file name changing
+ SetDirectory( GetLogDirectory());
+ SetFileName ( GetLogFileName());
+
+// std::cout << "*****\nxbLog::LogOpen(2) GetLogDirectory = " << GetLogDirectory() << "\n";
+// std::cout << "xbLog::LogOpen(2) GetLogFileName = " << GetLogFileName() << "\n";
+// std::cout << "xbLog::GetFqFileName(2) = " << GetFqFileName() << "\n\n";
+
if(( rc = xbFopen( "a", iShareMode )) != XB_NO_ERROR )
return rc;
xbFTurnOffFileBuffering();
diff --git a/src/core/xbmemo.cpp b/src/core/xbmemo.cpp
index 2bde853..406a77d 100755
--- a/src/core/xbmemo.cpp
+++ b/src/core/xbmemo.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.
diff --git a/src/core/xbmemo3.cpp b/src/core/xbmemo3.cpp
index 60c1d53..767e9d2 100755
--- a/src/core/xbmemo3.cpp
+++ b/src/core/xbmemo3.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.
@@ -133,15 +133,18 @@ xbInt16 xbMemoDbt3::GetMemoField( xbInt16 iFieldNo, xbString & sMemoData ){
xbBool bDone = xbFalse;
sMemoData = "";
try{
+
if(( rc = dbf->GetULongField( iFieldNo, ulBlockNo )) < XB_NO_ERROR ){
iErrorStop = 100;
throw rc;
}
+
if( ulBlockNo == 0L ){
sMemoData = "";
return XB_NO_ERROR;
}
spp = NULL;
+
while( !bDone ){
if(( rc = ReadBlock( ulBlockNo++, GetBlockSize(), mbb )) != XB_NO_ERROR ){
iErrorStop = 120;
@@ -256,6 +259,7 @@ xbInt16 xbMemoDbt3::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
#endif
try{
+
#ifdef XB_LOCKING_SUPPORT
if( dbf->GetAutoLock() && !dbf->GetTableLocked() ){
if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
@@ -275,7 +279,8 @@ xbInt16 xbMemoDbt3::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
// create temp file
xbString sTempMemoName;
- if(( iRc = CreateUniqueFileName( GetDirectory(), "dbt", sTempMemoName )) != XB_NO_ERROR ){
+ //if(( iRc = CreateUniqueFileName( GetDirectory(), "dbt", sTempMemoName )) != XB_NO_ERROR ){
+ if(( iRc = CreateUniqueFileName( GetTempDirectory(), "DBT", sTempMemoName )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
}
@@ -297,7 +302,8 @@ xbInt16 xbMemoDbt3::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
xbString sMemoFldData;
for( xbUInt32 ulI = 1; ulI <= ulRecCnt; ulI++ ){
- if(( iRc = dbf->GetRecord( ulI )) != XB_NO_ERROR ){
+
+ if(( iRc = dbf->GetRecord( ulI )) != XB_NO_ERROR ){
iErrorStop = 150;
throw iRc;
}
@@ -310,6 +316,8 @@ xbInt16 xbMemoDbt3::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
iErrorStop = 160;
throw iRc;
}
+
+
if( cFldType == 'M' ){
// copy it to work field
if(( iRc = dbf->GetMemoField( lFc, sMemoFldData )) != XB_NO_ERROR ){
@@ -363,11 +371,13 @@ xbInt16 xbMemoDbt3::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
throw iRc;
}
}
+
//close and delete target
if(( iRc = pMemo->xbFclose()) != XB_NO_ERROR ){
iErrorStop = 250;
throw iRc;
}
+
if(( iRc = pMemo->xbRemove()) != XB_NO_ERROR ){
iErrorStop = 260;
throw iRc;
diff --git a/src/core/xbmemo4.cpp b/src/core/xbmemo4.cpp
index d02df99..9770806 100755
--- a/src/core/xbmemo4.cpp
+++ b/src/core/xbmemo4.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.
@@ -798,7 +798,8 @@ xbInt16 xbMemoDbt4::PackMemo( void (*memoStatusFunc ) ( xbUInt32 ulItemNum, xbUI
// create temp file
xbString sTempMemoName;
- if(( iRc = CreateUniqueFileName( GetDirectory(), "dbt", sTempMemoName )) != XB_NO_ERROR ){
+ //if(( iRc = CreateUniqueFileName( GetDirectory(), "dbt", sTempMemoName )) != XB_NO_ERROR ){
+ if(( iRc = CreateUniqueFileName( GetTempDirectory(), "DBT", sTempMemoName )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
}
diff --git a/src/core/xbssv.cpp b/src/core/xbssv.cpp
index d3e1070..532f942 100755
--- a/src/core/xbssv.cpp
+++ b/src/core/xbssv.cpp
@@ -21,6 +21,7 @@ const xbErrorMessage xbErrorMessages[] = {
{ XB_NO_ERROR, "No Error" },
{ XB_NO_MEMORY, "No Memory" },
{ XB_INVALID_OPTION, "Invalid Option" },
+ { XB_INVALID_PARAMETER, "Invalid Parameter" },
{ XB_DUP_TABLE_OR_ALIAS, "Duplicate Alias/Table Name" },
{ XB_INVALID_NODELINK, "Invalid Node Link" },
{ XB_KEY_NOT_UNIQUE, "Key Not Unique" },
@@ -77,7 +78,6 @@ const xbErrorMessage xbErrorMessages[] = {
};
// see also xbretcod.h
-
xbInt16 xbSsv::iEndianType = 0;
xbString xbSsv::sDefaultDateFormat = "MM/DD/YY";
@@ -85,17 +85,12 @@ xbInt16 xbSsv::iDefaultFileVersion = 4;
xbString xbSsv::sNullString = "";
xbBool xbSsv::bDefaultAutoCommit = xbTrue;
-
-#ifdef WIN32
-xbString xbSsv::sDataDirectory = PROJECT_DATA_DIR;
-#else
-xbString xbSsv::sDataDirectory = PROJECT_DATA_DIR;
-#endif //
+xbString xbSsv::sDataDirectory = PROJECT_DATA_DIR;
+xbString xbSsv::sTempDirectory = PROJECT_TEMP_DIR;
#ifdef XB_LOGGING_SUPPORT
-xbString xbSsv::sLogDirectory = PROJECT_LOG_DIR;
-//xbString xbSsv::sLogDirectory = "";
-xbString xbSsv::sLogFileName = PROJECT_DFLT_LOGFILE;
+xbString xbSsv::sLogDirectory = PROJECT_LOG_DIR;
+xbString xbSsv::sLogFileName = PROJECT_DFLT_LOGFILE;
#endif // XB_LOGGING_SUPPORT
#ifdef XB_LOCKING_SUPPORT
@@ -223,25 +218,51 @@ const char * xbSsv::GetErrorMessage( xbInt16 iErrorCode ) const{
//! @brief Get home directory.
/*!
\param sHomeDirOut - Output home directory for current user.
- \returns void
*/
void xbSsv::GetHomeDir( xbString &sHomeDirOut ){
- #ifdef WIN32
+ #ifdef HAVE_GETENV_S_F
+
+ char sPath[MAX_PATH];
+ size_t lSize;
+
+ sHomeDirOut = "";
+ memset( sPath, 0x00, MAX_PATH );
+
+ getenv_s( &lSize, NULL, 0, "HOMEDRIVE" );
+ if( lSize > 0 ){
+ getenv_s( &lSize, sPath, lSize, "HOMEDRIVE" );
+ sHomeDirOut = sPath;
+ memset( sPath, 0x00, MAX_PATH );
+ }
+
+ getenv_s( &lSize, NULL, 0, "HOMEPATH" );
+ if( lSize > 0 ){
+ getenv_s( &lSize, sPath, lSize, "HOMEPATH" );
+ sHomeDirOut += sPath;
+ }
+ if( sHomeDirOut == "" )
+ sHomeDirOut = "C:\xbase64";
+
+ #elif defined(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.
/*!
- \param sDataDirectory Set the data direcroty.
+ \param sDataDirectory Set the data directory.
*/
void xbSsv::SetDataDirectory( const xbString &sDataDirectory ){
@@ -302,12 +323,55 @@ void xbSsv::SetEndianType() {
}
/*************************************************************************/
+//! @brief Set the temp directory.
+/*!
+ \param sTempDirectory Set the data direcroty.
+*/
+
+void xbSsv::SetTempDirectory( const xbString &sTempDirectory ){
+ this->sTempDirectory = sTempDirectory;
+
+ #ifdef WIN32
+ this->sTempDirectory.SwapChars( '/', '\\' );
+ #else
+ this->sTempDirectory.SwapChars( '\\', '/' );
+ #endif
+
+}
+
+/*************************************************************************/
+//! @brief Get the OS dependent path separator.
+/*!
+ \returns Returns '\' for windows environment, otherwise returns '/'.
+*/
+
+char xbSsv::GetPathSeparator() const {
+ #ifdef WIN32
+ return '\\';
+ #else
+ return '/';
+ #endif
+}
+
+/*************************************************************************/
+//! @brief Get the current temp directory.
+/*!
+ \returns xbString containing the current data directory
+ where the database files are stored.
+*/
+
+xbString &xbSsv::GetTempDirectory() const {
+ return sTempDirectory;
+}
+
+/*************************************************************************/
#ifdef XB_LOGGING_SUPPORT
//! @brief Get the default log file name.
/*!
\returns Returns the log file name.
*/
+
xbString & xbSsv::GetLogFileName() const {
return sLogFileName;
}
@@ -317,17 +381,18 @@ xbString & xbSsv::GetLogFileName() const {
/*!
\returns Returns the log directory.
*/
+
+
xbString & xbSsv::GetLogDirectory() const {
return sLogDirectory;
}
-
-
/*************************************************************************/
//! @brief Set the default log directory name.
/*!
\param sLogDirectory Name of desired log directory.
*/
+
void xbSsv::SetLogDirectory( const xbString &sLogDirectoryIn ){
this->sLogDirectory = sLogDirectoryIn;
@@ -339,13 +404,29 @@ void xbSsv::SetLogDirectory( const xbString &sLogDirectoryIn ){
}
+//! @brief Set the log file name.
+/*!
+ \param sLogFileName - Log File Name.
+ \return void
+*/
+
+void xbSsv::SetLogFileName( const xbString & sLogFileName ){
+
+ this->sLogFileName = sLogFileName;
+}
+
+
#else
xbString & xbSsv::GetLogFileName() const {
return sNullString;
}
+
xbString & xbSsv::GetLogDirectory() const {
+
+std::cout << "xbSsv::GetLogDirectory() returning null\n";
+
return sNullString;
}
@@ -353,6 +434,10 @@ void xbSsv::SetLogDirectory( const xbString &sLogDirectory ){
return;
}
+void xbSsv::SetLogFileName( const xbString & sLogFileName ){
+ return;
+}
+
#endif
/*************************************************************************/
diff --git a/src/core/xbstring.cpp b/src/core/xbstring.cpp
index 701e50e..89cefb6 100755
--- a/src/core/xbstring.cpp
+++ b/src/core/xbstring.cpp
@@ -2,7 +2,7 @@
XBase64 Software Library
-Copyright (c) 1997,2003,2014,2021,2022 Gary A Kunkel
+Copyright (c) 1997,2003,2014,2021,2022,2023 Gary A Kunkel
The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
@@ -175,7 +175,7 @@ xbString &xbString::operator+=( const xbString &s ) {
*t++ = s.GetCharacter(i+1);
data[newLen] = '\0';
- size += Len;
+ size == 0 ? size += (Len + 1) : size += Len;
return (*this);
}
@@ -197,7 +197,8 @@ xbString &xbString::operator+=( const char *s ) {
for( xbUInt32 i = 0; i < Len; i++ )
data[i+oldLen] = s[i];
data[newLen] = '\0';
- size += Len;
+ // size += Len;
+ size == 0 ? size+= (Len + 1) : size += Len;
return (*this);
}
/************************************************************************/
@@ -211,7 +212,8 @@ xbString &xbString::operator+=( char c ) {
data = (char *)realloc(data, oldLen+Len+1);
data[oldLen] = c;
data[oldLen+1] = 0;
- size++;
+ // size++;
+ size == 0 ? size += 2 : size++;
return (*this);
}
/************************************************************************/
@@ -237,7 +239,8 @@ xbString &xbString::operator-=( const xbString &s ) {
data[i+oldLen] = s.GetCharacter(i+1);
data[newLen] = '\0';
- size += Len;
+ //size += Len;
+ size == 0 ? size += (Len+1) : size += Len;
Rtrim();
return (*this);
}
@@ -265,7 +268,9 @@ xbString &xbString::operator-=(const char *s) {
data[i+oldLen] = s[i];
data[newLen] = '\0';
- size += Len;
+ //size += Len;
+ size == 0 ? size += (Len+1) : size += Len;
+
Rtrim();
return (*this);
}
@@ -278,7 +283,10 @@ xbString &xbString::operator-=(const char *s) {
xbString &xbString::operator-=(const char c) {
Rtrim();
xbUInt32 oldSize = size;
- size += 1;
+
+ // size += 1;
+ size == 0 ? size += 2 : size += 1;
+
data = (char *)realloc( data, size );
if( oldSize == 0 ) data[0] = 0;
data[size-2] = c;
@@ -534,7 +542,10 @@ xbString &xbString::AddBackSlash( char c ) {
if( data )
free( data );
data = p;
- size += lCnt;
+
+ // size += lCnt;
+ size == 0 ? size += (lCnt+1) : size += lCnt;
+
return *this;
}
/************************************************************************/
@@ -571,26 +582,37 @@ xbString &xbString::Append( char c ) {
/************************************************************************/
//! @brief Append data to string.
/*!
- \param s String data to append.
+ \param s String data to append.
\param ulByteCount Maximum number of bytes to append.
\returns Reference to this string.
*/
xbString &xbString::Append( const char *s, xbUInt32 ulByteCount ) {
- if (s == NULL) return (*this);
- xbUInt32 oldLen = this->Len();
- xbUInt32 newLen = ulByteCount + oldLen;
+ if ( s == NULL || !*s || ulByteCount == 0)
+ return (*this);
- data = (char *)realloc(data, newLen+1);
+ xbUInt32 ulOrigLen = this->Len();
- if(oldLen == 0)
- data[0] = 0;
+ // s might not be null byte at the end, can't use strlen
+ // xbUInt32 ulAddLen = strlen( s );
+ xbUInt32 ulAddLen = 0;
+ const char *p = s;
- for( xbUInt32 i = 0; i < ulByteCount; i++ )
- data[i+oldLen] = s[i];
+ while( ulAddLen < ulByteCount && *p ){
+ p++;
+ ulAddLen++;
+ }
- data[newLen] = '\0';
- size += ulByteCount;
+ if( ulAddLen > ulByteCount )
+ ulAddLen = ulByteCount;
+
+ size = ulOrigLen + ulAddLen + 1;
+ data = (char *) realloc( data, size );
+
+ for( xbUInt32 i = 0; i < ulAddLen; i++ )
+ data[i+ulOrigLen] = s[i];
+
+ data[size-1] = 0x00;
return (*this);
}
@@ -616,7 +638,10 @@ xbString &xbString::Assign(const char * sStr, xbUInt32 ulStartPos, xbUInt32 ulCo
if((( ulCopyLen - 1) + ulStartPos ) > lLen )
ulCopyLen = lLen - ulStartPos + 1;
data = (char *)calloc(1, ulCopyLen + 1);
- size = ulCopyLen;
+
+ //size = ulCopyLen + 1;
+ size == 0 ? size += (ulCopyLen+1) : size += ulCopyLen;
+
for( xbUInt32 i = 0; i < ulCopyLen; i++ )
data[i] = sStr[i + ulStartPos - ((xbUInt32) 1)];
data[ulCopyLen] = '\0';
@@ -643,7 +668,9 @@ xbString &xbString::Assign(const char * sStr, xbUInt32 ulStartPos){
xbUInt32 ulCopyLen;
ulCopyLen = ulSrcLen - ulStartPos + 1;
data = (char *)calloc(1, ulCopyLen + 1);
- size = ulCopyLen;
+
+ size = ulCopyLen + 1;
+
for( xbUInt32 i = 0; i < ulCopyLen; i++ )
data[i] = sStr[i + ulStartPos - ((xbUInt32) 1)];
data[ulCopyLen] = '\0';
@@ -672,7 +699,7 @@ xbString &xbString::Assign(const xbString& sStr, xbUInt32 ulStartPos, xbUInt32 u
if((( ulCopyLen - 1) + ulStartPos ) > ulSrcLen )
ulCopyLen = ulSrcLen - ulStartPos + 1;
data = (char *)calloc(1, ulCopyLen + 1);
- size = ulCopyLen;
+ size = ulCopyLen + 1;
for( xbUInt32 i = 0; i < ulCopyLen; i++ )
data[i] = sStr[i + ulStartPos];
data[ulCopyLen] = '\0';
@@ -703,6 +730,7 @@ xbString &xbString::Assign(const xbString& sStr, xbUInt32 ulStartPos){
for( xbUInt32 i = 0; i < ulCopyLen; i++ )
data[i] = sStr[i + ulStartPos];
data[ulCopyLen] = '\0';
+ size++;
return (*this);
}
/************************************************************************/
@@ -895,6 +923,21 @@ void xbString::DumpHex( const char * title ) const {
/************************************************************************/
//! @brief Extract an element out of a delimited string.
/*!
+ \param sSrc Source string.
+ \param cDelim Delimiter.
+ \param lSkipCnt Number of delimiters to skip.
+ \param iOpt 0 - ignore single and double quotes.<br>
+ 1 - ignore delimiters between single or double quotes.
+ \returns Reference to string extracted from element.
+*/
+xbString &xbString::ExtractElement( xbString &sSrc, char cDelim, xbUInt32 lSkipCnt, xbInt16 iOpt )
+{
+ return ExtractElement( sSrc.Str(), cDelim, lSkipCnt, iOpt );
+}
+
+/************************************************************************/
+//! @brief Extract an element out of a delimited string.
+/*!
\param pSrc Source string.
\param cDelim Delimiter.
\param lSkipCnt Number of delimiters to skip.
@@ -1043,6 +1086,8 @@ xbUInt32 xbString::GetLastPos(const char* s) const{
/************************************************************************/
//! @brief Get the path separator out of the string.
/*!
+ This method assumes the string is a valid path name.
+ If it is, it returns either / or \.
\returns Char value containing either / or \ depending on OS.
*/
char xbString::GetPathSeparator() const {
@@ -1147,12 +1192,15 @@ xbString &xbString::Ltrim(){
s++;
size--;
}
+
xbUInt32 i;
for( i = 0; i < size; i++ )
data[i] = data[i+s];
data[i] = 0x00;
data = (char *) realloc( data, size );
+
return *this;
+
}
/************************************************************************/
@@ -1162,10 +1210,6 @@ xbString &xbString::Ltrim(){
\returns Reference to this string.
*/
xbString &xbString::Ltrunc( xbUInt32 ulCnt ){
- // left truncate cnt bytes
-
- char * ndata;
- char * p;
if( ulCnt >= size ){
if( size > 0 ){
free( data );
@@ -1174,6 +1218,9 @@ xbString &xbString::Ltrunc( xbUInt32 ulCnt ){
}
return *this;
}
+
+ char * ndata;
+ char * p;
ndata = (char *) calloc( 1, size - ulCnt );
p = data;
p += ulCnt;
@@ -1203,12 +1250,27 @@ xbString &xbString::Mid( xbUInt32 ulStartPos, xbUInt32 ulTargLen ){
return( *this );
if( ulStartPos > Len() )
return( *this );
+/*
+ // Resize( ulTargLen + 1 );
char *pTarg = data;
char *pSrc = data + ulStartPos - 1;
for( xbUInt32 l = 0; l < ulTargLen; l++ )
*pTarg++ = *pSrc++;
*pTarg = 0x00;
- Resize( ulTargLen + 1 );
+ // Resize( ulTargLen + 1 );
+ */
+
+ char * newData = (char *) calloc( 1, ulTargLen + 1 );
+ char *pTarg = newData;
+ char *pSrc = data + ulStartPos - 1;
+ for( xbUInt32 l = 0; l < ulTargLen; l++ )
+ *pTarg++ = *pSrc++;
+ *pTarg = 0x00;
+
+ free( data );
+ data = newData;
+ size = ulTargLen + 1;
+
return *this;
}
@@ -1300,8 +1362,6 @@ xbUInt32 xbString::Pos(char c, xbUInt32 ulStartPos ) const {
return 0;
}
-
-
/************************************************************************/
//! @brief Determine position of a given character
/*!
@@ -1323,7 +1383,6 @@ xbUInt32 xbString::Pos(char c) const {
p++;
}
}
-
if( iFound )
return iPos + 1;
else
@@ -1396,10 +1455,6 @@ xbString &xbString::Remove(xbUInt32 ulStartPos, xbUInt32 ulDelSize ) {
return( *this );
}
-
-
-
-
/************************************************************************/
//! @brief Replace a value within a string with another value
/*!
@@ -1457,6 +1512,7 @@ xbString &xbString::Replace( const char *sReplace, const char *sReplaceWith, xbI
free(data);
data = sBuf2;
+ size = ulNewLen;
}
}
return *this;
@@ -1471,12 +1527,11 @@ xbString &xbString::Replace( const char *sReplace, const char *sReplaceWith, xbI
//the new size includes the null termination byte
xbString &xbString::Resize(xbUInt32 ulSize) {
-// data = (char *) realloc((void *) data, ulSize );
+// data = (char *) realloc( data, ulSize );
// original
- data = (char *)realloc(data, ulSize);
-
+ data = (char *) realloc( data, ulSize );
if( ulSize > 0 )
data[ulSize-1] = 0;
@@ -1495,6 +1550,8 @@ xbString &xbString::Rtrim(){
xbUInt32 l = Len();
if( l == 0 )
return *this;
+
+ xbUInt32 ulOrigSize = size;
l--;
for(;;) {
@@ -1506,6 +1563,9 @@ xbString &xbString::Rtrim(){
break;
l--;
}
+
+ if( ulOrigSize != size )
+ data = (char * ) realloc( data, size );
return *this;
}
@@ -1525,7 +1585,7 @@ xbString &xbString::Set( const char *s ) {
free(data);
data = NULL;
}
- if(s == NULL ) {
+ if( s == NULL || !*s ) {
if( data )
free( data );
data = NULL;
@@ -1546,14 +1606,17 @@ xbString &xbString::Set( const char *s ) {
*/
xbString &xbString::Set( const xbString &s ) {
+// if( s.Str() == NULL || s.Len() == 0 ){
+
if( s.Str() == NULL ){
if( data ) free( data );
data = NULL;
size = 0;
} else {
- char *p = (char *) calloc( 1, s.Len() + 1 );
+ xbUInt32 ulLen = s.Len();
+ char *p = (char *) calloc( 1, ulLen + 1 );
xb_strcpy( p, s.Str());
- size = s.Len() + 1;
+ size = ulLen + 1;
if( data ) free( data );
data = p;
}
@@ -1619,12 +1682,8 @@ xbString &xbString::Sprintf( const char *sFormat, ...) {
xbInt32 iRc;
va_list ap;
-
char *t;
-// if( data )
-// free( data );
-
#ifdef HAVE__VSNPRINTF_S_F
va_start( ap, sFormat );
@@ -1646,7 +1705,7 @@ xbString &xbString::Sprintf( const char *sFormat, ...) {
va_start( ap, sFormat );
// size = (xbUInt32) vsprintf_s( NULL, 0, sFormat, ap ) + 1;
- size = _vscprintf( sFormat, ap ) + 1;
+ size = (xbUInt32) _vscprintf( sFormat, ap ) + 1;
va_end( ap );
t = (char *) malloc( size );
@@ -1772,7 +1831,6 @@ xbString &xbString::Trim(){
return *this;
}
-
/************************************************************************/
//! @brief Private function used for reallocateing memory
/*!
@@ -1816,11 +1874,8 @@ char * xbString::xb_realloc( char * pIn, xbUInt32 iLen ){
char * xbString::xb_strcpy( char *sTarget, const char *sSource ){
char *temp = sTarget;
- while( *sSource != '\0'){
+ while( *sSource != '\0')
*sTarget++ = *sSource++;
-// sTarget++;
-// sSource++;
- }
*sTarget= '\0';
return temp;
}
@@ -1890,7 +1945,8 @@ xbString &xbString::ZapChar( char c ){
}
}
*t = 0x00;
- Resize( size );
+
+ data = (char *) realloc( data, size );
return *this;
}
@@ -1914,7 +1970,6 @@ xbString &xbString::ZapLeadingChar( char c ){
return *this;
}
-
/************************************************************************/
//! @brief Remove trailing character from a string.
/*!
@@ -1926,7 +1981,7 @@ xbString &xbString::ZapTrailingChar( char c ){
xbUInt32 l = Len();
if( l == 0 )
return *this;
-
+ xbUInt32 ulOrigSize = size;
l--;
for(;;) {
if( data[l] != c )
@@ -1937,6 +1992,8 @@ xbString &xbString::ZapTrailingChar( char c ){
break;
l--;
}
+ if( ulOrigSize != size )
+ data = (char *) realloc( data, size );
return *this;
}
diff --git a/src/core/xbtag.cpp b/src/core/xbtag.cpp
index a71880b..621d44b 100755
--- a/src/core/xbtag.cpp
+++ b/src/core/xbtag.cpp
@@ -3,7 +3,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.
diff --git a/src/core/xbtblmgr.cpp b/src/core/xbtblmgr.cpp
index 2fe6a8c..53b6dd9 100755
--- a/src/core/xbtblmgr.cpp
+++ b/src/core/xbtblmgr.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.
@@ -124,6 +124,7 @@ xbInt16 xbTblMgr::AddTblToTblList( xbDbf *d, const xbString & sFqTblName, const
if( t && (strcmp( t->psTblAlias->Str(), sAlias.Str()) == 0 )){
iErrorStop = 120;
delete i->psFqTblName;
+ delete i->psTblName;
delete i->psTblAlias;
free( i );
iRc = XB_DUP_TABLE_OR_ALIAS;
@@ -194,7 +195,7 @@ xbDbf *xbTblMgr::GetDbfPtr(const xbString& sTblAlias) const {
t = TblList;
while( t ){
- std::cout << "s = [" << s.Str() << "] tbl name = [" << t->psTblName->Str() << "]\n";
+ // std::cout << "s = [" << s.Str() << "] tbl name = [" << t->psTblName->Str() << "]\n";
if( s == t->psTblName->Str()){
std::cout << "found\n";
return t->pDbf;
diff --git a/src/core/xbuda.cpp b/src/core/xbuda.cpp
index 0a9c2e7..5db7aec 100755
--- a/src/core/xbuda.cpp
+++ b/src/core/xbuda.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.
diff --git a/src/core/xbxbase.cpp b/src/core/xbxbase.cpp
index 20b7fcc..7267f98 100755
--- a/src/core/xbxbase.cpp
+++ b/src/core/xbxbase.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.
@@ -21,13 +21,13 @@ namespace xb{
//! @brief Class Constructor.
xbXBase::xbXBase() {
SetEndianType();
- #ifdef XB_LOGGING_SUPPORT
- xLog = new xbLog();
- #endif
xbFile f( this );
f.SetHomeFolders();
-
+ xbDate d( (xbUInt16) 1); // initialize xbDate static variables
+ #ifdef XB_LOGGING_SUPPORT
+ xLog = new xbLog();
+ #endif
}
/*************************************************************************/
//! @brief Class Deconstructor.
@@ -37,11 +37,10 @@ xbXBase::~xbXBase(){
delete xLog;
#endif
}
-
/*************************************************************************/
//! @brief Close all tables / files.
/*!
- This closes everything.
+ This closes everything and deletes references to the associated xbDbf objects.
\returns <a href="xbretcod_8h.html">Return Codes</a>
*/
xbInt16 xbXBase::CloseAllTables(){
@@ -58,6 +57,7 @@ xbInt16 xbXBase::CloseAllTables(){
iErrorStop = 100;
throw iRc;
}
+ delete d;
} else {
iRc = XB_INVALID_OBJECT;
iErrorStop = 110;
@@ -74,7 +74,39 @@ xbInt16 xbXBase::CloseAllTables(){
return iRc;
}
+/************************************************************************/
+//! @brief Fully qualified file name from a directory, filename and extension.
+/*!
+ Given a directory, file name and file extension as inputs, create a fully qualified file name.
+ \param sDirIn Directory
+ \param sFileIn File Name
+ \param sExtIn File Extension
+ \param sFqnOut A fully qualifed unique file name as output
+ \returns XB_INVALIED_PARAMETER or XB_NO_ERROR
+*/
+xbInt16 xbXBase::CreateFqn( const xbString &sDirIn, const xbString &sNameIn, const xbString &sExtIn, xbString &sFqnOut ){
+
+ if( sNameIn == "" || sExtIn == "" )
+ return XB_INVALID_PARAMETER;
+
+ sFqnOut = sDirIn;
+ #ifdef WIN32
+ sFqnOut.SwapChars( '/', '\\' );
+ if( sFqnOut[sFqnOut.Len()] != '\\' )
+ sFqnOut += '\\';
+ #else
+ sFqnOut.SwapChars( '\\', '/' );
+ if( sFqnOut[sFqnOut.Len()] != '/' )
+ sFqnOut += '/';
+ #endif
+ sFqnOut += sNameIn;
+ if( sExtIn != "" ){
+ sFqnOut += '.';
+ sFqnOut += sExtIn;
+ }
+ return XB_NO_ERROR;
+}
/*************************************************************************/
//! @brief Parse commmand line options for a given parm request
@@ -134,18 +166,21 @@ const xbString & xbXBase::GetLogFqFileName() const {
/*!
\returns Returns the log file name.
*/
+/*
const xbString & xbXBase::GetLogFileName() const {
return xLog->GetFileName();
}
+*/
//! @brief Get the log directory.
/*!
\returns Returns the log directory.
*/
+/*
const xbString & xbXBase::GetLogDirectory() const {
- return xLog->GetDirectory();
+ return GetLogDirectory();
}
-
+*/
//! @brief Get the log directory.
/*!
\returns xbTrue - Logging enabled.<br>xbFalse - Logging disables.
@@ -159,19 +194,23 @@ xbBool xbXBase::GetLogStatus() const {
\param sLogFileName - Log File Name.
\return void
*/
+/*
void xbXBase::SetLogFileName( const xbString & sLogFileName ){
xLog->SetFileName( sLogFileName );
}
-
+*/
//! @brief Set the log directory.
/*!
\param sLogDirectory - Log File Directory.
\return void
*/
+/*
void xbXBase::SetLogDirectory( const xbString & sLogDirectory ){
xLog->SetDirectory( sLogDirectory );
}
+*/
+
//! @brief Set the logfile size.
/*!
@@ -182,6 +221,15 @@ void xbXBase::SetLogSize( size_t lSize ) {
xLog->LogSetLogSize( lSize );
}
+//! @brief Get the logfile size.
+/*!
+ \return log file size
+*/
+size_t xbXBase::GetLogSize() const {
+ return xLog->LogGetLogSize();
+}
+
+
//! @brief Write message to logfile.
/*!
\param sLogMessage - Message to write.
@@ -225,18 +273,22 @@ xbInt16 xbXBase::FlushLog() {
const xbString & xbXBase::GetLogFqFileName() const {
return sNullString;
}
+/*
const xbString & xbXBase::GetLogFileName() const {
return sNullString;
}
const xbString & xbXBase::GetLogDirectory() const {
return sNullString;
}
+*/
+/*
void xbXBase::SetLogFileName( const xbString & sLogFileName ){
return;
}
void xbXBase::SetLogDirectory( const xbString & sLogDirectory ){
return;
}
+*/
xbBool xbXBase::GetLogStatus() const {
return xbFalse;
}
@@ -258,6 +310,7 @@ xbInt16 xbXBase::FlushLog() {
void xbXBase::SetLogSize( size_t lSize ) {
return;
}
+
#endif // XB_LOGGING_SUPPORT
/*************************************************************************/
@@ -554,8 +607,8 @@ xbInt16 xbXBase::GetFunctionInfo( const xbString &sExpLine, char &cReturnType, x
\param lMillisecs Milliseconds to sleep.
*/
void xbXBase::xbSleep( xbInt32 lMillisecs ){
- #ifdef WIN32
- Sleep( lMillisecs );
+ #ifdef WIN32
+ Sleep( (xbUInt32) lMillisecs );
#else
usleep( (xbInt64) lMillisecs * 1000 );
#endif
@@ -703,6 +756,7 @@ xbInt16 xbXBase::OpenHighestVersion( const xbString &sTableName, const xbString
iRc = XB_FILE_NOT_FOUND;
throw iRc;
}
+
unsigned char cFileTypeByte;
if(( iRc = f.GetXbaseFileTypeByte( f.GetFqFileName(), cFileTypeByte )) != XB_NO_ERROR ){
iErrorStop = 120;