summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
-rwxr-xr-xsrc/examples/xb_ex_date.cpp2
-rwxr-xr-xsrc/examples/xb_ex_expression.cpp5
-rwxr-xr-xsrc/examples/xb_ex_log.cpp77
-rwxr-xr-xsrc/examples/xb_ex_ssv.cpp4
-rwxr-xr-xsrc/examples/xb_ex_string.cpp5
-rwxr-xr-xsrc/examples/xb_ex_v3_create_dbf.cpp28
-rwxr-xr-xsrc/examples/xb_ex_v3_upd_dbf.cpp144
-rwxr-xr-xsrc/examples/xb_ex_v4_create_dbf.cpp9
-rwxr-xr-xsrc/examples/xb_ex_v4_upd_dbf.cpp16
-rwxr-xr-xsrc/include/xbconfig.h.in6
-rwxr-xr-xsrc/include/xbcrix.cpp292
-rwxr-xr-xsrc/include/xbdate.h5
-rwxr-xr-xsrc/include/xbdbf.h22
-rwxr-xr-xsrc/include/xbexp.h1
-rwxr-xr-xsrc/include/xbexpnode.h2
-rwxr-xr-xsrc/include/xbfile.h139
-rwxr-xr-xsrc/include/xbindex.h184
-rwxr-xr-xsrc/include/xbindex.h.nope605
-rwxr-xr-xsrc/include/xblog.h15
-rwxr-xr-xsrc/include/xbretcod.h3
-rwxr-xr-xsrc/include/xbssv.h19
-rwxr-xr-xsrc/include/xbstring.h6
-rwxr-xr-xsrc/include/xbxbase.h13
-rwxr-xr-xsrc/sql/xbcrix.cpp54
-rwxr-xr-xsrc/sql/xbcrtbl.cpp13
-rwxr-xr-xsrc/sql/xbcrtbl.save.cpp256
-rwxr-xr-xsrc/sql/xbdelete.cpp2
-rwxr-xr-xsrc/sql/xbdrptbl.cpp11
-rwxr-xr-xsrc/tests/tstfuncs.cpp2
-rwxr-xr-xsrc/tests/xb_test_date.cpp34
-rwxr-xr-xsrc/tests/xb_test_dbf_v3_memos.cpp6
-rwxr-xr-xsrc/tests/xb_test_dbf_v4_nomemos.cpp14
-rwxr-xr-xsrc/tests/xb_test_expression.cpp62
-rwxr-xr-xsrc/tests/xb_test_file.cpp116
-rwxr-xr-xsrc/tests/xb_test_funcs.cpp3
-rwxr-xr-xsrc/tests/xb_test_lock.cpp318
-rwxr-xr-xsrc/tests/xb_test_lock2.cpp34
-rwxr-xr-xsrc/tests/xb_test_log.cpp52
-rwxr-xr-xsrc/tests/xb_test_mdx.cpp15
-rwxr-xr-xsrc/tests/xb_test_ndx.cpp55
-rwxr-xr-xsrc/tests/xb_test_sql.cpp119
-rwxr-xr-xsrc/tests/xb_test_string.cpp176
-rwxr-xr-xsrc/tests/xb_test_tblmgr.cpp33
-rwxr-xr-xsrc/tests/xb_test_tdx.cpp162
-rwxr-xr-xsrc/tests/xb_test_xbase.cpp113
-rwxr-xr-xsrc/utils/xb_cfg_check.cpp55
-rwxr-xr-xsrc/utils/xb_dbfutil.cpp75
-rwxr-xr-xsrc/utils/xb_execsql.cpp69
-rwxr-xr-xsrc/utils/xb_import.cpp242
74 files changed, 4539 insertions, 1631 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;
diff --git a/src/examples/xb_ex_date.cpp b/src/examples/xb_ex_date.cpp
index fc038b5..7b92dbe 100755
--- a/src/examples/xb_ex_date.cpp
+++ b/src/examples/xb_ex_date.cpp
@@ -24,6 +24,8 @@ using namespace xb;
int main()
{
+ xbXBase x; /* initial date static variables */
+
xbString StringDate( "19601007" ); /* oct 7 1960 */
char CharDate[9] = "19611109"; /* nov 9 1961 */
diff --git a/src/examples/xb_ex_expression.cpp b/src/examples/xb_ex_expression.cpp
index 840e9c6..f16c79f 100755
--- a/src/examples/xb_ex_expression.cpp
+++ b/src/examples/xb_ex_expression.cpp
@@ -168,7 +168,6 @@ int main(){
}
PrintResult( &sExpression, &exp );
-
// String expression example
sExpression = "CFLD1+CFLD2+'{'+DTOS(DATE1)+'}'";
xbExp exp2( &x );
@@ -176,11 +175,13 @@ int main(){
iErrorStop = 210;
throw iRc;
}
+
// Process the parsed expression
if(( iRc = exp2.ProcessExpression()) != XB_NO_ERROR ){
iErrorStop = 220;
return -1;
}
+
PrintResult( &sExpression, &exp2 );
// Date example
@@ -211,8 +212,6 @@ int main(){
}
PrintResult( &sExpression, &exp4 );
-
-
// Cleanup
MyFile->DeleteTable();
delete MyFile;
diff --git a/src/examples/xb_ex_log.cpp b/src/examples/xb_ex_log.cpp
new file mode 100755
index 0000000..cf5320f
--- /dev/null
+++ b/src/examples/xb_ex_log.cpp
@@ -0,0 +1,77 @@
+/* xb_ex_log.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 program demostrates how to use logging
+
+
+#include "xbase.h"
+
+using namespace xb;
+
+int main( int argCnt, char **av )
+{
+
+ #ifdef XB_LOGGING_SUPPORT
+
+ xbXBase x;
+ xbString sMsg;
+
+
+ std::cout << "Default Logfile Name is: [" << x.GetLogFqFileName().Str()
+ << "] Rollover size = [" << x.GetLogSize()
+ << "]" << std::endl;
+
+ if( x.GetLogStatus() )
+ std::cout << "Logging is active" << std::endl;
+ else
+ std::cout << "Logging is inactive" << std::endl;
+
+ x.SetLogDirectory( PROJECT_LOG_DIR ); // use the library log directory
+ x.SetLogFileName ( "MySpecialLogFile.txt" ); // set to use a special name
+ x.SetLogSize ( x.GetLogSize() * 2 ); // double the log file size
+
+ // enable the logfile and write a message for the new settings to take effect
+ x.EnableMsgLogging();
+ sMsg.Sprintf( "Program [%s] initializing...", av[0] );
+ x.WriteLogMessage( sMsg );
+
+ std::cout << "New Logfile Name is: [" << x.GetLogFqFileName().Str()
+ << "] Rollover size = [" << x.GetLogSize()
+ << "]" << std::endl;
+
+ if( x.GetLogStatus() )
+ std::cout << "Logging is active" << std::endl;
+ else
+ std::cout << "Logging is inactive" << std::endl;
+
+ // write some messages to the logfile
+ for( int i = 0; i < 5; i++ ){
+ sMsg.Sprintf( "Test message [%d]", i );
+ x.WriteLogMessage( sMsg );
+ }
+
+ sMsg.Sprintf( "Program [%s] terminating..", av[0] );
+ x.WriteLogMessage( sMsg );
+
+ x.FlushLog(); // not really needed, but here for demonstration purposes
+
+ #endif // B_LOGGING_SUPPORT
+
+ return 0;
+}
+
+
+
+
diff --git a/src/examples/xb_ex_ssv.cpp b/src/examples/xb_ex_ssv.cpp
index a78345f..61d72a2 100755
--- a/src/examples/xb_ex_ssv.cpp
+++ b/src/examples/xb_ex_ssv.cpp
@@ -19,7 +19,9 @@ This program demonstrates using functionality of the xbSsv class (Shared system
using namespace xb;
-int main( int ac, char ** av ){
+//int main( int ac, char ** av ){
+
+int main( int, char ** av ){
xbXBase x; // set up xbase for business
xbString sMsg; // a message string
diff --git a/src/examples/xb_ex_string.cpp b/src/examples/xb_ex_string.cpp
index 30fd74e..0cd7671 100755
--- a/src/examples/xb_ex_string.cpp
+++ b/src/examples/xb_ex_string.cpp
@@ -116,8 +116,9 @@ int main()
std::cout << s3.Str() << std::endl;
- s3 = 'A' + s1;
-
+ // The following compiles and runs, but is not valid
+ // s3 = 'A' + s1;
+
std::cout << std::endl << "== operator tests" << std::endl;
if( s1 == s2 )
std::cout << s1.Str() << " == " << s2.Str() << std::endl;
diff --git a/src/examples/xb_ex_v3_create_dbf.cpp b/src/examples/xb_ex_v3_create_dbf.cpp
index ecfcd72..d6f7047 100755
--- a/src/examples/xb_ex_v3_create_dbf.cpp
+++ b/src/examples/xb_ex_v3_create_dbf.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.
@@ -47,19 +47,19 @@ int main()
// Create Dbase3 NDX style indices if support compiled in
-#ifdef XB_NDX_SUPPORT
+ #ifdef XB_NDX_SUPPORT
xbIxNdx MyIndex1( MyDbfFile ); /* class for index 1 */
xbIxNdx MyIndex2( MyDbfFile ); /* class for index 2 */
xbIxNdx MyIndex3( MyDbfFile ); /* class for index 3 */
-#endif
+ #endif
-// fixme
-// Create Clipper NTX style indices if support compiled in - bring this back to life in a future release
-#ifdef XB_INDEX_NTX
+ // fixme
+ // Create Clipper NTX style indices if support compiled in - bring this back to life in a future release
+ #ifdef XB_INDEX_NTX
xbNtx MyIndex4( &MyDbfFile ); /* class for index 4 */
xbNtx MyIndex5( &MyDbfFile ); /* class for index 5 */
-#endif
+ #endif
xbInt16 rc;
@@ -68,7 +68,7 @@ int main()
else
{
-#ifdef XB_NDX_SUPPORT
+ #ifdef XB_NDX_SUPPORT
xbIx *pIx;
void *pTag;
@@ -83,6 +83,7 @@ int main()
if(( rc = MyDbfFile->CreateTag ( "NDX", "MYINDEX1.NDX", "LASTNAME", "", 0, 1, XB_OVERLAY, &pIx, &pTag )) != XB_NO_ERROR )
x.DisplayError( rc );
+
/* define a multi-field index "LASTNAME FIRSTNAME" */
if(( rc = MyDbfFile->CreateTag( "NDX", "MYINDEX2.NDX", "LASTNAME+FIRSTNAME", "", 0, 1, XB_OVERLAY, &pIx, &pTag )) != XB_NO_ERROR )
x.DisplayError( rc );
@@ -91,12 +92,19 @@ int main()
if(( rc = MyDbfFile->CreateTag( "NDX", "MYINDEX3.NDX", "ZIPCODE", "", 0, 0, XB_OVERLAY, &pIx, &pTag )) != XB_NO_ERROR )
x.DisplayError( rc );
-#endif
+ std::cout << "Tag Count in MYINDEX3.NDX = " << pIx->GetTagCount() << "\n";
+ xbString sTagName;
+ sTagName = pIx->GetTagName( &pTag );
+ std::cout << "Tag Name in MYINDEX3.NDX = " << sTagName.Str() << "\n";
+
+
+ #endif
}
MyDbfFile->Close(); /* Close database and associated indexes */
+ delete MyDbfFile;
-#endif // XB_DBF3_SUPPORT
+ #endif // XB_DBF3_SUPPORT
return 0;
}
diff --git a/src/examples/xb_ex_v3_upd_dbf.cpp b/src/examples/xb_ex_v3_upd_dbf.cpp
index aa6ec49..eecba16 100755
--- a/src/examples/xb_ex_v3_upd_dbf.cpp
+++ b/src/examples/xb_ex_v3_upd_dbf.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.
@@ -45,7 +45,9 @@ int main()
x.WriteLogMessage( "Program [xb_ex_v3_upd_dbf] initializing..." );
- xbDbf * MyTable = new xbDbf3( &x ); /* class for V3 table */
+ xbDbf * MyTable = new xbDbf3( &x ); /* class for V3 table */
+
+ xbString sSearchKey; /* string for doing an index lookup */
xbInt16 iRc = 0;
xbInt16 iErrorStop = 0;
@@ -53,29 +55,36 @@ int main()
try{
if(( iRc = MyTable->Open( "MyV3Table1.DBF" )) != XB_NO_ERROR ){
- iErrorStop = 1;
+ iErrorStop = 100;
throw iRc;
}
+
#ifdef XB_NDX_SUPPORT
// V3 NDX style indices can be opened manually (vs production MDX index files opened automatically)
+
+
if(( iRc = MyTable->OpenIndex( "NDX", "MYINDEX1.NDX")) != XB_NO_ERROR ){
- iErrorStop = 2;
+ iErrorStop = 110;
throw iRc;
}
+
+
+/*
if(( iRc = MyTable->OpenIndex( "NDX", "MYINDEX2.NDX" )) != XB_NO_ERROR ){
- iErrorStop = 3;
+ iErrorStop = 120;
throw iRc;
}
+
if(( iRc = MyTable->OpenIndex( "NDX", "MYINDEX3.NDX" )) != XB_NO_ERROR ){
- iErrorStop = 4;
+ iErrorStop = 130;
throw iRc;
}
+*/
+
std::cout << "Current tag = [" << MyTable->GetCurTagName().Str() << "]\n";
#endif
-
-
// get the field numbers for all the fields in the table
fld_FIRSTNAME = MyTable->GetFieldNo( "FIRSTNAME" );
fld_LASTNAME = MyTable->GetFieldNo( "LASTNAME" );
@@ -84,189 +93,223 @@ int main()
fld_RETIRED = MyTable->GetFieldNo( "RETIRED?" );
fld_ZIPCODE = MyTable->GetFieldNo( "ZIPCODE" );
+
+
+ // do an index lookup for (key does not exist in this example)
+ sSearchKey = "abc123";
+ if(( iRc = MyTable->Find( sSearchKey )) != XB_NOT_FOUND ){
+ iErrorStop = 140;
+ throw iRc;
+ }
+ std::cout << "RC = " << iRc << "\n";
+
+
+
#ifdef XB_MEMO_SUPPORT
fld_MEMO1 = MyTable->GetFieldNo( "MEMO1" );
#endif
+
// Blank the record buffer
if(( iRc = MyTable->BlankRecord()) != XB_NO_ERROR ){
- iErrorStop = 7;
+ iErrorStop = 140;
throw iRc;
}
+
// put field examples - using field numbers
if(( iRc = MyTable->PutField( fld_LASTNAME, "JONES" )) != XB_NO_ERROR ){
- iErrorStop = 8;
+ iErrorStop = 150;
throw iRc;
}
+
if(( iRc = MyTable->PutField( fld_FIRSTNAME, "JERRY" )) != XB_NO_ERROR ){
- iErrorStop = 9;
+ iErrorStop = 160;
throw iRc;
}
+
if(( iRc = MyTable->PutField( fld_AMOUNT, "12.35" )) != XB_NO_ERROR ){
- iErrorStop = 10;
+ iErrorStop = 170;
throw iRc;
}
if(( iRc = MyTable->PutField( fld_BIRTHDATE, "19880208" )) != XB_NO_ERROR ){
- iErrorStop = 10;
+ iErrorStop = 180;
throw iRc;
}
if(( iRc = MyTable->PutLogicalField( fld_RETIRED, "Y" )) != XB_NO_ERROR ){
- iErrorStop = 11;
+ iErrorStop = 190;
throw iRc;
}
if(( iRc = MyTable->PutLongField( fld_ZIPCODE, 12345 )) != XB_NO_ERROR ){
- iErrorStop = 12;
+ iErrorStop = 200;
throw iRc;
}
#ifdef XB_MEMO_SUPPORT
sMemoData = "Memo data record 1";
if(( iRc = MyTable->UpdateMemoField( fld_MEMO1, sMemoData )) != XB_NO_ERROR ){
- iErrorStop = 13;
+ iErrorStop = 210;
throw iRc;
}
#endif
// Append the first record
if(( iRc = MyTable->AppendRecord()) != XB_NO_ERROR ){
- iErrorStop = 15;
- throw iRc;
+ // here is where you would address any errors.
+ // in this program, we simply abort and continue
+ MyTable->Abort();
}
// put field to the record buffer using field name (slightly less efficient than using field numbers)
-
// Blank the record buffer
if(( iRc = MyTable->BlankRecord()) != XB_NO_ERROR ){
- iErrorStop = 20;
+ iErrorStop = 220;
throw iRc;
}
if(( iRc = MyTable->PutField( "LASTNAME", "EINSTIEN" )) != XB_NO_ERROR ){
- iErrorStop = 21;
+ iErrorStop = 230;
throw iRc;
}
if(( iRc = MyTable->PutField( "FIRSTNAME", "ALBERT" )) != XB_NO_ERROR ){
- iErrorStop = 22;
+ iErrorStop = 240;
throw iRc;
}
if(( iRc = MyTable->PutField( "AMOUNT", "987.55" )) != XB_NO_ERROR ){
- iErrorStop = 23;
+ iErrorStop = 250;
throw iRc;
}
if(( iRc = MyTable->PutField( fld_BIRTHDATE, "19890209" )) != XB_NO_ERROR ){
- iErrorStop = 24;
+ iErrorStop = 260;
throw iRc;
}
if(( iRc = MyTable->PutLogicalField( "RETIRED?", "N" )) != XB_NO_ERROR ){
- iErrorStop = 25;
+ iErrorStop = 270;
throw iRc;
}
if(( iRc = MyTable->PutLongField( "ZIPCODE", 44256 )) != XB_NO_ERROR ){
- iErrorStop = 26;
+ iErrorStop = 280;
throw iRc;
}
#ifdef XB_MEMO_SUPPORT
sMemoData = "Memo data record 2";
if(( iRc = MyTable->UpdateMemoField( fld_MEMO1, sMemoData )) != XB_NO_ERROR ){
- iErrorStop = 27;
+ iErrorStop = 290;
throw iRc;
}
#endif
// Append the second record
if(( iRc = MyTable->AppendRecord()) != XB_NO_ERROR ){
- iErrorStop = 30;
- throw iRc;
+ // here is where you would address any errors.
+ // in this program, we simply abort and continue
+ MyTable->Abort();
}
+
+ if(( iRc = MyTable->GetRecord( 1 )) != XB_NO_ERROR ){
+ iErrorStop = 300;
+ throw iRc;
+ }
// get a field with a field number
- xbString FirstName;
- if(( iRc = MyTable->GetField( fld_FIRSTNAME, FirstName )) < 0 ){
- iErrorStop = 40;
+ xbString sFirstName;
+ if(( iRc = MyTable->GetField( fld_FIRSTNAME, sFirstName )) < 0 ){
+ iErrorStop = 310;
throw iRc;
}
- std::cout << "First Name is [" << FirstName.Str() << "]" << std::endl;
+ std::cout << "First Name is [" << sFirstName.Str() << "]" << std::endl;
- xbString LastName;
- if(( iRc = MyTable->GetField( "LASTNAME", LastName )) < 0 ){
- iErrorStop = 41;
+ xbString sLastName;
+ if(( iRc = MyTable->GetField( "LASTNAME", sLastName )) < 0 ){
+ iErrorStop = 320;
throw iRc;
}
- std::cout << "Last Name is [" << LastName.Str() << "]" << std::endl;
+ std::cout << "Last Name is [" << sLastName.Str() << "]" << std::endl;
xbInt16 iNoOfDecimals;
if(( iRc = MyTable->GetFieldDecimal( "AMOUNT", iNoOfDecimals )) != XB_NO_ERROR ){
- iErrorStop = 42;
+ iErrorStop = 330;
throw iRc;
}
std::cout << "There are " << iNoOfDecimals << " decimals in the AMOUNT field" << std::endl;
xbString FieldName;
if(( iRc = MyTable->GetFieldName( 4, FieldName )) != XB_NO_ERROR ){
- iErrorStop = 43;
+ iErrorStop = 340;
throw iRc;
}
std::cout << "Field #4 name is " << FieldName.Str() << std::endl;
xbString sRetired;
if(( iRc = MyTable->GetLogicalField( "RETIRED?", sRetired )) < 0 ){
- iErrorStop = 45;
+ iErrorStop = 350;
throw iRc;
}
std::cout << "Switch value = [" << sRetired.Str() << "]" << std::endl;
xbInt32 lZip;
if(( iRc = MyTable->GetLongField( "ZIPCODE", lZip )) < 0 ){
- iErrorStop = 46;
+ iErrorStop = 360;
throw iRc;
}
std::cout << "Long value = [" << lZip << "]" << std::endl;
// Initialize the record buffer in preparation for another record
if(( iRc = MyTable->BlankRecord()) != XB_NO_ERROR ){
- iErrorStop = 48;
+ iErrorStop = 370;
throw iRc;
}
// Append another record (it will be blank)
if(( iRc = MyTable->AppendRecord()) != XB_NO_ERROR ){
- iErrorStop = 49;
- throw iRc;
+ // here is where you would address any errors.
+ // in this program, we simply abort and continue
+ MyTable->Abort();
};
- // mark current record for deletion
+ // mark record 1 for deletion
+ if(( iRc = MyTable->GetRecord( 1 )) != XB_NO_ERROR ){
+ iErrorStop = 300;
+ throw iRc;
+ }
+
if(( iRc = MyTable->DeleteRecord()) != XB_NO_ERROR ){
- iErrorStop = 50;
+ iErrorStop = 380;
throw iRc;
};
// save current record
if(( iRc = MyTable->PutRecord()) != XB_NO_ERROR ){
- iErrorStop = 51;
+ iErrorStop = 390;
throw iRc;
}
// pack the table with no options
if(( iRc = MyTable->Pack()) != XB_NO_ERROR ){
- iErrorStop = 52;
+ iErrorStop = 400;
throw iRc;
}
+ if(( iRc = MyTable->Commit()) != XB_NO_ERROR ){
+ // here is where you would address any errors.
+ // in this program, we simply abort and continue
+ MyTable->Abort();
+ }
+
/* Close database and associated indexes */
if(( iRc = MyTable->Close()) != XB_NO_ERROR ){
- iErrorStop = 53;
+ iErrorStop = 410;
throw iRc;
}
@@ -276,7 +319,8 @@ int main()
std::cout << x.GetErrorMessage( rc ) << std::endl;
}
-#endif // XB_DBF3_SUPPORT
+ delete MyTable;
+ #endif // XB_DBF3_SUPPORT
return 0;
}
diff --git a/src/examples/xb_ex_v4_create_dbf.cpp b/src/examples/xb_ex_v4_create_dbf.cpp
index 6169213..d6bfb2f 100755
--- a/src/examples/xb_ex_v4_create_dbf.cpp
+++ b/src/examples/xb_ex_v4_create_dbf.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.
@@ -60,12 +60,12 @@ int main()
xbInt16 iRc;
xbDbf * MyDbfFile;
-
+
#ifdef XB_MDX_SUPPORT
xbIx *pIx;
void *pTag;
#endif // XB_MDX_SUPPORT
-
+
MyDbfFile = new xbDbf4( &x );
if(( iRc = MyDbfFile->CreateTable( "Address.DBF", "Address", MyAddressBookRecord, XB_OVERLAY, XB_MULTI_USER )) != XB_NO_ERROR )
@@ -93,7 +93,8 @@ int main()
}
MyDbfFile->Close(); /* Close database and associated indexes */
+ delete MyDbfFile;
-#endif // XB_DBF4_SUPPORT
+ #endif // XB_DBF4_SUPPORT
return 0;
}
diff --git a/src/examples/xb_ex_v4_upd_dbf.cpp b/src/examples/xb_ex_v4_upd_dbf.cpp
index 75d0641..d128eba 100755
--- a/src/examples/xb_ex_v4_upd_dbf.cpp
+++ b/src/examples/xb_ex_v4_upd_dbf.cpp
@@ -209,7 +209,7 @@ int main()
}
std::cout << "Switch value = [" << sFriend.Str() << "]" << std::endl;
- xbInt32 lZip;
+ xbInt32 lZip = 0;
if(( iRc = MyTable->GetLongField( "ZIPCODE", lZip )) < 0 ){
iErrorStop = 350;
throw iRc;
@@ -259,9 +259,15 @@ int main()
}
// example code to loop through the table
- for( xbUInt32 ul = 1; ul <= MyTable->GetRecordCount(); ul++ ){
+ xbUInt32 ulRecCnt;
+ if(( iRc = MyTable->GetRecordCnt( ulRecCnt )) != XB_NO_ERROR ){
+ iErrorStop = 430;
+ throw iRc;
+ }
+
+ for( xbUInt32 ul = 1; ul <= ulRecCnt; ul++ ){
if(( iRc = MyTable->GetRecord( ul )) != XB_NO_ERROR ){
- iErrorStop = 430;
+ iErrorStop = 440;
throw iRc;
}
// do something with the record here
@@ -271,9 +277,11 @@ int main()
/* Close database and associated indexes */
if(( iRc = MyTable->Close()) != XB_NO_ERROR ){
- iErrorStop = 440;
+ iErrorStop = 450;
throw iRc;
}
+ delete MyTable;
+
}
catch( xbInt16 iRc ){
diff --git a/src/include/xbconfig.h.in b/src/include/xbconfig.h.in
index f0d475a..f084038 100755
--- a/src/include/xbconfig.h.in
+++ b/src/include/xbconfig.h.in
@@ -11,6 +11,7 @@
#define PROJECT_RUNTIME_DIR "@PROJECT_RUNTIME_DIR@"
#define PROJECT_DATA_DIR "@PROJECT_DATA_DIR@"
#define PROJECT_LOG_DIR "@PROJECT_LOG_DIR@"
+#define PROJECT_TEMP_DIR "@PROJECT_TEMP_DIR@"
#define PROJECT_DFLT_LOGFILE "@CMAKE_SYSTEM_NAME@_@XB_PLATFORM@.xbLog.txt"
#define EXTRA_LIBS "@EXTRA_LIBS@"
#define CMAKE_RUNTIME_OUTPUT_DIRECTORY "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
@@ -69,11 +70,12 @@
#cmakedefine HAVE__FILENO_F
#cmakedefine HAVE_FOPEN_S_F
#cmakedefine HAVE__FSOPEN_F
-
#cmakedefine HAVE_FORK_F
#cmakedefine HAVE__FSEEKI64_F
#cmakedefine HAVE_FSEEKO_F
#cmakedefine HAVE_FTRUNCATE_F
+
+#cmakedefine HAVE_GETENV_S_F
#cmakedefine HAVE__LOCALTIME64_S_F
#cmakedefine HAVE_LOCKFILE_F
#cmakedefine HAVE_LOCKING_F
@@ -84,6 +86,7 @@
#cmakedefine HAVE__VSNPRINTF_S_F
#cmakedefine HAVE_VSPRINTF_S_F
+
#cmakedefine XB_PLATFORM_32
#cmakedefine XB_PLATFORM_64
#cmakedefine XB_DEBUG_SUPPORT
@@ -98,6 +101,7 @@
#cmakedefine XB_INDEX_SUPPORT
#cmakedefine XB_NDX_SUPPORT
#cmakedefine XB_MDX_SUPPORT
+#cmakedefine XB_TDX_SUPPORT
#cmakedefine XB_SQL_SUPPORT
#cmakedefine XB_INF_SUPPORT
#cmakedefine XB_FILTER_SUPPORT
diff --git a/src/include/xbcrix.cpp b/src/include/xbcrix.cpp
new file mode 100755
index 0000000..b89baaa
--- /dev/null
+++ b/src/include/xbcrix.cpp
@@ -0,0 +1,292 @@
+/* xbcrix.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+#ifdef XB_INDEX_SUPPORT
+xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
+
+ // std::cout << "CREATE INDEX " << sCmdLine << std::endl;
+
+ // expected format to create an Dbase 3, NDX index:
+ // CREATE INDEX ixname.ndx ON tablename.dbf ( EXPRESSION ) [ASSOCIATE]
+
+ // expected format to create an Dbase 4, tag on an MDX index:
+ // CREATE [UNIQUE] INDEX tagname ON tablename.dbf ( EXPRESSION ) [DESC] [FILTER .NOT. DELETED()]
+
+ // The ASSOCIATE parameter is specific to Xbase64 library, it is used to associate
+ // a non production (NDX) index file to a dbf file so it will be automatically
+ // opened with the dbf file whenever the dbf file is opened by the xbase64 routines.
+
+ // The [ASSOCIATE] parameter is not used with MDX production indices
+
+ // This method first looks for ".NDX" in the file name to determine if an NDX
+ // index should be created.
+ // if .NDX is not in the filename, it looks in the uda for "IXTYPE" for either
+ // NDX or MDX to detmermine the index type to create
+ // if IXTYPE not found, create an MDX tag
+
+ // The optional DESC parameter defines an entire index key as descending. This is
+ // different than other SQL implementations where specific fields can be descending.
+
+ // The optional FILTER parameter is specific to the XBASE64 library, is it used to
+ // assign a filter to a tag in an MDX style index. Everything to the right of
+ // the keyword FILTER is considered part of the filter.
+
+ // The original DBASE indices used to '+' to create an index on more than one field
+ // ie: FIELD1+FIELD2+FIELD3
+ // SQL uses commas: ie: FIELD1, FIELD2, FIELD3
+ // The Xbase library supports either '+' or ',' when creating mutli field indices.
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName;
+ xbString sIxName;
+ xbString sIxType;
+ xbUInt32 ulPos;
+ xbString sCmd = sCmdLine;
+ xbString sNode;
+ xbBool bUnique = xbFalse;
+ xbDbf * dbf = NULL;
+ xbBool bTableLocked = xbFalse;
+
+ try{
+
+ // drop off the first node
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.ToUpperCase();
+
+ if( sNode == "UNIQUE" ){
+ //std::cout << "unique ix\n";
+ bUnique = xbTrue;
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ }
+
+ // go past the index keyword
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // pull the index name off the cmd line
+ sIxName.ExtractElement( sCmd, ' ', 1, 0 );
+
+ #ifdef XB_NDX_SUPPORT
+ xbString sTemp = sIxName;
+ sTemp.ToUpperCase();
+ ulPos = sTemp.Pos( ".NDX" );
+ if(ulPos == (sTemp.Len() - 3) )
+ sIxType = "NDX";
+ #endif // XB_NDX_SUPPORT
+
+ if( sIxType == "" ){
+ if(( iRc = uda.GetTokenForKey( "IXTYPE", sIxType )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "NDX" ){
+ xbFile f( xbase );
+ f.SetFileName( sIxName );
+ if( f.FileExists()){
+
+ iErrorStop = 110;
+ iRc = XB_FILE_EXISTS;
+ throw iRc;
+ }
+ }
+ #endif // XB_NDX_SUPPORT
+
+ // skip past index name
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // skip past "ON"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // get the table name
+ ulPos = sCmd.Pos( '(' );
+ sTableName.ExtractElement( sCmd, '(', 1, 0 );
+ sTableName.Trim();
+
+ xbFile fDbf( xbase );
+ fDbf.SetFileName( sTableName );
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
+
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sTableName, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+ }
+
+ if( dbf == NULL ){
+ iErrorStop = 130;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+ sCmd.Ltrunc( ulPos );
+
+ //ulPos = sCmd.GetLastPos( ')' );
+ xbString sKeyExpression;
+ xbBool bDone = xbFalse;
+ xbUInt32 lPos = 1;
+ xbInt16 iParenCtr = 0;
+
+ while( !bDone && lPos < sCmd.Len()){
+ if( sCmd[lPos] == '(' ){
+ iParenCtr++;
+ sKeyExpression.Append( sCmd[lPos] );
+ } else if( sCmd[lPos] == ')' ){
+ if( iParenCtr > 0 ){
+ iParenCtr--;
+ sKeyExpression.Append( sCmd[lPos] );
+ } else {
+ bDone = xbTrue;
+ }
+ } else if( sCmd[lPos] == ',' && iParenCtr == 0 ){
+ sKeyExpression.Append( '+' );
+ } else if( sCmd[lPos] != ' ' ){
+ sKeyExpression.Append( sCmd[lPos] );
+ }
+ lPos++;
+ }
+
+ // std::cout << "Key Expression =[" << sKeyExpression << "]\n";
+ sCmd.Ltrunc( lPos );
+ sCmd.Trim();
+
+ xbBool bDesc = xbFalse;
+ // std::cout << "sCmd - looking for DESC [" << sCmd << "]\n";
+ if( sCmd.Len() > 4 ){
+ sNode = sCmd;
+ sNode.ToUpperCase();
+ ulPos = sNode.Pos( "DESC" );
+ if( ulPos > 0 ){
+ bDesc = xbTrue;
+ sCmd.Ltrunc( 4 );
+ sCmd.Trim();
+ std::cout << "Descending\n";
+ }
+ }
+
+ // std::cout << "sCmd - looking for FILTER stuff [" << sCmd << "]\n";
+ xbString sFilter;
+ if( sCmd.Len() > 6 ){
+ sNode = sCmd;
+ sNode.ToUpperCase();
+ ulPos = sNode.Pos( "FILTER" );
+ if( ulPos > 0 ){
+ sFilter = sCmd;
+ sFilter.Ltrunc( ulPos + 6 );
+ sFilter.Trim();
+ }
+ }
+ // std::cout << "sCmd - FILTER = [" << sFilter << "]\n";
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 140;
+ throw iRc;
+ } else {
+ bTableLocked = xbTrue;
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ xbIx *pIx;
+ void *vpTag;
+
+ if(( iRc = dbf->CreateTag( sIxType, sIxName, sKeyExpression, sFilter, bDesc, bUnique, xbFalse, &pIx, &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "NDX"){
+ sCmd.Ltrunc( ulPos );
+ sCmd.Trim();
+ if( sCmd.Len() > 0 ){
+ sCmd.ToUpperCase();
+ if( sCmd.Pos( "ASSOCIATE" )){
+ if(( iRc = dbf->AssociateIndex( "NDX", sIxName, 0 )) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ }
+ }
+ }
+ #endif // XB_NDX_SUPPORT
+
+ if(( iRc = pIx->Reindex( &vpTag )) != XB_NO_ERROR ){
+
+// if(( iRc = dbf->Reindex( 2, &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+
+
+ //std::cout << "Tag count = " << pIx->GetTagCount() << "\n";
+ // s = pIx->GetTagName( &vpTag );
+ // std::cout << "tagname = [" << s.Str() << "]\n";
+
+
+ #ifdef XB_LOCKING_SUPPORT
+ if( bTableLocked ){
+ if(( iRc = dbf->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc;
+ } else {
+ bTableLocked = xbFalse;
+ }
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlCreateIndex() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ #ifdef XB_LOCKING_SUPPORT
+ if( bTableLocked && dbf )
+ dbf->LockTable( XB_UNLOCK );
+ #endif // XB_LOCKING_SUPPORT
+
+ return iRc;
+}
+#endif // XB_INDEX_SUPPORT
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/include/xbdate.h b/src/include/xbdate.h
index 8dff463..e914d65 100755
--- a/src/include/xbdate.h
+++ b/src/include/xbdate.h
@@ -66,6 +66,7 @@ class XBDLLEXPORT xbDate : public xbSsv {
xbDate( const char * Date8 );
xbDate( const xbString &Date8 );
xbDate( xbInt32 lJulDate );
+ xbDate( xbUInt16 iInit ); // Constructor used to set the static variables, also defaults to sysdate
~xbDate();
void operator=( const xbDate &d );
@@ -96,6 +97,7 @@ class XBDLLEXPORT xbDate : public xbSsv {
const char *Str() const;
xbBool IsLeapYear( xbInt16 iYear ) const;
xbBool IsLeapYear() const;
+ xbBool IsNull() const;
xbInt32 JulianDays() const;
xbInt16 JulToDate8( xbInt32 lJulDate );
xbInt16 LastDayOfMonth();
@@ -111,7 +113,8 @@ class XBDLLEXPORT xbDate : public xbSsv {
private:
void SetDateTables();
- xbString sDate8; /* CCYYMMDD date format ie; 20140718 */
+ xbString sDate8; // CCYYMMDD date format ie; 20140718
+ // Null date is identified by sDate.Len() < 8
static int iAggregatedDaysInMonths[2][13];
static int iDaysInMonths[2][13];
diff --git a/src/include/xbdbf.h b/src/include/xbdbf.h
index 16799f2..fe24e72 100755
--- a/src/include/xbdbf.h
+++ b/src/include/xbdbf.h
@@ -164,7 +164,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbInt16 DeleteAll ( xbInt16 iOption );
virtual xbInt16 DeleteAllRecords ();
virtual xbInt16 DeleteRecord ();
- virtual xbInt16 DumpHeader ( xbInt16 iOption ) const;
+ virtual xbInt16 DumpHeader ( xbInt16 iOption );
virtual xbInt16 DumpRecord ( xbUInt32 ulRecNo, xbInt16 iOutputDest = 0, xbInt16 iOutputFmt = 0 );
virtual xbInt16 GetAutoCommit () const;
virtual xbInt16 GetAutoCommit ( xbInt16 iOption ) const;
@@ -186,7 +186,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbInt16 GetPrevRecord ( xbInt16 iOption );
virtual xbInt16 GetRecord ( xbUInt32 ulRecNo );
- virtual xbUInt32 GetRecordCount ();
+ // virtual xbUInt32 GetRecordCount ();
virtual xbInt16 GetRecordCnt ( xbUInt32 & ulRecCnt );
virtual char * GetRecordBuf ( xbInt16 iOpt = 0 ) const;
@@ -207,7 +207,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbInt16 PutRecord (); // Put record to current location
virtual xbInt16 PutRecord ( xbUInt32 ulRecNo );
- virtual xbInt16 ReadHeader ( xbInt16 iFilePositionOption, xbInt16 iReadOption );
+// virtual xbInt16 ReadHeader ( xbInt16 iFilePositionOption, xbInt16 iReadOption );
virtual xbInt16 RecordDeleted ( xbInt16 iOpt = 0 ) const;
virtual xbInt16 Rename ( const xbString sNewName ) = 0;
@@ -251,7 +251,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbInt16 GetLongField( xbInt16 iFieldNo, xbInt32 &lFieldValue ) const;
virtual xbInt16 GetLongField( const xbString &sFieldName, xbInt32 &lFieldValue ) const;
virtual xbInt16 PutLongField( xbInt16 iFieldNo, xbInt32 lFieldValue );
- virtual xbInt16 PutLongField( const xbString &sFieldNo, xbInt32 lFieldValue );
+ virtual xbInt16 PutLongField( const xbString &sFieldName, xbInt32 lFieldValue );
virtual xbInt16 GetULongField( xbInt16 iFieldNo, xbUInt32 &lFieldValue ) const;
virtual xbInt16 GetULongField( const xbString &sFieldName, xbUInt32 &lFieldValue ) const;
@@ -274,6 +274,10 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbInt16 PutDateField( xbInt16 iFieldNo, const xbDate &dt );
virtual xbInt16 PutDateField( const xbString &sFieldName, const xbDate &dt );
+ virtual xbInt16 GetNullSts( xbInt16 iFieldNo, xbBool &bIsNull ) const;
+ virtual xbInt16 GetNullSts( const xbString &sFieldName, xbBool &bIsNull ) const;
+ virtual xbInt16 GetNullSts( xbInt16 iFieldNo, xbBool &bIsNull, xbInt16 iRecBufSw ) const;
+
#ifdef XB_MEMO_SUPPORT
@@ -282,7 +286,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
virtual xbUInt32 GetCreateMemoBlockSize() const;
virtual xbInt16 GetMemoField ( xbInt16 iFldNo, xbString &sMemoData );
virtual xbInt16 GetMemoField ( const xbString & sFldName, xbString &sMemoData );
- virtual xbInt16 GetMemoFieldLen ( xbInt16 iFldNo, xbUInt32 &ullMemoFieldLen );
+ virtual xbInt16 GetMemoFieldLen ( xbInt16 iFldNo, xbUInt32 &ulMemoFieldLen );
virtual xbInt16 GetMemoFieldLen ( const xbString & sFldName, xbUInt32 &ulMemoFieldLen );
virtual xbBool MemoFieldExists ( xbInt16 iFieldNo ) const;
virtual xbBool MemoFieldExists ( const xbString &sFieldName ) const;
@@ -347,7 +351,7 @@ class XBDLLEXPORT xbDbf : public xbFile {
xbLinkListNode<xbTag *> *GetTagList () const;
virtual xbInt16 OpenIndex( const xbString &sIxType, const xbString &sIndexName );
- virtual xbInt16 Reindex( xbInt16 iTagOpt );
+ virtual xbInt16 Reindex( xbInt16 iTagOpt = 0, xbInt16 iErrorOpt = 1, xbIx **pIx = NULL, void **vpTag = NULL );
virtual xbInt16 SetCurTag( const xbString &sTagName );
virtual void SetCurTag( const xbString &sIxType, xbIx *pIx, void *vpTag );
@@ -373,14 +377,20 @@ class XBDLLEXPORT xbDbf : public xbFile {
#ifdef XB_INDEX_SUPPORT
friend class xbIx;
friend class xbIxMdx;
+ friend class xbIxTdx;
xbInt16 AddIndex( xbIx *ix, const xbString &sFmt );
void ClearTagList();
xbInt16 RemoveIndex( xbIx * ix );
void UpdateSchemaIxFlag( xbInt16 iFldNo, unsigned char cVal );
+
+
virtual xbInt16 UpdateTagList ();
#endif // XB_INDEX_SUPPORT
+ virtual xbInt16 ReadHeader ( xbInt16 iFilePositionOption, xbInt16 iReadOption );
+
+
#ifdef XB_INF_SUPPORT
virtual xbInt16 GetInfFileName( xbString &sNdxIdxFileName );
#endif // XB_INF_SUPPORT
diff --git a/src/include/xbexp.h b/src/include/xbexp.h
index 96413ac..4792b0e 100755
--- a/src/include/xbexp.h
+++ b/src/include/xbexp.h
@@ -22,6 +22,7 @@ Email Contact:
// #pragma interface
// #endif
+#define XB_NULL_DATE 21474835648
#ifdef XB_FUNCTION_SUPPORT
diff --git a/src/include/xbexpnode.h b/src/include/xbexpnode.h
index f50d9eb..51efa9b 100755
--- a/src/include/xbexpnode.h
+++ b/src/include/xbexpnode.h
@@ -103,7 +103,7 @@ class XBDLLEXPORT xbExpNode {
xbUInt32 ulResultLen; // for string results, accumulated length of character operations
// includes the sum of all nodes under this + this
// date = 8, numeric = 4, logical = 1
- xbInt16 iWeight; // used for buildign the tree of nodes, assigned to operators
+ xbInt16 iWeight; // used for building the tree of nodes, assigned to operators
// the higher the number, the lower it goes on the tree
};
diff --git a/src/include/xbfile.h b/src/include/xbfile.h
index af04e98..e346a75 100755
--- a/src/include/xbfile.h
+++ b/src/include/xbfile.h
@@ -56,108 +56,109 @@ This class could be used if you want to write a platform independent program tha
class XBDLLEXPORT xbFile : public xbSsv {
public:
- // xbFile();
xbFile( xbXBase * x );
-
~xbFile();
- xbInt16 SetHomeFolders();
-
- xbInt16 CreateUniqueFileName( const xbString &sDirIn, const xbString &sExtIn, xbString &sFqnOut );
- xbInt16 CreateUniqueFileName( const xbString &sDirIn, const xbString &sExtIn, xbString &sFqnOut, xbInt16 iOption );
-
const xbString& GetDirectory() const;
const xbString& GetFileName() const;
const xbString& GetFqFileName() const;
- void SetDirectory ( const xbString &sDirectory);
- void SetFileName ( const xbString &sFileName );
- void SetFqFileName( const xbString &sFqName );
- xbUInt32 GetBlockSize () const;
- xbInt16 SetBlockSize ( xbUInt32 ulBlockSize );
+ xbInt16 CreateUniqueFileName( const xbString &sDirIn, const xbString &sExtIn, xbString &sFqnOut, xbInt16 iOption = 0 );
+
+ xbInt16 DetermineXbaseTableVersion( unsigned char cFileTypeByte ) const;
+ xbInt16 DetermineXbaseMemoVersion( unsigned char cFileTypeByte ) const;
+
+ xbDouble eGetDouble ( const char *p ) const;
+ xbInt32 eGetInt32 ( const char *p ) const;
+ xbUInt32 eGetUInt32 ( const char *p ) const;
+ xbInt16 eGetInt16 ( const char *p ) const;
+ xbUInt16 eGetUInt16 ( const char *p ) const;
+ void ePutDouble ( char *p, xbDouble d );
+ void ePutInt32 ( char *p, xbInt32 l );
+ void ePutUInt32 ( char *p, xbUInt32 ul );
+ void ePutInt16 ( char *p, xbInt16 s );
+ void ePutUInt16 ( char *p, xbUInt16 s );
+
+ xbBool FileExists () const;
+ xbBool FileExists ( xbInt16 iOption ) const;
+ xbBool FileExists ( const xbString &sFileName ) const;
+ xbBool FileExists ( const xbString &sFileName, xbInt16 iOption ) const;
+ xbBool FileIsOpen () const;
- xbInt16 GetOpenMode () const;
- xbInt16 GetShareMode () const;
+ xbUInt32 GetBlockSize () const;
xbInt16 GetFileDirPart ( xbString &sFileDirPartOut ) const;
xbInt16 GetFileDirPart ( const xbString &sCompleteFileNameIn, xbString &sFileDirPartOut ) const;
xbInt16 GetFileExtPart ( xbString &sFileExtPartOut ) const;
xbInt16 GetFileExtPart ( const xbString &sCompleteFileNameIn, xbString &sFileExtPartOut ) const;
+ xbInt16 GetFileMtime ( time_t &mtime );
xbInt16 GetFileNamePart( xbString &sFileNamePartOut ) const;
xbInt16 GetFileNamePart( const xbString &sCompleteFileNameIn, xbString &sFileNamePartOut ) const;
+ xbInt16 GetFileSize ( xbUInt64 &ullFileSize );
xbInt16 GetFileType ( xbString &sFileType ) const;
+
+ xbInt16 GetOpenMode () const;
+ xbInt16 GetShareMode () const;
+
+
xbInt16 GetXbaseFileTypeByte( const xbString &sFileName, xbInt16 &iVersion );
xbInt16 GetXbaseFileTypeByte( const xbString &sFileName, unsigned char &cFileTypeByte );
xbInt16 GetXbaseFileTypeByte( const xbString &sFileName, unsigned char &cFileTypeByte, xbInt16 &iVersion );
- xbInt16 DetermineXbaseTableVersion( unsigned char cFileTypeByte ) const;
- xbInt16 DetermineXbaseMemoVersion( unsigned char cFileTypeByte ) const;
- xbBool FileExists () const;
- xbBool FileExists ( xbInt16 iOption ) const;
- xbBool FileExists ( const xbString &sFileName ) const;
- xbBool FileExists ( const xbString &sFileName, xbInt16 iOption ) const;
+ xbInt16 NameSuffixMissing( const xbString &sFileName, xbInt16 iOption ) const;
- xbBool FileIsOpen () const;
+ xbInt16 ReadBlock ( xbUInt32 ulBlockNo, size_t readSize, void *buf );
+ xbInt16 ReadBlock ( xbUInt32 ulBlockNo, xbUInt32 ulBlockSize, size_t readSize, void *buf );
- xbInt16 ReadBlock ( xbUInt32 ulBlockNo, size_t readSize, void *buf );
- xbInt16 ReadBlock ( xbUInt32 ulBlockNo, xbUInt32 ulBlockSize, size_t readSize, void *buf );
- xbInt16 WriteBlock( xbUInt32 ulBlockNo, size_t writeSize, void *buf );
-
- xbInt16 GetFileSize( xbUInt64 &ullFileSize );
- xbInt16 GetFileMtime( time_t &mtime );
-
- xbDouble eGetDouble( const char *p ) const;
- xbInt32 eGetInt32 ( const char *p ) const;
- xbUInt32 eGetUInt32( const char *p ) const;
- xbInt16 eGetInt16 ( const char *p ) const;
- xbUInt16 eGetUInt16( const char *p ) const;
- void ePutDouble( char *p, xbDouble d );
- void ePutInt32 ( char *p, xbInt32 l );
- void ePutUInt32( char *p, xbUInt32 ul );
- void ePutInt16 ( char *p, xbInt16 s );
- void ePutUInt16( char *p, xbUInt16 s );
-
- xbInt16 xbFclose ();
- xbInt16 xbFeof ();
- xbInt16 xbFflush ();
- xbInt16 xbFgetc ( xbInt32 &c );
- xbInt16 xbFgetc ( char &c );
+ xbInt16 SetBlockSize ( xbUInt32 ulBlockSize );
+ void SetDirectory ( const xbString &sDirectory);
+ void SetFileName ( const xbString &sFileName );
+ void SetFqFileName ( const xbString &sFqName );
+ xbInt16 SetHomeFolders();
- #ifdef XB_LOCKING_SUPPORT
- xbInt16 xbLock ( xbInt16 iFunction, xbInt64 llOffset, size_t stLen );
- xbInt16 GetLockRetryCount() const;
- void SetLockRetryCount( xbInt16 iLockRetries );
- #endif
+ xbInt16 WriteBlock ( xbUInt32 ulBlockNo, size_t writeSize, void *buf );
- xbInt16 xbFopen ( xbInt16 iOpenMode );
- xbInt16 xbFopen ( const xbString &sOpenMode, xbInt16 iShareMode );
- xbInt16 xbFopen ( xbInt16 iOpenMode, xbInt16 iShareMode );
- xbInt16 xbFopen ( const xbString &sMode, const xbString &sFileName, xbInt16 iShareMode );
+ xbInt16 xbFclose ();
+ xbInt16 xbFeof ();
+ xbInt16 xbFflush ();
+ xbInt16 xbFgetc ( xbInt32 &c );
+ xbInt16 xbFgetc ( char &c );
+ xbInt16 xbFgets ( size_t lSize, xbString &sLine );
- xbInt16 xbFputc ( xbInt32 c );
- xbInt16 xbFputc ( xbInt32 c, xbInt32 iNoTimes );
- xbInt16 xbFputs ( const xbString &s );
- xbInt16 xbFread ( void *ptr, size_t size, size_t nmemb );
- xbInt16 xbFgets ( size_t lSize, xbString &sLine );
- size_t xbFtell ();
- xbInt16 xbFseek ( xbInt64 llOffset, xbInt32 whence );
+ xbInt16 xbFopen ( xbInt16 iOpenMode );
+ xbInt16 xbFopen ( const xbString &sOpenMode, xbInt16 iShareMode );
+ xbInt16 xbFopen ( xbInt16 iOpenMode, xbInt16 iShareMode );
+ xbInt16 xbFopen ( const xbString &sMode, const xbString &sFileName, xbInt16 iShareMode );
+ xbInt16 xbFputc ( xbInt32 c );
+ xbInt16 xbFputc ( xbInt32 c, xbInt32 iNoTimes );
+ xbInt16 xbFputs ( const xbString &s );
+ xbInt16 xbFread ( void *ptr, size_t size, size_t nmemb );
+ xbInt16 xbFseek ( xbInt64 llOffset, xbInt32 whence );
+ size_t xbFtell ();
void xbFTurnOffFileBuffering();
- xbInt16 xbFwrite ( const void *ptr, size_t lSize, size_t lNmemb );
+
+ xbInt16 xbReadUntil ( const char cDelim, xbString &sOut );
+ xbInt16 xbRemove ( const xbString &sFileName, xbInt16 iOption );
+ xbInt16 xbRemove ( const xbString &sFileName );
+ xbInt16 xbRemove ();
- xbInt16 xbReadUntil ( const char cDelim, xbString &sOut );
- xbInt16 xbRemove ( const xbString &sFileName, xbInt16 iOption );
- xbInt16 xbRemove ( const xbString &sFileName );
- xbInt16 xbRemove ();
+ xbInt16 xbRename ( const xbString &sOldName, const xbString &sNewName );
+ void xbRewind ();
- xbInt16 xbRename ( const xbString &sOldName, const xbString &sNewName );
- void xbRewind ();
+ xbInt16 xbFwrite ( const void *ptr, size_t lSize, size_t lNmemb );
- xbInt16 xbTruncate ( xbInt64 llSize );
- xbInt16 NameSuffixMissing( const xbString &sFileName, xbInt16 iOption ) const;
+ xbInt16 xbTruncate ( xbInt64 llSize );
+
+
+ #ifdef XB_LOCKING_SUPPORT
+ xbInt16 xbLock ( xbInt16 iFunction, xbInt64 llOffset, size_t stLen );
+ xbInt16 GetLockRetryCount() const;
+ void SetLockRetryCount( xbInt16 iLockRetries );
+ #endif
#ifdef XB_DEBUG_SUPPORT
xbInt16 DumpBlockToDisk( xbUInt32 ulBlockNo, size_t lBlockSize );
diff --git a/src/include/xbindex.h b/src/include/xbindex.h
index b42f76e..959562c 100755
--- a/src/include/xbindex.h
+++ b/src/include/xbindex.h
@@ -167,7 +167,6 @@ class XBDLLEXPORT xbIx : public xbFile {
virtual xbBool GetSortOrder( void *vpTag ) const = 0;
virtual xbInt16 Open( const xbString &sFileName );
- virtual xbInt16 Reindex( void **vpTag ) = 0;
virtual xbInt16 SetCurTag( xbInt16 iTagNo ) = 0;
virtual xbInt16 SetCurTag( xbString &sTagName ) = 0;
virtual void SetCurTag( void * vpCurTag );
@@ -176,6 +175,10 @@ class XBDLLEXPORT xbIx : public xbFile {
virtual void TestStub( char *s, void *vpTag ) {};
+
+ virtual xbInt16 Reindex( void **vpTag ) = 0;
+
+
#ifdef XB_DEBUG_SUPPORT
virtual xbInt16 DumpFreeBlocks( xbInt16 iOpt = 0 ) { return XB_NO_ERROR; }
virtual xbInt16 DumpHeader( xbInt16 iDestOpt = 0, xbInt16 iFmtOpt = 0 ) = 0;
@@ -199,17 +202,13 @@ class XBDLLEXPORT xbIx : public xbFile {
virtual xbInt16 CreateKeys( xbInt16 iOpt );
virtual xbInt16 CreateKey( void * vpTag, xbInt16 iOpt ) = 0;
virtual xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo ) = 0;
-// virtual xbInt16 DeleteKeys( xbUInt32 ulRecNo );
virtual xbInt16 DeleteKeys();
virtual xbInt16 DeleteKey( void *vpTag ) = 0;
-
virtual xbInt16 DeleteTag( void *vpTag ) = 0;
-
virtual xbInt16 FindKeyForCurRec( void *vpTag ) = 0;
virtual xbIxNode *FreeNodeChain( xbIxNode *np );
virtual xbInt16 GetBlock( void *vpTag, xbUInt32 ulBlockNo, xbInt16 iOpt, xbUInt32 ulAddlBuf = 0 );
-// virtual xbBool GetIndexUpdated() const = 0;
virtual xbInt32 GetKeyCount( xbIxNode *npNode ) const;
virtual char *GetKeyData( xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iKeyItemLen ) const;
virtual xbInt16 GetKeySts( void *vpTag ) const = 0;
@@ -217,9 +216,9 @@ class XBDLLEXPORT xbIx : public xbFile {
virtual xbInt16 InsertNodeL( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 uiPtr ) = 0;
virtual xbInt16 InsertNodeI( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, xbUInt32 uiPtr ) = 0;
virtual xbInt16 KeyExists( void * ) = 0;
-// virtual xbInt16 KeyUpdated( void *vpTag ) const = 0;
virtual void NodeFree( xbIxNode * ixNode );
virtual xbInt16 ReadHeadBlock( xbInt16 iOpt = 0 ) = 0;
+ // virtual xbInt16 Reindex( void **vpTag ) = 0;
virtual void SetDbf( xbDbf *dbf );
virtual xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr ) = 0;
virtual xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr ) = 0;
@@ -267,7 +266,6 @@ struct XBDLLEXPORT xbNdxTag {
char *cpKeyBuf; // key buffer, for searches and adds
char *cpKeyBuf2; // key buffer, for deletes
xbString sTagName; // tag name - is the file name without the extension
-// xbInt16 iKeyUpdated; // key updated? set in method KeyUpdated, checked in AddKey and DeleteKey routines
xbBool bFoundSts; // key found? used to determine if new key should be added in XB_EMULATE_DBASE mode in AddKey
@@ -307,7 +305,6 @@ class XBDLLEXPORT xbIxNdx : public xbIx {
~xbIxNdx();
xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt );
xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
-// xbInt16 DeleteTag( void *vpTag );
xbInt16 FindKey( void *vpTag, const void *vpKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
xbInt16 GetFirstKey( void *vpTag, xbInt16 iRetrieveSw );
@@ -326,12 +323,9 @@ class XBDLLEXPORT xbIxNdx : public xbIx {
xbInt16 GetTagCount() const;
xbBool GetUnique( void *vpTag = NULL ) const;
xbBool GetSortOrder( void *vpTag ) const;
- xbInt16 Reindex( void **vpTag );
xbInt16 SetCurTag( xbInt16 iTagNo );
xbInt16 SetCurTag( xbString &sTagName );
-
-
#ifdef XB_DEBUG_SUPPORT
xbInt16 DumpTagBlocks( xbInt16 iOpt = 1, void *vpTag = NULL );
xbInt16 DumpHeader( xbInt16 iOpt = 0, xbInt16 iFmt = 0 );
@@ -340,6 +334,9 @@ class XBDLLEXPORT xbIxNdx : public xbIx {
xbInt16 DumpNode( void * vpTag, xbIxNode * pNode, xbInt16 iOption ) const;
#endif
+ xbInt16 Reindex( void **vpTag );
+
+
protected:
friend class xbDbf;
xbInt16 AddKey( void *vpTag, xbUInt32 ulRecNo );
@@ -349,20 +346,16 @@ class XBDLLEXPORT xbIxNdx : public xbIx {
xbInt16 CreateKey( void * vpTag, xbInt16 iOpt );
xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo );
xbInt16 DeleteKey( void *vpTag );
-
xbInt16 DeleteTag( void *vpTag );
-
xbInt16 FindKeyForCurRec( void *vpTag );
-// xbBool GetIndexUpdated() const;
xbInt16 GetKeyTypeN( const void *vpTag ) const;
xbInt16 GetKeySts( void *vpTag ) const;
xbInt16 GetLastKey( xbUInt32 ulNodeNo, void *vpTag, xbInt16 iRetrieveSw = 1 );
xbInt16 InsertNodeI( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, xbUInt32 uiPtr );
xbInt16 InsertNodeL( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 uiPtr );
xbInt16 KeyExists( void *vpTag = NULL );
-// xbBool KeyFiltered( void *vpTag ) const;
-// xbInt16 KeyUpdated( void *vpTag ) const;
xbInt16 ReadHeadBlock(xbInt16 iOpt); // read the header node of the disk NDX file
+// xbInt16 Reindex( void **vpTag );
xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr );
xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
xbInt16 UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo = 0 );
@@ -377,7 +370,6 @@ class XBDLLEXPORT xbIxNdx : public xbIx {
xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const;
xbInt16 KeySetPosAdd( xbNdxTag *npTag, xbUInt32 ulAddKeyRecNo );
xbInt16 KeySetPosDel( xbNdxTag *npTag );
- // void SetCurNode( void *vpTag, xbIxNode *np );
xbNdxTag *ndxTag;
};
@@ -409,7 +401,6 @@ struct XBDLLEXPORT xbMdxTag {
// one unused byte fits here
char cTag11; // dbase sets to 0x1B
-
xbInt16 iKeyLen;
xbInt16 iKeysPerBlock;
xbInt16 iSecKeyType;
@@ -418,10 +409,8 @@ struct XBDLLEXPORT xbMdxTag {
char cSerialNo; // Increments +1 for each tag update
char cUnique;
xbString *sKeyExp; // Key expression
-
char cHasFilter; // 0x00 or 0x01
char cHasKeys; // 0x00 or 0x01
-
xbUInt32 ulLeftChild; // dbase 7 sets this to the root page on tag creation
xbUInt32 ulRightChild; // dbase 7 sets this to the root page on tag creation
@@ -441,12 +430,6 @@ struct XBDLLEXPORT xbMdxTag {
char *cpKeyBuf; // key buffer
char *cpKeyBuf2; // key buffer
-// xbBool iKeyUpdated; // key updated? set in method CreateKey, checked in AddKey and DeleteKey routines
- // 0 - no update
- // 1 - Add
- // 2 - Update
- // 3 - Delete
-// xbBool bKeyFiltered; // key filtered? True if included key, False if excluded key. Set in method CreateKey, checked in AddKey and DeleteKey routines
xbString *sTagName; // string tag name
@@ -469,59 +452,67 @@ class XBDLLEXPORT xbIxMdx : public xbIx {
public:
xbIxMdx( xbDbf * d );
~xbIxMdx();
- xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt );
- xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
-// xbInt16 DeleteTag( void *vpTag );
- xbInt16 FindKey( void *vpTag, const void *vKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
- xbInt16 FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw );
- xbInt16 GetFirstKey( void *vpTag, xbInt16 lRetrieveSw );
- xbString &GetKeyExpression( const void *vpTag ) const;
- xbString &GetKeyFilter( const void *vpTag ) const;
- char GetKeyType( const void *vpTag ) const;
- xbInt16 GetLastKey( void *vpTag, xbInt16 lRetrieveSw );
- xbInt16 GetNextKey( void *vpTag, xbInt16 lRetrieveSw );
- xbInt16 GetPrevKey( void *vpTag, xbInt16 lRetrieveSw );
- xbBool GetReuseEmptyNodesSw() const;
- xbBool GetSortOrder( void *vpTag ) const;
- void *GetTag( xbInt16 iTagNo ) const;
- void *GetTag( xbString &sTagName ) const;
- xbInt16 GetTagCount() const;
+ virtual xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt );
+ virtual xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
+ virtual xbInt16 FindKey( void *vpTag, const void *vKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw );
+ virtual xbInt16 GetFirstKey( void *vpTag, xbInt16 lRetrieveSw );
+ virtual xbString &GetKeyExpression( const void *vpTag ) const;
+ virtual xbString &GetKeyFilter( const void *vpTag ) const;
+ virtual char GetKeyType( const void *vpTag ) const;
+ virtual xbInt16 GetLastKey( void *vpTag, xbInt16 lRetrieveSw );
+ virtual xbInt16 GetNextKey( void *vpTag, xbInt16 lRetrieveSw );
+ virtual xbInt16 GetPrevKey( void *vpTag, xbInt16 lRetrieveSw );
+ virtual xbBool GetReuseEmptyNodesSw() const;
+ virtual xbBool GetSortOrder( void *vpTag ) const;
+ virtual void *GetTag( xbInt16 iTagNo ) const;
+ virtual void *GetTag( xbString &sTagName ) const;
+ virtual xbInt16 GetTagCount() const;
- xbString &GetTagName( void *vpTag ) const;
- const char * GetTagName( void *vpTag, xbInt16 iOpt ) const;
- void GetTagName( void *vpTag, xbString &sTagName );
+ virtual xbString &GetTagName( void *vpTag ) const;
+ virtual const char * GetTagName( void *vpTag, xbInt16 iOpt ) const;
+ virtual void GetTagName( void *vpTag, xbString &sTagName );
+
+ virtual xbInt16 GetUnique( void *vpTag ) const;
+ virtual xbInt16 SetCurTag( xbInt16 iTagNo );
+ virtual xbInt16 SetCurTag( xbString &sTagName );
+ void SetReuseEmptyNodesSw( xbBool bReuse );
+
+ void TestStub( char *s, void *vpTag );
- xbInt16 GetUnique( void *vpTag ) const;
- xbInt16 Reindex( void **vpTag );
- xbInt16 SetCurTag( xbInt16 iTagNo );
- xbInt16 SetCurTag( xbString &sTagName );
- void SetReuseEmptyNodesSw( xbBool bReuse );
- void TestStub( char *s, void *vpTag );
+ virtual xbInt16 Reindex( void **vpTag );
+
protected:
friend class xbDbf;
xbInt16 AddKey( void *vpTag, xbUInt32 ulRecNo );
xbIxNode *AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt32 ulBlock2 );
+ void CalcBtreePointers();
+ char CalcTagKeyFmt( xbExp &exp );
+
xbInt16 CheckForDupKey( void *vpTag );
- xbInt16 Close();
+ virtual xbInt16 Close();
xbInt16 CreateKey( void * vpTag, xbInt16 iOpt );
xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo );
xbInt16 DeleteKey( void *vpTag );
- xbInt16 DeleteTag( void *vpTag );
+ virtual xbInt16 DeleteTag( void *vpTag );
xbInt16 FindKeyForCurRec( void *vpTag );
xbInt16 GetKeySts( void *vpTag ) const;
xbInt16 GetLastKey( xbUInt32 ulBlockNo, void *vpTag, xbInt16 lRetrieveSw );
void *GetTagTblPtr() const;
+
+ xbInt16 HarvestTagNodes( xbMdxTag *mpTag, xbBool bRecycleRoot = xbFalse );
void Init( xbInt16 iOpt = 0 );
xbInt16 InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xbUInt32 uiPtr );
xbInt16 InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
xbInt16 KeyExists( void * );
xbInt16 LoadTagTable();
xbInt16 ReadHeadBlock(xbInt16 iOpt); // read the header node of the disk file
+ //virtual xbInt16 Reindex( void **vpTag );
xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr );
xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
xbInt16 UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo = 0 );
@@ -535,34 +526,10 @@ class XBDLLEXPORT xbIxMdx : public xbIx {
void DumpIxNodeChain( void *vpTag, xbInt16 iOutputOpt ) const;
#endif
- private:
- xbInt16 AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight );
- void AppendNodeChain( void *vpTag, xbIxNode *npNode );
- xbUInt32 BlockToPage( xbUInt32 ulBlockNo );
- void CalcBtreePointers();
- char CalcTagKeyFmt( xbExp &exp );
- char CalcTagFwdThread1();
- char CalcTagFwdThread2();
- xbMdxTag *ClearTagTable();
- xbInt16 DumpBlock( xbInt16 iOpt, xbUInt32 ulBlockNo, xbMdxTag * mpTag );
- xbInt16 GetDbfPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulDbfPtr ) const;
- xbInt16 GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulKeyPtr ) const;
- xbInt16 GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpKeyBuf );
- xbInt16 HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iOpt, xbBool bHarvestRoot = xbFalse );
- xbInt16 HarvestTagNodes( xbMdxTag *mpTag, xbBool bRecycleRoot = xbFalse );
- xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const;
- xbInt16 KeySetPosAdd( xbMdxTag *mpTag, xbUInt32 ulAddKeyRecNo );
- xbInt16 KeySetPosDel( xbMdxTag *mpTag );
- xbInt16 LoadTagDetail( xbInt16 iOption, xbMdxTag *tte );
- xbUInt32 PageToBlock( xbUInt32 ulPageNo );
- xbInt16 TagSerialNo( xbInt16 iOption, xbMdxTag *mpTag );
- xbInt16 UpdateTagSize( xbMdxTag *mpTag, xbUInt32 ulTagSz );
- #ifdef XB_DEBUG_SUPPORT
- xbInt16 PrintKey( void *vpTag, xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iDepth, char cType, xbInt16 iOutputOpt );
- #endif
+ xbMdxTag *mdxTagTbl;
- // MDX File Header Fields
+// MDX File Header Fields
char cVersion;
char cCreateYY;
char cCreateMM;
@@ -588,18 +555,59 @@ class XBDLLEXPORT xbIxMdx : public xbIx {
// end of MDX Header fields
-
- xbMdxTag *mdxTagTbl;
-
xbBool bReuseEmptyNodes; // Reuese empty MDX nodes when all keys deleted?
// DBase 7.x and MS ODBC drivers do not reuse empty nodes, leaves them stranded in the file
// Codebase 6.x reuses empty nodes.
// Setting this to True will reuse empty nodes in the same manner Codebase 6.x reuses them.
+
+ private:
+ xbInt16 AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight );
+ void AppendNodeChain( void *vpTag, xbIxNode *npNode );
+ xbUInt32 BlockToPage( xbUInt32 ulBlockNo );
+ xbMdxTag *ClearTagTable();
+ xbInt16 DumpBlock( xbInt16 iOpt, xbUInt32 ulBlockNo, xbMdxTag * mpTag );
+ xbInt16 GetDbfPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulDbfPtr ) const;
+ xbInt16 GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulKeyPtr ) const;
+ xbInt16 GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpKeyBuf );
+ xbInt16 HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iOpt, xbBool bHarvestRoot = xbFalse );
+ xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const;
+ xbInt16 KeySetPosAdd( xbMdxTag *mpTag, xbUInt32 ulAddKeyRecNo );
+ xbInt16 KeySetPosDel( xbMdxTag *mpTag );
+ xbInt16 LoadTagDetail( xbInt16 iOption, xbMdxTag *tte );
+ xbUInt32 PageToBlock( xbUInt32 ulPageNo );
+ xbInt16 TagSerialNo( xbInt16 iOption, xbMdxTag *mpTag );
+ xbInt16 UpdateTagSize( xbMdxTag *mpTag, xbUInt32 ulTagSz );
+
+ #ifdef XB_DEBUG_SUPPORT
+ xbInt16 PrintKey( void *vpTag, xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iDepth, char cType, xbInt16 iOutputOpt );
+ #endif
+
+
+ };
+ #endif /* XB_MDX_SUPPORT */
+
+
+#ifdef XB_TDX_SUPPORT
+
+class XBDLLEXPORT xbIxTdx : public xbIxMdx {
+ public:
+ xbIxTdx( xbDbf * d );
+ ~xbIxTdx();
+
+ xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
+
+ protected:
+ friend class xbDbf;
+ xbInt16 Close();
+ xbInt16 DeleteTag( void *vpTag );
+
+ private:
};
-#endif /* XB_MDX_SUPPORT */
-
-} /* namespace xb */
-#endif /* XB_INDEX_SUPPORT */
-#endif /* __XB_INDEX_H__ */
+#endif /* XB_TDX_SUPPORT */
+
+
+ } /* namespace xb */
+ #endif /* XB_INDEX_SUPPORT */
+#endif /* __XB_INDEX_H__ */
diff --git a/src/include/xbindex.h.nope b/src/include/xbindex.h.nope
new file mode 100755
index 0000000..b42f76e
--- /dev/null
+++ b/src/include/xbindex.h.nope
@@ -0,0 +1,605 @@
+/* xbindex.h
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014, 2018, 2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+
+#ifndef __XB_INDEX_H__
+#define __XB_INDEX_H__
+
+#ifdef XB_INDEX_SUPPORT
+
+
+#define XB_ADD_KEY 1
+#define XB_UPD_KEY 2
+#define XB_DEL_KEY 3
+
+namespace xb{
+
+
+
+///@cond DOXYOFF
+// structure for index nodes, each node contains information regarding one block
+struct XBDLLEXPORT xbIxNode {
+ xbIxNode *npPrev; // pointer to previous node in chain
+ xbIxNode *npNext; // pointer to next node in chain
+ xbUInt32 iCurKeyNo; // current key number in the node, 0 offset
+ xbUInt32 ulBlockNo; // this block number
+ xbUInt32 ulBufSize; // size of cpBlockData
+ char *cpBlockData; // pointer to memory version of block data stored in file
+};
+///@endcond DOXYOFF
+
+
+//! @brief Base class for handling dbf indices.
+/*!
+
+The xbIx class is used as a base class for accessing index files.
+Each index file can have one or more tags.
+
+Calls to the index routines to perform index updates are handled automatically by the dbf class.
+The application program does not need to be concerned with index updates.
+
+If there is a production MDX index, it is opened automatically when the dbf file is opened.
+If there is an ndx file, that has been associated with the dbf file with the metadata routines,
+it will be opened automatically when the dbf file is opened.
+If there are non prod ndx indices that are not associated with the dbf file, the application
+program will need to open as appropriate.
+The meta data association logic is specific to the Xbase64 library and is not applicable to
+other available tools that handle ndx indices.
+All index files are automatically closed when the dbf file is closed.
+
+
+<br>
+The class is designed to support the addition of additional indices with a minimal amount of effort
+needed to integrate into the library.
+If you are looking at adding an new index type to the library, create a derived class using xbIx as a
+base class and modify methods needed to support the new index file version.
+The xbDbf class (and derived classes) perform the needed calls to the index routines for updates.<br>
+See the following for examples on how to start on this:<br>
+xbIxNdx is a derived class and supports a single tag.<br>
+xbIxMdx is a derived class and supports multiple tags.<br>
+
+
+
+<br>
+How data fields are stored in index files:
+<table>
+<tr><th>Field Type<th>Stored in DBF as<th>Stored in NDX as<th>Stored in MDX as</tr>
+<tr><td>C<td>char<td>char<td>char
+<tr><td>F<td>text numbers<td>xbDouble<td>xbBcd
+<tr><td>N<td>text numbers<td>xbDouble<td>xbBcd
+<tr><td>D<td>text CCYYMMDD<td>xbDouble - julian<td>xbDouble - julian
+</table>
+
+
+<br>
+Pages Vs Blocks
+<br>
+For purposes of the Xbase index classes, a page is considered to be 512 bytes of data
+and a block is made up of one or more 512 byte pages.
+<br>Default block sixe of NDX indices is one 512 byte page.
+<br>Default block size of MDX indices is two 512 byte pages or 1024 bytes.
+
+<br>The WriteBlock and GetBlock functions calculate the physical position in the
+file based on a combination of Block Number and Block Size. Block size is set at
+time of index file creation, default is 1024 or two pages.
+
+<br>Page numbers are stored in the physical file, but block reads and writes
+are performed.
+
+<br>
+Duplicate Keys
+<br>
+With the original DBase unique indexing option, if a table has multiple records with the
+same key value, DBase would allow multiple records in the table, but only the first
+record would be found in the index.
+<br>
+XBase64 can be configured to support the original DBase duplicate key implementation,
+or can be configured to halt with a DUPLICATE_KEY error on the insertion of a record
+with a duplicate key.
+<br>
+<table>
+<tr><th>Option<th>Description</tr>
+<tr><td>XB_HALT_ON_DUPKEY</td><td>Return error XB_KEY_NOT_UNIQUE when attempting to append record with duplicate key</td></tr>
+<tr><td>XB_EMULATE_DBASE</td><td>Emulate DBase, allow duplicate records with the same key, only the first record is indexed</td></tr>
+</table>
+*/
+
+
+class XBDLLEXPORT xbIx : public xbFile {
+ public:
+ xbIx( xbDbf * d );
+ virtual ~xbIx();
+
+ virtual xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt ) = 0;
+ virtual xbInt16 Close();
+ virtual xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag ) = 0;
+ virtual xbInt16 FindKey( void *vpTag, const xbString &sKey, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, const char * cKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, const xbBcd &bcd, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, const xbDate &dtKey, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw );
+ virtual xbInt16 FindKey( void *vpTag, const void *vKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw ) = 0;
+ virtual void *GetCurTag() const;
+ virtual xbDbf *GetDbf() const;
+
+ virtual xbString &GetKeyExpression( const void *vpTag ) const = 0;
+ virtual xbString &GetKeyFilter( const void *vpTag ) const = 0;
+ virtual char GetKeyType( const void *vpTag ) const = 0;
+ virtual xbBool GetLocked() const;
+
+ virtual xbInt16 GetFirstKey( void *vpTag, xbInt16 iRetrieveSw ) = 0;
+ virtual xbInt16 GetFirstKey( void *vpTag );
+ virtual xbInt16 GetFirstKey();
+
+ virtual xbInt16 GetLastKey( void *vpTag, xbInt16 lRetrieveSw ) = 0;
+ virtual xbInt16 GetLastKey( void *vpTag );
+ virtual xbInt16 GetLastKey();
+
+ virtual xbInt16 GetNextKey( void *vpTag, xbInt16 iRetrieveSw ) = 0;
+ virtual xbInt16 GetNextKey( void *vpTag );
+ virtual xbInt16 GetNextKey();
+
+ virtual xbInt16 GetPrevKey( void *vpTag, xbInt16 iRetrieveSw ) = 0;
+ virtual xbInt16 GetPrevKey( void *vpTag );
+ virtual xbInt16 GetPrevKey();
+
+ virtual void *GetTag( xbInt16 iTagNo ) const = 0;
+ virtual void *GetTag( xbString &sTagName ) const = 0;
+ virtual xbInt16 GetTagCount() const = 0;
+
+ virtual xbString &GetTagName( void *vpTag ) const = 0;
+ virtual const char * GetTagName( void *vpTag, xbInt16 iOpt ) const = 0;
+ virtual void GetTagName( void *vpTag, xbString &sTagName ) {};
+
+ virtual xbBool GetUnique( void *vpTag ) const = 0;
+ virtual xbBool GetSortOrder( void *vpTag ) const = 0;
+
+ virtual xbInt16 Open( const xbString &sFileName );
+ virtual xbInt16 Reindex( void **vpTag ) = 0;
+ virtual xbInt16 SetCurTag( xbInt16 iTagNo ) = 0;
+ virtual xbInt16 SetCurTag( xbString &sTagName ) = 0;
+ virtual void SetCurTag( void * vpCurTag );
+ virtual void SetLocked( xbBool bLocked );
+
+ virtual void TestStub( char *s, void *vpTag ) {};
+
+
+ #ifdef XB_DEBUG_SUPPORT
+ virtual xbInt16 DumpFreeBlocks( xbInt16 iOpt = 0 ) { return XB_NO_ERROR; }
+ virtual xbInt16 DumpHeader( xbInt16 iDestOpt = 0, xbInt16 iFmtOpt = 0 ) = 0;
+ virtual xbInt16 DumpIxForTag( void *vpTag, xbInt16 iOutputOpt ) = 0;
+ virtual void DumpIxNodeChain( void *vpTag, xbInt16 iOutputOpt ) const = 0;
+ virtual xbInt16 DumpNode( void * vpTag, xbIxNode * pNode, xbInt16 iOption ) const;
+ virtual xbInt16 DumpTagBlocks( xbInt16 iOpt = 1, void *vpTag = NULL ) = 0;
+
+ #endif
+
+ protected:
+ friend class xbDbf;
+
+ virtual xbInt16 AddKey( void *vpTag, xbUInt32 ulRecNo ) = 0;
+ virtual xbInt16 AddKeys( xbUInt32 ulRecNo );
+ virtual xbIxNode *AllocateIxNode( xbUInt32 ulBufSize = 0, xbInt16 iOption = 0 );
+ virtual xbInt16 BSearchBlock( char cKeyType, xbIxNode *npNode, xbInt32 lKeyLen, const void *vpKey, xbInt32 lSearchKeyLen, xbInt16 &iCompRc, xbBool bDescending = xbFalse ) const;
+ virtual xbInt16 CheckForDupKeys();
+ virtual xbInt16 CheckForDupKey( void *vpTag ) = 0;
+ virtual xbInt16 CompareKey( char cKeyType, const void *v1, const void *v2, size_t lKeyLen ) const;
+ virtual xbInt16 CreateKeys( xbInt16 iOpt );
+ virtual xbInt16 CreateKey( void * vpTag, xbInt16 iOpt ) = 0;
+ virtual xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo ) = 0;
+// virtual xbInt16 DeleteKeys( xbUInt32 ulRecNo );
+ virtual xbInt16 DeleteKeys();
+ virtual xbInt16 DeleteKey( void *vpTag ) = 0;
+
+ virtual xbInt16 DeleteTag( void *vpTag ) = 0;
+
+
+ virtual xbInt16 FindKeyForCurRec( void *vpTag ) = 0;
+ virtual xbIxNode *FreeNodeChain( xbIxNode *np );
+ virtual xbInt16 GetBlock( void *vpTag, xbUInt32 ulBlockNo, xbInt16 iOpt, xbUInt32 ulAddlBuf = 0 );
+// virtual xbBool GetIndexUpdated() const = 0;
+ virtual xbInt32 GetKeyCount( xbIxNode *npNode ) const;
+ virtual char *GetKeyData( xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iKeyItemLen ) const;
+ virtual xbInt16 GetKeySts( void *vpTag ) const = 0;
+ virtual xbInt16 GetLastKey( xbUInt32 ulNodeNo, void *vpTag, xbInt16 lRetrieveSw ) = 0;
+ virtual xbInt16 InsertNodeL( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 uiPtr ) = 0;
+ virtual xbInt16 InsertNodeI( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, xbUInt32 uiPtr ) = 0;
+ virtual xbInt16 KeyExists( void * ) = 0;
+// virtual xbInt16 KeyUpdated( void *vpTag ) const = 0;
+ virtual void NodeFree( xbIxNode * ixNode );
+ virtual xbInt16 ReadHeadBlock( xbInt16 iOpt = 0 ) = 0;
+ virtual void SetDbf( xbDbf *dbf );
+ virtual xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr ) = 0;
+ virtual xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr ) = 0;
+ virtual xbInt16 UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo = 0 ) = 0;
+ virtual xbInt16 WriteHeadBlock( xbInt16 iOption ) = 0;
+
+ xbDbf *dbf;
+ char *cNodeBuf; // pointer to memory for processing in a block of index data
+ void *vpCurTag; // pointer to active tag. Single index files have only one tag
+
+ private:
+ virtual void AppendNodeChain( void *vpTag, xbIxNode *npNode ) = 0;
+ virtual xbInt16 GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulKeyPtr ) const = 0;
+ virtual xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const = 0;
+ // virtual void SetCurNode( void *vpTag, xbIxNode *npNode ) = 0;
+
+ xbBool bLocked; // index file locked?
+};
+
+#ifdef XB_NDX_SUPPORT
+
+#define XB_NDX_BLOCK_SIZE 512
+
+
+///@cond DOXYOFF
+struct XBDLLEXPORT xbNdxTag {
+
+ // NDX File Header Fields
+ xbUInt32 ulRootBlock; // header node is 0
+ xbUInt32 ulTotalBlocks; // includes header node
+ char cKeyType; // C = Char, F = Numeric, D = Date
+ xbInt16 iKeyLen; // length of key data
+ xbInt16 iKeysPerBlock; // max number keys per block <=100
+ xbInt16 iKeyType; // 00 = Char, 01 = Numeric
+ xbInt16 iKeyItemLen; // KeyLen + 8 bytes
+ char cSerNo; // rolling incrementing serial number +1 on each index update
+ xbInt16 iUnique; // True if unique
+ xbString sKeyExpression; // index expression
+ // end of NDX Header field
+
+ xbExp *exp; // pointer to expression for expression keys
+ time_t tNodeChainTs; // node chain time stamp
+ xbIxNode *npNodeChain;
+ xbIxNode *npCurNode;
+ char *cpKeyBuf; // key buffer, for searches and adds
+ char *cpKeyBuf2; // key buffer, for deletes
+ xbString sTagName; // tag name - is the file name without the extension
+// xbInt16 iKeyUpdated; // key updated? set in method KeyUpdated, checked in AddKey and DeleteKey routines
+ xbBool bFoundSts; // key found? used to determine if new key should be added in XB_EMULATE_DBASE mode in AddKey
+
+
+ xbInt16 iKeySts; // key updated? set in method CreateKey, checked in AddKey and DeleteKey routines
+ // old key filtered new key filtered iKeySts
+ // Y Y XB_UPD_KEY 2 - update key if changed (delete and add)
+ // Y N XB_DEL_KEY 3 - delete key
+ // N Y XB_ADD_KEY 1 - add key
+ // N N 0 - no update
+
+};
+///@endcond DOXYOFF
+
+//! @brief Class for handling NDX single tag indices.
+/*!
+
+The xbIxNdx class is derived from the xbIx base class and is specific to handling NDX single tag index files.
+Each NDX index file can have only one tag, but the methods are set up to take an argument for a specific tag.
+This was done in order to provide a consistant interface across index types.
+
+Calls to the ndx index routines to perform index updates are handled automatically be the dbf class after
+the ndx file has been opened.
+
+Xbase64 provides a mechanism to automatically open ndx files when a dbf file is opened.
+If the ndx file has been associated with the dbf file with the metadata routines,
+it will be opened automatically when the dbf file is opened.
+If there are non prod ndx indices that are not associated with the dbf file, the application
+program will need to open as appropriate.
+The meta data association logic is specific to the Xbase64 library and is not applicable to
+other available tools that handle ndx indices.
+
+*/
+
+class XBDLLEXPORT xbIxNdx : public xbIx {
+ public:
+ xbIxNdx( xbDbf * d );
+ ~xbIxNdx();
+ xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt );
+ xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
+// xbInt16 DeleteTag( void *vpTag );
+ xbInt16 FindKey( void *vpTag, const void *vpKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
+ xbInt16 GetFirstKey( void *vpTag, xbInt16 iRetrieveSw );
+
+ xbInt16 GetLastKey( void *vpTag, xbInt16 iRetrieveSw = 1 );
+ xbInt16 GetNextKey( void *vpTag, xbInt16 iRetrieveSw = 1 );
+ xbInt16 GetPrevKey( void *vpTag, xbInt16 iRetrieveSw = 1 );
+ xbInt32 GetKeyLen ( const void *vpTag ) const;
+ char GetKeyType ( const void *vpTag ) const;
+ xbString &GetKeyExpression( const void *vpTag ) const;
+ xbString &GetKeyFilter( const void *vpTag ) const;
+ void *GetTag( xbInt16 iTagNo ) const;
+ void *GetTag( xbString &sTagName ) const;
+ xbString &GetTagName( void *vpTag ) const;
+ const char * GetTagName( void *vpTag, xbInt16 iOpt ) const;
+
+ xbInt16 GetTagCount() const;
+ xbBool GetUnique( void *vpTag = NULL ) const;
+ xbBool GetSortOrder( void *vpTag ) const;
+ xbInt16 Reindex( void **vpTag );
+ xbInt16 SetCurTag( xbInt16 iTagNo );
+ xbInt16 SetCurTag( xbString &sTagName );
+
+
+
+ #ifdef XB_DEBUG_SUPPORT
+ xbInt16 DumpTagBlocks( xbInt16 iOpt = 1, void *vpTag = NULL );
+ xbInt16 DumpHeader( xbInt16 iOpt = 0, xbInt16 iFmt = 0 );
+ xbInt16 DumpIxForTag( void *vpTag, xbInt16 iOutputOpt );
+ void DumpIxNodeChain( void *vpTag, xbInt16 iOutputOpt ) const;
+ xbInt16 DumpNode( void * vpTag, xbIxNode * pNode, xbInt16 iOption ) const;
+ #endif
+
+ protected:
+ friend class xbDbf;
+ xbInt16 AddKey( void *vpTag, xbUInt32 ulRecNo );
+ xbIxNode *AllocateIxNode( xbUInt32 ulBufSize = 0, xbInt16 iOption = 0 );
+ xbInt16 CheckForDupKey( void *vpTag );
+ xbIxNode *CreateIxNode( xbUInt32 ulBufSize );
+ xbInt16 CreateKey( void * vpTag, xbInt16 iOpt );
+ xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo );
+ xbInt16 DeleteKey( void *vpTag );
+
+ xbInt16 DeleteTag( void *vpTag );
+
+ xbInt16 FindKeyForCurRec( void *vpTag );
+// xbBool GetIndexUpdated() const;
+ xbInt16 GetKeyTypeN( const void *vpTag ) const;
+ xbInt16 GetKeySts( void *vpTag ) const;
+ xbInt16 GetLastKey( xbUInt32 ulNodeNo, void *vpTag, xbInt16 iRetrieveSw = 1 );
+ xbInt16 InsertNodeI( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, xbUInt32 uiPtr );
+ xbInt16 InsertNodeL( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 uiPtr );
+ xbInt16 KeyExists( void *vpTag = NULL );
+// xbBool KeyFiltered( void *vpTag ) const;
+// xbInt16 KeyUpdated( void *vpTag ) const;
+ xbInt16 ReadHeadBlock(xbInt16 iOpt); // read the header node of the disk NDX file
+ xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr );
+ xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
+ xbInt16 UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo = 0 );
+ xbInt16 WriteHeadBlock( xbInt16 iOption );
+
+ private:
+ xbInt16 AddKeyNewRoot( xbNdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight );
+ void AppendNodeChain( void *vpTag, xbIxNode *npNode );
+ xbInt16 GetDbfPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulDbfPtr ) const;
+ xbInt16 GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulKeyPtr ) const;
+ xbInt16 GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpKeyBuf );
+ xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const;
+ xbInt16 KeySetPosAdd( xbNdxTag *npTag, xbUInt32 ulAddKeyRecNo );
+ xbInt16 KeySetPosDel( xbNdxTag *npTag );
+ // void SetCurNode( void *vpTag, xbIxNode *np );
+ xbNdxTag *ndxTag;
+};
+
+#endif /* XB_NDX_SUPPORT */
+
+
+#ifdef XB_MDX_SUPPORT
+//#define XB_MDX_BLOCK_SIZE 1024
+
+struct XBDLLEXPORT xbMdxTag {
+
+ // next 7 fields comprise the tag table entry
+ xbUInt32 ulTagHdrPageNo; // 512 byte page number, NOT block number
+ char cTagName[11];
+ char cKeyFmt; // always 0x10 w/ DBase V7
+ char cLeftChild; // cFwdTagThread
+ char cRightChild; // cFwdTagThread2
+ char cParent; // cBwdTagThread
+ char c2;
+ char cKeyType; // C,D,N
+
+ xbUInt32 ulRootPage; // 512 byte page number, NOT block number
+ xbUInt32 ulTagSize; // Number of 512 byte pages allocated to the tag. Tag size of two is a single 1024 block
+
+ char cKeyFmt2; // 0x10 - base
+ // 0x08 - descending
+ // 0x40 - unique
+ char cKeyType2;
+ // one unused byte fits here
+
+ char cTag11; // dbase sets to 0x1B
+
+ xbInt16 iKeyLen;
+ xbInt16 iKeysPerBlock;
+ xbInt16 iSecKeyType;
+ xbInt16 iKeyItemLen; // iKeyLen + 4
+
+ char cSerialNo; // Increments +1 for each tag update
+ char cUnique;
+ xbString *sKeyExp; // Key expression
+
+ char cHasFilter; // 0x00 or 0x01
+ char cHasKeys; // 0x00 or 0x01
+
+ xbUInt32 ulLeftChild; // dbase 7 sets this to the root page on tag creation
+ xbUInt32 ulRightChild; // dbase 7 sets this to the root page on tag creation
+
+ char cTagYY;
+ char cTagMM;
+ char cTagDD;
+
+ char cKeyFmt3; // dbase 7 sets this 0x01 if discreet field or 0x00 if calculated or combination field key expression on tag creation
+
+ xbString *sFiltExp; // Filter expression
+
+ time_t tNodeChainTs;
+ xbIxNode *npNodeChain;
+ xbIxNode *npCurNode;
+ xbExp *exp; // pointer to expression for expression based tags
+ xbExp *filter; // pointer to expression for index filter
+
+ char *cpKeyBuf; // key buffer
+ char *cpKeyBuf2; // key buffer
+// xbBool iKeyUpdated; // key updated? set in method CreateKey, checked in AddKey and DeleteKey routines
+ // 0 - no update
+ // 1 - Add
+ // 2 - Update
+ // 3 - Delete
+// xbBool bKeyFiltered; // key filtered? True if included key, False if excluded key. Set in method CreateKey, checked in AddKey and DeleteKey routines
+ xbString *sTagName; // string tag name
+
+
+ xbMdxTag *next;
+ xbBool bFoundSts; // key found? used to determine if new key should be added in XB_EMULATE_DBASE mode in AddKey
+
+
+ xbInt16 iKeySts; // key updated? set in method CreateKey, checked in AddKey and DeleteKey routines
+ // old key filtered new key filtered iKeySts
+ // Y Y XB_UPD_KEY 2 - update key if changed (delete and add)
+ // Y N XB_DEL_KEY 3 - delete key
+ // N Y XB_ADD_KEY 1 - add key
+ // N N 0 - no update
+
+
+};
+
+
+class XBDLLEXPORT xbIxMdx : public xbIx {
+ public:
+ xbIxMdx( xbDbf * d );
+ ~xbIxMdx();
+ xbInt16 CheckTagIntegrity( void *vpTag, xbInt16 iOpt );
+ xbInt16 CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag );
+// xbInt16 DeleteTag( void *vpTag );
+ xbInt16 FindKey( void *vpTag, const void *vKey, xbInt32 lKeyLen, xbInt16 iRetrieveSw );
+ xbInt16 FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw );
+ xbInt16 GetFirstKey( void *vpTag, xbInt16 lRetrieveSw );
+ xbString &GetKeyExpression( const void *vpTag ) const;
+ xbString &GetKeyFilter( const void *vpTag ) const;
+ char GetKeyType( const void *vpTag ) const;
+ xbInt16 GetLastKey( void *vpTag, xbInt16 lRetrieveSw );
+ xbInt16 GetNextKey( void *vpTag, xbInt16 lRetrieveSw );
+ xbInt16 GetPrevKey( void *vpTag, xbInt16 lRetrieveSw );
+ xbBool GetReuseEmptyNodesSw() const;
+ xbBool GetSortOrder( void *vpTag ) const;
+ void *GetTag( xbInt16 iTagNo ) const;
+ void *GetTag( xbString &sTagName ) const;
+ xbInt16 GetTagCount() const;
+
+ xbString &GetTagName( void *vpTag ) const;
+ const char * GetTagName( void *vpTag, xbInt16 iOpt ) const;
+ void GetTagName( void *vpTag, xbString &sTagName );
+
+ xbInt16 GetUnique( void *vpTag ) const;
+ xbInt16 Reindex( void **vpTag );
+ xbInt16 SetCurTag( xbInt16 iTagNo );
+ xbInt16 SetCurTag( xbString &sTagName );
+ void SetReuseEmptyNodesSw( xbBool bReuse );
+
+ void TestStub( char *s, void *vpTag );
+
+ protected:
+ friend class xbDbf;
+
+ xbInt16 AddKey( void *vpTag, xbUInt32 ulRecNo );
+ xbIxNode *AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt32 ulBlock2 );
+ xbInt16 CheckForDupKey( void *vpTag );
+ xbInt16 Close();
+ xbInt16 CreateKey( void * vpTag, xbInt16 iOpt );
+ xbInt16 DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo );
+ xbInt16 DeleteKey( void *vpTag );
+
+ xbInt16 DeleteTag( void *vpTag );
+
+ xbInt16 FindKeyForCurRec( void *vpTag );
+ xbInt16 GetKeySts( void *vpTag ) const;
+ xbInt16 GetLastKey( xbUInt32 ulBlockNo, void *vpTag, xbInt16 lRetrieveSw );
+ void *GetTagTblPtr() const;
+ void Init( xbInt16 iOpt = 0 );
+ xbInt16 InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xbUInt32 uiPtr );
+ xbInt16 InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
+ xbInt16 KeyExists( void * );
+ xbInt16 LoadTagTable();
+ xbInt16 ReadHeadBlock(xbInt16 iOpt); // read the header node of the disk file
+ xbInt16 SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 uiPtr );
+ xbInt16 SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, char *cpKeyBuf, xbUInt32 uiPtr );
+ xbInt16 UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo = 0 );
+ xbInt16 WriteHeadBlock( xbInt16 iOption );
+
+ #ifdef XB_DEBUG_SUPPORT
+ xbInt16 DumpTagBlocks( xbInt16 iOpt = 1, void *vpTag = NULL );
+ xbInt16 DumpFreeBlocks( xbInt16 iOpt = 0 );
+ xbInt16 DumpHeader( xbInt16 iOpt = 0, xbInt16 iFmtOpt = 0 );
+ xbInt16 DumpIxForTag( void *vpTag, xbInt16 iOutputOpt );
+ void DumpIxNodeChain( void *vpTag, xbInt16 iOutputOpt ) const;
+ #endif
+
+ private:
+ xbInt16 AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight );
+ void AppendNodeChain( void *vpTag, xbIxNode *npNode );
+ xbUInt32 BlockToPage( xbUInt32 ulBlockNo );
+ void CalcBtreePointers();
+ char CalcTagKeyFmt( xbExp &exp );
+ char CalcTagFwdThread1();
+ char CalcTagFwdThread2();
+ xbMdxTag *ClearTagTable();
+ xbInt16 DumpBlock( xbInt16 iOpt, xbUInt32 ulBlockNo, xbMdxTag * mpTag );
+ xbInt16 GetDbfPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulDbfPtr ) const;
+ xbInt16 GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *npNode, xbUInt32 &ulKeyPtr ) const;
+ xbInt16 GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpKeyBuf );
+ xbInt16 HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iOpt, xbBool bHarvestRoot = xbFalse );
+ xbInt16 HarvestTagNodes( xbMdxTag *mpTag, xbBool bRecycleRoot = xbFalse );
+ xbBool IsLeaf( void *vpTag, xbIxNode *npNode ) const;
+ xbInt16 KeySetPosAdd( xbMdxTag *mpTag, xbUInt32 ulAddKeyRecNo );
+ xbInt16 KeySetPosDel( xbMdxTag *mpTag );
+ xbInt16 LoadTagDetail( xbInt16 iOption, xbMdxTag *tte );
+ xbUInt32 PageToBlock( xbUInt32 ulPageNo );
+ xbInt16 TagSerialNo( xbInt16 iOption, xbMdxTag *mpTag );
+ xbInt16 UpdateTagSize( xbMdxTag *mpTag, xbUInt32 ulTagSz );
+
+ #ifdef XB_DEBUG_SUPPORT
+ xbInt16 PrintKey( void *vpTag, xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iDepth, char cType, xbInt16 iOutputOpt );
+ #endif
+
+ // MDX File Header Fields
+ char cVersion;
+ char cCreateYY;
+ char cCreateMM;
+ char cCreateDD;
+ xbString sFileName;
+ xbInt16 iBlockFactor; // 1-32 #of 512 byte segments in a block
+
+ // use file version
+ // xbInt16 iBlockSize; // Stored at the xbFile level
+
+ char cProdIxFlag;
+ char cTagEntryCnt;
+ xbInt16 iTagLen;
+ xbInt16 iTagUseCnt;
+ char cNextTag; // byte 28 +1
+ char c1B; // always 0x1B
+ xbUInt32 ulPageCnt; // number of 512 byte pages in the mdx file
+ xbUInt32 ulFirstFreePage; // page number corresponding to the next free block
+ xbUInt32 ulNoOfBlockAvail; // might be improperly named?? not sure how it is used
+ char cUpdateYY;
+ char cUpdateMM;
+ char cUpdateDD;
+ // end of MDX Header fields
+
+
+
+ xbMdxTag *mdxTagTbl;
+
+ xbBool bReuseEmptyNodes; // Reuese empty MDX nodes when all keys deleted?
+ // DBase 7.x and MS ODBC drivers do not reuse empty nodes, leaves them stranded in the file
+ // Codebase 6.x reuses empty nodes.
+ // Setting this to True will reuse empty nodes in the same manner Codebase 6.x reuses them.
+
+};
+#endif /* XB_MDX_SUPPORT */
+
+
+} /* namespace xb */
+#endif /* XB_INDEX_SUPPORT */
+#endif /* __XB_INDEX_H__ */
diff --git a/src/include/xblog.h b/src/include/xblog.h
index e78f476..5c7d721 100755
--- a/src/include/xblog.h
+++ b/src/include/xblog.h
@@ -44,13 +44,14 @@ class XBDLLEXPORT xbLog : public xbFile {
xbLog( const xbString &sLogFileName );
~xbLog();
- xbInt16 LogClose ();
- xbInt16 LogGetStatus ();
- xbInt16 LogOpen ();
- void LogSetStatus ( xbBool bLogStatus );
- void LogSetLogSize( size_t lSize ); // { LogSize = size; }
- xbInt16 LogWrite ( const xbString &LogEntry, xbInt16 iOutputOption = 0 );
- xbInt16 LogWriteBytes( xbUInt32 lByteCnt, const char *p );
+ xbInt16 LogClose ();
+ xbInt16 LogGetStatus ();
+ xbInt16 LogOpen ();
+ void LogSetStatus ( xbBool bLogStatus );
+ void LogSetLogSize( size_t lSize ); // { LogSize = size; }
+ xbInt16 LogWrite ( const xbString &LogEntry, xbInt16 iOutputOption = 0 );
+ xbInt16 LogWriteBytes( xbUInt32 lByteCnt, const char *p );
+ size_t LogGetLogSize() const { return lLogSize; }
private:
xbBool bLoggingStatus; // false = logging off
diff --git a/src/include/xbretcod.h b/src/include/xbretcod.h
index ec1f91b..f2885b1 100755
--- a/src/include/xbretcod.h
+++ b/src/include/xbretcod.h
@@ -24,9 +24,10 @@ namespace xb{
#define XB_NO_ERROR 0 // general
#define XB_NO_MEMORY -100 // general
#define XB_INVALID_OPTION -101 // general
+ #define XB_INVALID_PARAMETER -102 // general
#define XB_DUP_TABLE_OR_ALIAS -110 // table manager
#define XB_INVALID_NODELINK -120 // linklist
- #define XB_KEY_NOT_UNIQUE -121 // linklist
+ #define XB_KEY_NOT_UNIQUE -121 // linklist, index
#define XB_MEMCPY_ERROR -122 // memcpy failure
#define XB_FILE_EXISTS -200 // file
diff --git a/src/include/xbssv.h b/src/include/xbssv.h
index d050bcb..3b87a13 100755
--- a/src/include/xbssv.h
+++ b/src/include/xbssv.h
@@ -64,11 +64,19 @@ class XBDLLEXPORT xbSsv{
void DisplayError ( xbInt16 ErrorCode ) const;
xbString& GetDefaultDateFormat () const;
xbString& GetDataDirectory () const;
- xbInt16 GetEndianType () const;
+ xbString& GetTempDirectory () const;
+
+ void GetHomeDir ( xbString &sHomeDirOut );
+
+ xbInt16 GetEndianType () const;
const char *GetErrorMessage ( xbInt16 ErrorCode ) const;
+ char GetPathSeparator () const;
+
void SetDataDirectory ( const xbString &sDataDirectory );
void SetDefaultDateFormat ( const xbString &sDefaultDateFormat );
+ void SetTempDirectory ( const xbString &sTempDirectory );
+
xbBool BitSet ( unsigned char c, xbInt16 iBitNo ) const;
void BitDump ( unsigned char c ) const;
@@ -77,11 +85,11 @@ class XBDLLEXPORT xbSsv{
xbBool GetDefaultAutoCommit () const;
void SetDefaultAutoCommit ( xbBool bDefaultAutoCommit );
- void GetHomeDir ( xbString &sHomeDirOut );
-
xbString& GetLogDirectory () const;
xbString& GetLogFileName () const;
void SetLogDirectory ( const xbString &sLogDirectory );
+ void SetLogFileName ( const xbString &sLogFileName );
+
xbBool GetMultiUser () const;
void SetMultiUser ( xbBool bMultiUser );
@@ -127,10 +135,11 @@ class XBDLLEXPORT xbSsv{
static xbString sDefaultDateFormat;
static xbString sDataDirectory; //Data file directory
+ static xbString sTempDirectory; //Temp file directory
#ifdef XB_LOGGING_SUPPORT
- static xbString sLogDirectory; //Default location to store log files
- static xbString sLogFileName; //Default LogFileName
+ static xbString sLogDirectory; //Default location to store log files
+ static xbString sLogFileName; //Default LogFileName
#endif
static xbInt16 iDefaultFileVersion; // 3 = DBase 3
diff --git a/src/include/xbstring.h b/src/include/xbstring.h
index 3e70acc..7fe1692 100755
--- a/src/include/xbstring.h
+++ b/src/include/xbstring.h
@@ -95,8 +95,8 @@ class XBDLLEXPORT xbString {
xbString &Append(char c);
xbString &Assign(const char *srcStr, xbUInt32 lStartPos, xbUInt32 lCopyLen );
xbString &Assign(const char *srcStr, xbUInt32 lStartPos );
- xbString &Assign(const xbString &s, xbUInt32 pos, xbUInt32 lCopyLen );
- xbString &Assign(const xbString &s, xbUInt32 lCopyLen );
+ xbString &Assign(const xbString &s, xbUInt32 ulStartPos, xbUInt32 lCopyLen );
+ xbString &Assign(const xbString &s, xbUInt32 ulStartPos );
xbString Copy() const;
xbUInt32 CountChar( char c ) const;
@@ -112,7 +112,9 @@ class XBDLLEXPORT xbString {
void DumpHex( const char *title ) const;
#endif
+ xbString &ExtractElement(xbString &s, char delim, xbUInt32 iCnt, xbInt16 iOpt = 0 );
xbString &ExtractElement(const char *src, char delim, xbUInt32 iCnt, xbInt16 iOpt = 0 );
+
char GetCharacter( xbUInt32 lPos ) const;
xbUInt32 GetLastPos(char c) const;
xbUInt32 GetLastPos(const char *s) const;
diff --git a/src/include/xbxbase.h b/src/include/xbxbase.h
index fe1f323..702da23 100755
--- a/src/include/xbxbase.h
+++ b/src/include/xbxbase.h
@@ -126,12 +126,13 @@ class XBDLLEXPORT xbXBase : public xbTblMgr{
~xbXBase();
xbInt16 CloseAllTables();
+ xbInt16 CreateFqn( const xbString &sDirIn, const xbString &sNameIn, const xbString &sExtIn, xbString &sFqfnOut );
void DisableMsgLogging();
void EnableMsgLogging ();
xbInt16 FlushLog();
- const xbString &GetLogDirectory () const;
- const xbString &GetLogFileName () const;
+ //const xbString &GetLogDirectory () const;
+ //const xbString &GetLogFileName () const;
const xbString &GetLogFqFileName() const;
xbBool GetLogStatus () const;
@@ -140,9 +141,13 @@ class XBDLLEXPORT xbXBase : public xbTblMgr{
xbDbf * Open( const xbString &sTableName, xbInt16 &iRc );
xbDbf * Open( const xbString &sTableName, const xbString &sAlias, xbInt16 iOpenMode, xbInt16 iShareMode, xbInt16 iVersion, xbInt16 &iRc );
- void SetLogDirectory( const xbString &sLogFileDirectory );
- void SetLogFileName ( const xbString &sLogFileName );
+
+ // next three methods moved to xbssv for consistency
+ // void SetLogDirectory( const xbString &sLogFileDirectory );
+ // void SetLogFileName ( const xbString &sLogFileName );
void SetLogSize ( size_t lSize );
+ size_t GetLogSize () const;
+
xbInt16 WriteLogMessage( const xbString &sLogMessage, xbInt16 iOutputOpt = 0 );
xbInt16 WriteLogBytes ( xbUInt32 lCnt, const char *p );
diff --git a/src/sql/xbcrix.cpp b/src/sql/xbcrix.cpp
index 6a391f7..8efdc39 100755
--- a/src/sql/xbcrix.cpp
+++ b/src/sql/xbcrix.cpp
@@ -66,6 +66,7 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
xbString sNode;
xbBool bUnique = xbFalse;
xbDbf * dbf = NULL;
+ xbBool bTableLocked = xbFalse;
try{
@@ -113,6 +114,7 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
xbFile f( xbase );
f.SetFileName( sIxName );
if( f.FileExists()){
+
iErrorStop = 110;
iRc = XB_FILE_EXISTS;
throw iRc;
@@ -140,12 +142,14 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
// if not open, attempt to open it
dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
+
if( !dbf ){
if(( iRc = xbase->OpenHighestVersion( sTableName, "", &dbf )) != XB_NO_ERROR ){
iErrorStop = 120;
throw iRc;
}
}
+
if( dbf == NULL ){
iErrorStop = 130;
iRc = XB_FILE_NOT_FOUND;
@@ -153,8 +157,6 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
}
sCmd.Ltrunc( ulPos );
- // std::cout << "cp1 ulPos = " << ulPos << " sCmd = [" << sCmd << "]\n";
-
//ulPos = sCmd.GetLastPos( ')' );
xbString sKeyExpression;
xbBool bDone = xbFalse;
@@ -181,7 +183,6 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
}
// std::cout << "Key Expression =[" << sKeyExpression << "]\n";
-
sCmd.Ltrunc( lPos );
sCmd.Trim();
@@ -199,7 +200,6 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
}
}
-
// std::cout << "sCmd - looking for FILTER stuff [" << sCmd << "]\n";
xbString sFilter;
if( sCmd.Len() > 6 ){
@@ -218,11 +218,11 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
iErrorStop = 140;
throw iRc;
+ } else {
+ bTableLocked = xbTrue;
}
#endif // XB_LOCKING_SUPPORT
- // std::cout << "SqlCreateIndex() - ixtype = " << sIxType << "\n";
-
xbIx *pIx;
void *vpTag;
@@ -230,14 +230,16 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
iErrorStop = 150;
throw iRc;
}
- // std::cout << "SqlCreateIndex() - back from tag create\n";
+
#ifdef XB_NDX_SUPPORT
+ xbBool bAssociate = xbFalse;
if( sIxType == "NDX"){
sCmd.Ltrunc( ulPos );
sCmd.Trim();
if( sCmd.Len() > 0 ){
sCmd.ToUpperCase();
if( sCmd.Pos( "ASSOCIATE" )){
+ bAssociate = xbTrue;
if(( iRc = dbf->AssociateIndex( "NDX", sIxName, 0 )) != XB_NO_ERROR ){
iErrorStop = 160;
throw iRc;
@@ -245,25 +247,36 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
}
}
}
-// if( sIxType == "NDX"){
-// if(( iRc = pIx->Reindex( &vpTag )) != XB_NO_ERROR ){
-// iErrorStop = 160;
-// throw iRc;
-// }
-// }
#endif // XB_NDX_SUPPORT
+ iRc = dbf->Reindex( 2, 1, &pIx, &vpTag );
- if(( iRc = pIx->Reindex( &vpTag )) != XB_NO_ERROR ){
- iErrorStop = 170;
+ #ifdef XB_NDX_SUPPORT
+ if( iRc != XB_NO_ERROR && sIxType == "NDX" && bAssociate ){
+ xbInt16 iRc2;
+ if(( iRc2 = dbf->AssociateIndex( "NDX", sIxName, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc2;
+ }
+ iErrorStop = 190;
+ throw iRc;
+ }
+ #endif // XB_NDX_SUPPORT
+
+ if( iRc != XB_NO_ERROR ){
+ iErrorStop = 200;
throw iRc;
}
#ifdef XB_LOCKING_SUPPORT
- if(( iRc = dbf->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
+ if( bTableLocked ){
+ if(( iRc = dbf->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 210;
+ throw iRc;
+ } else {
+ bTableLocked = xbFalse;
+ }
}
#endif // XB_LOCKING_SUPPORT
@@ -273,11 +286,10 @@ xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
sMsg.Sprintf( "xbSql::SqlCreateIndex() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
-
}
-
#ifdef XB_LOCKING_SUPPORT
- dbf->LockTable( XB_UNLOCK );
+ if( bTableLocked && dbf )
+ dbf->LockTable( XB_UNLOCK );
#endif // XB_LOCKING_SUPPORT
return iRc;
diff --git a/src/sql/xbcrtbl.cpp b/src/sql/xbcrtbl.cpp
index dfb3403..e22b0b5 100755
--- a/src/sql/xbcrtbl.cpp
+++ b/src/sql/xbcrtbl.cpp
@@ -69,8 +69,8 @@ xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
sTableName.ExtractElement( s, ' ', 3, 0 );
sTableName.Trim();
- // std::cout << "Tablename = [" << sTableName << "]\n";
-
+// std::cout << "Create table - Tablename = [" << sTableName.Str() << "]\n";
+// std::cout << "Cm line = [" << sCmdLine.Str() << "]\n";
// determine if it already exists
xbFile f( xbase );
@@ -160,17 +160,21 @@ xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
if( iAttribCnt == 1 ){
sAttrib1 = sWork;
} else {
+
lCmPos = sWork.Pos( ',' );
if( lCmPos <= 0 ){
iErrorStop = 140;
iRc = XB_INVALID_FIELD_LEN;
throw iRc;
}
+
sAttrib1.Assign( sWork, 1, lCmPos - 1);
sAttrib1.Trim();
+
sWork.Ltrunc( lCmPos );
sAttrib2 = sWork;
sAttrib2.Trim();
+
}
s.Ltrunc( lPos );
}
@@ -239,13 +243,15 @@ xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
#elif defined (XB_DBF3_SUPPORT)
dbf = new xbDbf3( xbase );
#endif
+
if(( iRc = dbf->CreateTable( sTableName, "", schema, 0, XB_MULTI_USER )) != XB_NO_ERROR ){
iErrorStop = 150;
throw iRc;
}
-
free( schema );
+
ll.Clear();
+
}
catch (xbInt16 iRc ){
xbString sMsg;
@@ -258,6 +264,7 @@ xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
xbase->WriteLogMessage( GetErrorMessage( iRc ));
if( schema ) free( schema );
}
+
return iRc;
}
diff --git a/src/sql/xbcrtbl.save.cpp b/src/sql/xbcrtbl.save.cpp
deleted file mode 100755
index 445ad56..0000000
--- a/src/sql/xbcrtbl.save.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/* xbcrtbl.cpp
-
-XBase64 Software Library
-
-Copyright (c) 1997,2003,2014,2019,2022 Gary A Kunkel
-
-The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
-
-Email Contact:
-
- XDB-devel@lists.sourceforge.net
- XDB-users@lists.sourceforge.net
-
-*/
-
-#include "xbase.h"
-
-#ifdef XB_SQL_SUPPORT
-
-namespace xb{
-
-
-/***********************************************************************/
-xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
-
-
- // std::cout << "CREATE TABLE " << sCmdLine << std::endl;
-
- // expected format:
- // CREATE TABLE tablename.dbf (Field1 CHAR(10), INTFLD1 INTEGER, ... )
-
- // supported field types
- //
- // SQL TYPE XBASE Field Type
- // -------- ----------------
- // SMALLINT NUMERIC(6,0)
- // INTEGER NUMERIC(11,0)
- // DECIMAL(x,y) NUMERIC(x+1,y)
- // NUMERIC(x,y) NUMERIC(x,y)
- // FLOAT(x,y) FLOAT(x,y)
- // CHAR(n) CHARACTER(n)
- // DATE DATE
- // VARCHAR MEMO
- // LOGICAL LOGICAL
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbString sTableName;
- xbString sFieldName;
- xbString sDataType;
- xbString sAttrib1;
- xbString sAttrib2;
- xbString sLlEntry;
- xbInt16 iType = 0;
- xbInt16 iAttribCnt; // number of attributes for a given data type
- xbString s;
- xbUInt32 lPos = 0;
- xbUInt32 lSpPos = 0; // space position
- xbUInt32 lCmPos = 0; // comma position
- xbUInt32 lLpPos = 0; // left paren position
- xbLinkList<xbString> ll;
- xbSchema *schema = NULL;
- xbString sMsg;
-
- try{
- // retrieve table name
- s.ExtractElement( sCmdLine, '(', 1, 0 );
- sTableName.ExtractElement( s, ' ', 3, 0 );
- sTableName.Trim();
-
- // std::cout << "Tablename = [" << sTableName << "]\n";
-
-
- // determine if it already exists
- xbFile f( xbase );
- f.SetFileName( sTableName );
- if( f.FileExists() ){
- iErrorStop = 100;
- iRc = XB_FILE_EXISTS;
- throw iRc;
- }
-
- // build out table structure with parms from the sql string
- lPos = sCmdLine.Pos( '(' );
- s = sCmdLine;
- s.Ltrunc( lPos );
- s.Trim();
-
- // remove the last byte, should be a )
- s.Remove( s.Len(), 1 );
-
- s.Trim();
- //std::cout << "s = [" << s << "]\n";
-
-
- xbBool bDone = xbFalse;
- xbInt16 iLoop = 0;
- while( !bDone && iLoop++ < 255 ){
- sFieldName.ExtractElement( s, ' ', 1 , 0 );
- lPos = sFieldName.Len();
- sFieldName.Trim();
- if( sFieldName.Len() > 10 )
- sFieldName.Mid( 1, 10 ); // shrink to 10 buytes if too big
-
- //std::cout << "field name=[" << sFieldName << "]\n";
- s.Ltrunc( lPos + 1 );
- s.Ltrim();
- //std::cout << "remainder after field name removed = [" << s << "]\n";
-
- // Data type is delimited with either a space, comma or left paren
- lPos = 9999999;
- lSpPos = s.Pos( ' ' );
- lCmPos = s.Pos( ',' );
- lLpPos = s.Pos( '(' );
- if( lSpPos != 0 ) lPos = lSpPos;
- if( lCmPos != 0 && lCmPos < lPos ) lPos = lCmPos;
- if( lLpPos != 0 && lLpPos < lPos ) lPos = lLpPos;
-
- //sMsg.Sprintf( "SpPos=[%d] CmPos=[%d] LpPos=[%d] lPos=[%d]", lSpPos, lCmPos, lLpPos, lPos );
- //std::cout << sMsg << "\n";
-
- sDataType.Assign( s, 1, lPos-1 );
-
- //std::cout << "DataType=[" << sDataType << "]\n";
- if( sDataType == "CHAR" )
- iAttribCnt = 1;
- else if( sDataType == "DECIMAL" || sDataType == "NUMERIC" || sDataType == "FLOAT" )
- iAttribCnt = 2;
- else if( sDataType == "SMALLINT" || sDataType == "INTEGER" || sDataType == "DATE" || sDataType == "VARCHAR" || sDataType == "LOGICAL" )
- iAttribCnt = 0;
- else{
- iErrorStop = 110;
- iRc = XB_INVALID_FIELD_TYPE;
- throw iRc;
- }
-
- sAttrib1 = "";
- sAttrib2 = "0";
-
- if( iAttribCnt == 0 ){
- s.Ltrunc( sDataType.Len());
-
- } else if( iAttribCnt > 0 ){
- lPos = s.Pos( '(' );
- if( lPos <= 0 ){
- iErrorStop = 110;
- iRc = XB_INVALID_FIELD_LEN;
- throw iRc;
- }
- s.Ltrunc( lPos );
- if( iAttribCnt == 1 )
- lPos = s.Pos( ')' );
- else
- lPos = s.Pos( ',' );
-
- sAttrib1.Assign( s, 1, lPos-1 );
- sAttrib1.Trim();
- s.Ltrunc( lPos );
-
- if( iAttribCnt > 1 ){
- lPos = s.Pos( ')' );
- sAttrib2.Assign( s, 1, lPos-1 );
- s.Ltrunc( lPos );
- }
- }
-
- s.Ltrim();
- s.ZapLeadingChar( ',' );
- s.Ltrim();
-
- if( sDataType == "CHAR" ){
- iType = XB_CHAR_FLD;
- } else if( sDataType == "DECIMAL" ){
- xbInt32 lVal = atol( sAttrib1.Str()) + 1;
- sAttrib1.Sprintf( "%d", lVal );
- iType = XB_NUMERIC_FLD;
- } else if( sDataType == "SMALLINT" ){
- sAttrib1 = "6";
- iType = XB_NUMERIC_FLD;
- } else if( sDataType == "INTEGER" ){
- sAttrib1 = "11";
- iType = XB_NUMERIC_FLD;
- } else if( sDataType == "NUMERIC" ){
- iType = XB_NUMERIC_FLD;
- } else if( sDataType == "FLOAT" ) {
- iType = XB_FLOAT_FLD;
- } else if( sDataType == "DATE" ){
- iType = XB_DATE_FLD;
- sAttrib1 = "8";
- } else if( sDataType == "VARCHAR" ){
- iType = XB_MEMO_FLD;
- sAttrib1 = "10";
- } else if( sDataType == "LOGICAL" ){
- iType = XB_LOGICAL_FLD;
- sAttrib1 = "1";
- }
- sLlEntry.Sprintf( "%s,%s,%c,%s,%s", sFieldName.Str(), sDataType.Str(), iType, sAttrib1.Str(), sAttrib2.Str());
- ll.InsertAtEnd( sLlEntry );
-
- if( s.Len() == 0 )
- bDone = xbTrue;
- }
-
- schema = (xbSchema *) calloc( ll.GetNodeCnt()+1, sizeof( xbSchema ));
- xbLinkListNode<xbString> * llN = ll.GetHeadNode();
- xbUInt32 ulCnt = ll.GetNodeCnt();
-
- char *pTrg;
- for( xbUInt32 i = 0; i < ulCnt; i++ ){
- s = llN->GetKey();
- sFieldName.ExtractElement( s, ',', 1 , 0 );
- pTrg = schema[i].cFieldName;
- for( xbUInt32 j = 0; j < sFieldName.Len(); j++ )
- *pTrg++ = sFieldName[j+1];
- sDataType.ExtractElement( s, ',', 3, 0 );
- schema[i].cType = sDataType[1];
- sAttrib1.ExtractElement( s, ',', 4, 0 );
- schema[i].iFieldLen = atoi( sAttrib1.Str());
- sAttrib2.ExtractElement( s, ',', 5, 0 );
- schema[i].iNoOfDecs = atoi( sAttrib2.Str());
- llN = llN->GetNextNode();
- }
-
- // create the table
- xbDbf * dbf = NULL;
- #ifdef XB_DBF4_SUPPORT
- dbf = new xbDbf4( xbase );
- #elif defined (XB_DBF3_SUPPORT)
- dbf = new xbDbf3( xbase );
- #endif
- if(( iRc = dbf->CreateTable( sTableName, "", schema, 0, XB_MULTI_USER )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- free( schema );
- ll.Clear();
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- if( sFieldName.Len() > 0 )
- sMsg.Sprintf( "xbSql::SqlCreateTbl() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s] field = [%s]", iErrorStop, iRc, sTableName.Str(), sFieldName.Str() );
- else
- sMsg.Sprintf( "xbSql::SqlCreateTbl() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
-
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( schema ) free( schema );
- }
- return iRc;
-}
-
-/***********************************************************************/
-} /* namespace */
-#endif /* XB_SQL_SUPPORT */
-
diff --git a/src/sql/xbdelete.cpp b/src/sql/xbdelete.cpp
index 82b4937..9bd4279 100755
--- a/src/sql/xbdelete.cpp
+++ b/src/sql/xbdelete.cpp
@@ -134,7 +134,7 @@ xbInt16 xbSql::SqlDelete( const xbString &sCmdLine ){
catch (xbInt16 iRc ){
xbString sMsg;
- sMsg.Sprintf( "xbSql::SqlDropTable() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ sMsg.Sprintf( "xbSql::SqlDelete() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
xbase->WriteLogMessage( sMsg.Str() );
xbase->WriteLogMessage( GetErrorMessage( iRc ));
}
diff --git a/src/sql/xbdrptbl.cpp b/src/sql/xbdrptbl.cpp
index b03ee8f..ee3e325 100755
--- a/src/sql/xbdrptbl.cpp
+++ b/src/sql/xbdrptbl.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.
@@ -86,8 +86,10 @@ xbInt16 xbSql::SqlDropTable( const xbString &sCmdLine ){
dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
if( !dbf ){
- dbf = xbase->Open( sTableName, iRc );
- if( iRc != XB_NO_ERROR ){
+
+ //dbf = xbase->Open( sTableName, iRc );
+ iRc = xbase->OpenHighestVersion( sTableName, "", &dbf );
+ if( iRc != XB_NO_ERROR ){
if( iRc == XB_FILE_NOT_FOUND && bIfExists ){
return XB_NO_ERROR;
} else {
@@ -106,6 +108,9 @@ xbInt16 xbSql::SqlDropTable( const xbString &sCmdLine ){
iErrorStop = 130;
throw iRc;
}
+
+ delete dbf;
+ // dbf = NULL;
}
catch (xbInt16 iRc ){
diff --git a/src/tests/tstfuncs.cpp b/src/tests/tstfuncs.cpp
index d9b108d..377b199 100755
--- a/src/tests/tstfuncs.cpp
+++ b/src/tests/tstfuncs.cpp
@@ -415,7 +415,7 @@ xbInt16 SetCmd( xbXBase &x, const xbString &sFileName, const xbString &sCmd, con
#ifdef HAVE__FSOPEN_F
// 0x40 is SH_DENYNO or _SH_DENYNO
- if(( f = _fsopen( sFileName.Str(), "r", 0x40 )) == NULL){
+ if(( f = _fsopen( sFileName.Str(), "w", 0x40 )) == NULL){
x.xbSleep( 250 );
iTryCnt++;
}
diff --git a/src/tests/xb_test_date.cpp b/src/tests/xb_test_date.cpp
index 7aee584..0efe102 100755
--- a/src/tests/xb_test_date.cpp
+++ b/src/tests/xb_test_date.cpp
@@ -69,6 +69,8 @@ int main( int argCnt, char **av )
iRc += TestMethod( po, "FormatDate( '', sOutDate ) (sys default format)", d3.FormatDate( sFmt, sOutDate ), 0 );
iRc += TestMethod( po, "FormatDate( '', sOutDate ) (sys default format)", sOutDate, "07/09/12", 8 );
+
+
iRc += TestMethod( po, "CenturyOf()" , d3.CenturyOf(), 20 );
iRc += TestMethod( po, "YearOf()", d3.YearOf(), 2012 );
iRc += TestMethod( po, "MonthOf()", d3.MonthOf(), 7 );
@@ -84,12 +86,11 @@ int main( int argCnt, char **av )
d1.Set( "20010102" );
iRc += TestMethod( po, "d1.Set('20010102')", d1.Str(), "20010102", 8 );
- iRc += TestMethod( po, "d1.CalcRollingCenturyForYear(10)", d1.CalcRollingCenturyForYear( 10 ), 20 );
+ iRc += TestMethod( po, "d1.CalcRollingCenturyForYear(10)", d1.CalcRollingCenturyForYear( 10 ), 20 );
iRc += TestMethod( po, "d1.JulianDays()", d1.JulianDays(), 2451912 );
-
-
iRc += TestMethod( po, "d1.Set( '20140709' )", d1.Set( "20140709" ) , 0 );
+
d1.CharDayOf( s );
iRc += TestMethod( po, "d1.CharDayOf(s)", s, "Wednesday", 9 );
@@ -135,8 +136,8 @@ int main( int argCnt, char **av )
iRc+= TestMethod( po, "d1+2", d1+2, "20130407", 8 );
iRc+= TestMethod( po, "d1-5", d1-5, "20130402", 8 );
-// d1.Dump( "d1" );
-// d2.Dump( "d2" );
+ //d1.Dump( "d1" );
+ //d2.Dump( "d2" );
iRc+= TestMethod( po, "d1==d2", d1==d2, 0 );
d2 = d1;
@@ -159,6 +160,29 @@ int main( int argCnt, char **av )
iRc+= TestMethod( po, "d1<=d2", d1<=d2, 0 );
iRc+= TestMethod( po, "d1-d2", d1-d2, 1 );
+
+ // null date testing follows
+ iRc+= TestMethod( po, "IsNull", d1.IsNull(), xbFalse );
+ xbDate dN;
+ iRc+= TestMethod( po, "IsNull", dN.IsNull(), xbTrue );
+
+ xbDate dtNull1;
+ xbDate dtNull2;
+
+ iRc+= TestMethod( po, "dtNull1==dtNull2", dtNull1 == dtNull2, 1 );
+ iRc+= TestMethod( po, "dtNull1!=dtNull2", dtNull1 != dtNull2, 0 );
+
+ iRc+= TestMethod( po, "dtNull1 < d2", dtNull1 < d2, 1 );
+ iRc+= TestMethod( po, "dtNull1 > d2", dtNull1 > d2, 0 );
+ iRc+= TestMethod( po, "dtNull1 <= d2", dtNull1 <= d2, 1 );
+ iRc+= TestMethod( po, "dtNull1 >= d2", dtNull1 >= d2, 0 );
+
+ iRc+= TestMethod( po, "d2 < dtNull1", d2 < dtNull1, 0 );
+ iRc+= TestMethod( po, "d2 > dtNull1", d2 > dtNull1, 1 );
+ iRc+= TestMethod( po, "d2 <= dtNull1", d2 <= dtNull1, 0 );
+ iRc+= TestMethod( po, "d2 >= dtNull1", d2 >= dtNull1, 1 );
+
+
/*
xbDate d4( "20171015" );
std::cout << "day of [" << d4.Str() << "][" << d4.DayOf( XB_FMT_WEEK ) << "]\n";
diff --git a/src/tests/xb_test_dbf_v3_memos.cpp b/src/tests/xb_test_dbf_v3_memos.cpp
index e42edb1..7940c35 100755
--- a/src/tests/xb_test_dbf_v3_memos.cpp
+++ b/src/tests/xb_test_dbf_v3_memos.cpp
@@ -206,7 +206,6 @@ int main( int argCnt, char **av )
rc += TestMethod( po, "UpdateMemoField()", V3Dbf.UpdateMemoField( fldMemo2, sData ), XB_NO_ERROR );
rc += TestMethod( po, "AppendRecord()", V3Dbf.AppendRecord(), XB_NO_ERROR );
-
// Flag 1, 3, 5 and 7 for deletion
rc += TestMethod( po, "GetRecord()", V3Dbf.GetRecord( 1 ), XB_NO_ERROR );
rc += TestMethod( po, "DeleteRecord()", V3Dbf.DeleteRecord(), XB_NO_ERROR );
@@ -219,6 +218,7 @@ int main( int argCnt, char **av )
rc += TestMethod( po, "GetRecord()", V3Dbf.GetRecord( 7 ), XB_NO_ERROR );
rc += TestMethod( po, "DeleteRecord()", V3Dbf.DeleteRecord(), XB_NO_ERROR );
+
rc += TestMethod( po, "Pack()", V3Dbf.Pack(), XB_NO_ERROR );
xbString sDir;
@@ -228,8 +228,8 @@ int main( int argCnt, char **av )
sDbfName.Sprintf( "%snewV3nm.DBF", sDir.Str());
sDbtName.Sprintf( "%snewV3nm.DBT", sDir.Str());
- std::cout << "remove [" << sDbfName.Str() << "\n";
- std::cout << "remove [" << sDbtName.Str() << "\n";
+ //std::cout << "remove [" << sDbfName.Str() << "]\n";
+ //std::cout << "remove [" << sDbtName.Str() << "]\n";
V3Dbf.xbRemove( sDbfName );
V3Dbf.xbRemove( sDbtName );
diff --git a/src/tests/xb_test_dbf_v4_nomemos.cpp b/src/tests/xb_test_dbf_v4_nomemos.cpp
index 984eb63..dd4976d 100755
--- a/src/tests/xb_test_dbf_v4_nomemos.cpp
+++ b/src/tests/xb_test_dbf_v4_nomemos.cpp
@@ -125,8 +125,22 @@ int main( int argCnt, char **av )
rc += TestMethod( po, "GetFieldNo()", V4Dbf.GetFieldNo("LASTNAME"), 1 );
rc += TestMethod( po, "GetFieldNo()", V4Dbf.GetFieldNo("MIDDLEINIT"), 2 );
+ xbBool bIsNull;
+ rc += TestMethod( po, "GetNullSts()", V4Dbf.GetNullSts( V4Dbf.GetFieldNo("LASTNAME"), bIsNull, 0 ), XB_NO_ERROR );
+ rc += TestMethod( po, "GetNullSts()", bIsNull, xbTrue );
+
+
+
xbInt16 fldLastName = V4Dbf.GetFieldNo( "LASTNAME" );
rc += TestMethod( po, "PutField()", V4Dbf.PutField( fldLastName, "NELSON" ), XB_NO_ERROR );
+
+ rc += TestMethod( po, "GetNullSts()", V4Dbf.GetNullSts( V4Dbf.GetFieldNo("LASTNAME"), bIsNull, 0 ), XB_NO_ERROR );
+ rc += TestMethod( po, "GetNullSts()", bIsNull, xbFalse );
+
+ rc += TestMethod( po, "GetNullSts()", V4Dbf.GetNullSts( V4Dbf.GetFieldNo("FIRSTNAME"), bIsNull, 0 ), XB_NO_ERROR );
+ rc += TestMethod( po, "GetNullSts()", bIsNull, xbTrue );
+
+
rc += TestMethod( po, "PutField()", V4Dbf.PutField( "FIRSTNAME", "WILLIE" ), XB_NO_ERROR );
rc += TestMethod( po, "PutField()", V4Dbf.PutField( "AMOUNT", "12.34" ), XB_NO_ERROR );
xbDate dt( "19500209" );
diff --git a/src/tests/xb_test_expression.cpp b/src/tests/xb_test_expression.cpp
index ac1cde7..52c0b5c 100755
--- a/src/tests/xb_test_expression.cpp
+++ b/src/tests/xb_test_expression.cpp
@@ -384,6 +384,8 @@ int main( int argCnt, char **av )
{ "CHAR2", XB_CHAR_FLD, 7, 0 },
{ "DATE1", XB_DATE_FLD, 8, 0 },
{ "DATE2", XB_DATE_FLD, 8, 0 },
+ { "NULLDATE1", XB_DATE_FLD, 8, 0 },
+ { "NULLDATE2", XB_DATE_FLD, 8, 0 },
{ "NUM1", XB_NUMERIC_FLD, 9, 2 },
{ "",0,0,0 }
};
@@ -391,6 +393,10 @@ int main( int argCnt, char **av )
xbXBase x;
xbDbf * MyFile;
xbDate d;
+ xbDate dtTest1( "19890303" );
+ xbDate dtTest2( "20120708" );
+
+
#ifdef XB_LOGGING_SUPPORT
x.SetLogDirectory( PROJECT_LOG_DIR );
@@ -412,8 +418,6 @@ int main( int argCnt, char **av )
std::cout << "Default Data Directory is [" << x.GetDataDirectory().Str() << "]" << std::endl;
}
-// return 0;
-
#ifdef XB_DBF4_SUPPORT
MyFile = new xbDbf4( &x ); /* version 4 dbf file */
#else
@@ -421,13 +425,8 @@ int main( int argCnt, char **av )
#endif
-
-// return 0;
-
rc2 = MyFile->CreateTable( "ExpTest.DBF", "ExpTest", MyRecord, XB_OVERLAY, XB_MULTI_USER );
-// return 0;
-
iRc += TestMethod( po, "CreateTable()", rc2, XB_NO_ERROR );
iRc += TestMethod( po, "PutField()", MyFile->PutField( "CHAR1", "TEST" ), XB_NO_ERROR );
iRc += TestMethod( po, "PutField()", MyFile->PutField( "CHAR2", "TEST7B" ), XB_NO_ERROR );
@@ -437,8 +436,6 @@ int main( int argCnt, char **av )
iRc += TestMethod( po, "AppendRecord()", MyFile->AppendRecord(), XB_NO_ERROR );
-// return 0;
-
iRc += TestTokenMethod( &x, po, "EOX Test1", "", "", "", '?', XB_EXP_UNKNOWN, XB_NO_ERROR, XB_END_OF_EXPRESSION );
iRc += TestTokenMethod( &x, po, "EOX Test2 ", " ", "", "", '?', XB_EXP_UNKNOWN, XB_NO_ERROR, XB_END_OF_EXPRESSION );
@@ -634,49 +631,64 @@ int main( int argCnt, char **av )
iRc += TestMethod( &x, MyFile, po, "FuncTest41", "VAL( \"89\" )", (xbDouble) 89 );
iRc += TestMethod( &x, MyFile, po, "FuncTest42", "VAL( \"22.13 and some text\" )", (xbDouble) 22.13 );
iRc += TestMethod( &x, MyFile, po, "FuncTest43", "YEAR( STOD( \"20171017\" ))", (xbDouble) 2017 );
+ iRc += TestMethod( &x, MyFile, po, "FuncTest44", "CTOD( \"07\\08\\12\" )", dtTest2 );
+ xbDate dtToday;
+ dtToday.Sysdate();
+ iRc += TestMethod( &x, MyFile, po, "FuncTest45", "DATE()", dtToday );
+ dtTest2 = "28870625";
+ iRc += TestMethod( &x, MyFile, po, "FuncTest46", "DESCEND( DATE2 )", dtTest2 );
+ iRc += TestMethod( &x, MyFile, po, "FuncTest47", "STOD( \"19890303\" )", dtTest1 );
+
// date logic tests
- xbDate dtTest1( "19890303" );
- xbDate dtTest2( "20120708" );
+
iRc += TestMethod( &x, MyFile, po, "DateTest1", "ExpTest->DATE1", dtTest1 );
iRc += TestMethod( &x, MyFile, po, "DateTest2", "DATE1", dtTest1 );
+ dtTest2.Set( "20120708" );
iRc += TestMethod( &x, MyFile, po, "DateTest3", "ExpTest->DATE2", dtTest2 );
iRc += TestMethod( &x, MyFile, po, "DateTest4", "DATE2", dtTest2 );
iRc += TestMethod( &x, MyFile, po, "DateTest5", "DATE2 - DATE1", (xbDouble) 8528 );
+
dtTest1.Set( "20120705" );
iRc += TestMethod( &x, MyFile, po, "DateTest6", "DATE2 - 3", dtTest1 );
-
iRc += TestMethod( &x, MyFile, po, "DateTest7", "DATE2 -= 3", dtTest1 );
-
dtTest1.Set( "20120718" );
iRc += TestMethod( &x, MyFile, po, "DateTest8", "DATE2 + 10", dtTest1 );
iRc += TestMethod( &x, MyFile, po, "DateTest9", "DATE2 += 10", dtTest1 );
-
dtTest1.Set( "20120709" );
iRc += TestMethod( &x, MyFile, po, "DateTest10", "++DATE2", dtTest1 );
dtTest1.Set( "20120707" );
iRc += TestMethod( &x, MyFile, po, "DateTest11", "--DATE2", dtTest1 );
-
dtTest1.Set( "20120708" );
iRc += TestMethod( &x, MyFile, po, "DateTest12", "DATE2++", dtTest1 );
iRc += TestMethod( &x, MyFile, po, "DateTest13", "DATE2--", dtTest1 );
-
iRc += TestMethod( &x, MyFile, po, "DateTest14", "{07/08/12}", dtTest1 );
iRc += TestMethod( &x, MyFile, po, "DateTest15", "{07/08/2012}", dtTest1 );
-
iRc += TestMethod( &x, MyFile, po, "DateTest16", "{07/11/12} -3", dtTest1 );
iRc += TestMethod( &x, MyFile, po, "DateTest17", "{07/06/2012} + 2", dtTest1 );
- iRc += TestMethod( &x, MyFile, po, "FuncTest44", "CTOD( \"07\\08\\12\" )", dtTest1 );
-
- xbDate dtToday;
- iRc += TestMethod( &x, MyFile, po, "FuncTest45", "DATE()", dtToday );
-
- dtTest2 = "28870625";
- iRc += TestMethod( &x, MyFile, po, "FuncTest46", "DESCEND( DATE2 )", dtTest2 );
- iRc += TestMethod( &x, MyFile, po, "FuncTest47", "STOD( \"20120708\" )", dtTest1 );
+ iRc += TestMethod( &x, MyFile, po, "DateTest18", "ExpTest->NULLDATE1 = {07/06/2012}", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest19", "ExpTest->NULLDATE1 != {07/06/2012}", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest20", "ExpTest->NULLDATE1 < {07/06/2012}", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest21", "ExpTest->NULLDATE1 <= {07/06/2012}", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest22", "ExpTest->NULLDATE1 > {07/06/2012}", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest23", "ExpTest->NULLDATE1 >= {07/06/2012}", (xbBool) xbFalse );
+
+ iRc += TestMethod( &x, MyFile, po, "DateTest24", "{07/06/2012} = ExpTest->NULLDATE1", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest25", "{07/06/2012} != ExpTest->NULLDATE1", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest26", "{07/06/2012} < ExpTest->NULLDATE1", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest27", "{07/06/2012} <= ExpTest->NULLDATE1", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest28", "{07/06/2012} > ExpTest->NULLDATE1", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest29", "{07/06/2012} >= ExpTest->NULLDATE1", (xbBool) xbTrue );
+
+ iRc += TestMethod( &x, MyFile, po, "DateTest18", "ExpTest->NULLDATE1 = ExpTest->NULLDATE2", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest19", "ExpTest->NULLDATE1 != ExpTest->NULLDATE2", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest20", "ExpTest->NULLDATE1 < ExpTest->NULLDATE2", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest21", "ExpTest->NULLDATE1 <= ExpTest->NULLDATE2", (xbBool) xbTrue );
+ iRc += TestMethod( &x, MyFile, po, "DateTest22", "ExpTest->NULLDATE1 > ExpTest->NULLDATE2", (xbBool) xbFalse );
+ iRc += TestMethod( &x, MyFile, po, "DateTest23", "ExpTest->NULLDATE1 >= ExpTest->NULLDATE2", (xbBool) xbTrue );
// boolean logic tests
iRc += TestMethod( &x, MyFile, po, "LogicTest1", "3=5", (xbBool) xbFalse );
diff --git a/src/tests/xb_test_file.cpp b/src/tests/xb_test_file.cpp
index cf835c2..0db6eca 100755
--- a/src/tests/xb_test_file.cpp
+++ b/src/tests/xb_test_file.cpp
@@ -27,24 +27,24 @@ using namespace xb;
int main( int argCnt, char **av )
{
- int rc = 0;
- int po = 1; /* print option */
+ int iRc = 0;
+ int iPo = 1; /* print option */
/* 0 - QUIET */
/* 1 - NORMAL */
/* 2 - VERBOSE */
if( argCnt > 1 ) {
if( av[1][0] == 'Q' )
- po = 0;
+ iPo = 0;
else if( av[1][0] == 'V' )
- po = 2;
+ iPo = 2;
}
xbXBase x;
#ifdef XB_LOGGING_SUPPORT
x.SetLogDirectory( PROJECT_LOG_DIR );
x.EnableMsgLogging();
- if( po ){
+ if( iPo ){
std::cout << "Logfile is [" << x.GetLogFqFileName().Str() << "]" << std::endl;
}
xbString sMsg;
@@ -65,14 +65,14 @@ int main( int argCnt, char **av )
sWrkStr.SwapChars( '\\', '/' );
#endif
- rc += TestMethod( po, "Set/GetDataDirectory()", f.GetDataDirectory(), sWrkStr, sWrkStr.Len());
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", f.GetDataDirectory(), sWrkStr, sWrkStr.Len());
f.SetFileName( "TestFile.txt" );
sWrkStr = "TestFile.txt";
- rc += TestMethod( po, "Set/GetFileName()", f.GetFileName(), sWrkStr, sWrkStr.Len());
+ iRc += TestMethod( iPo, "Set/GetFileName()", f.GetFileName(), sWrkStr, sWrkStr.Len());
f.GetFileType( sWrkStr );
- rc += TestMethod( po, "GetFileType()", sWrkStr, "TXT", 3 );
+ iRc += TestMethod( iPo, "GetFileType()", sWrkStr, "TXT", 3 );
#ifdef WIN32
sWrkStr = "\\my\\directory\\";
@@ -81,10 +81,10 @@ int main( int argCnt, char **av )
#endif
f.SetDirectory( sWrkStr );
- rc += TestMethod( po, "Set/GetDirectory()", f.GetDirectory(), sWrkStr, sWrkStr.Len());
+ iRc += TestMethod( iPo, "Set/GetDirectory()", f.GetDirectory(), sWrkStr, sWrkStr.Len());
sWrkStr += "TestFile.txt";
- rc += TestMethod( po, "GetFqFileName()", f.GetFqFileName(), sWrkStr, 26 );
+ iRc += TestMethod( iPo, "GetFqFileName()", f.GetFqFileName(), sWrkStr, 26 );
#ifdef WIN32
sWrkStr = "\\some\\directory\\myfile.dat";
@@ -95,115 +95,115 @@ int main( int argCnt, char **av )
#endif
f.SetFqFileName( sWrkStr );
- rc += TestMethod( po, "GetDirectory()", f.GetDirectory(), sWrkStr2, 16 );
- rc += TestMethod( po, "GetFileName()", f.GetFileName(), "myfile.dat", 10 );
+ iRc += TestMethod( iPo, "GetDirectory()", f.GetDirectory(), sWrkStr2, 16 );
+ iRc += TestMethod( iPo, "GetFileName()", f.GetFileName(), "myfile.dat", 10 );
- rc += TestMethod( po, "NameSuffixMissing()", f.NameSuffixMissing( "myfile.dbf", 1 ), 0 );
- rc += TestMethod( po, "NameSuffixMissing()", f.NameSuffixMissing( "myfile", 1 ), 1 );
- rc += TestMethod( po, "NameSuffixMissing()", f.NameSuffixMissing( "MYFILE", 1 ), 2 );
+ iRc += TestMethod( iPo, "NameSuffixMissing()", f.NameSuffixMissing( "myfile.dbf", 1 ), 0 );
+ iRc += TestMethod( iPo, "NameSuffixMissing()", f.NameSuffixMissing( "myfile", 1 ), 1 );
+ iRc += TestMethod( iPo, "NameSuffixMissing()", f.NameSuffixMissing( "MYFILE", 1 ), 2 );
f.SetDirectory( PROJECT_DATA_DIR );
f.SetFileName( "xbfile.txt" );
- rc += TestMethod( po, "xbFopen()", f.xbFopen( "w+b", XB_MULTI_USER ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFopen()", f.xbFopen( "w+b", XB_MULTI_USER ), XB_NO_ERROR );
xbString sTest;
sTest = "Test Data";
- rc += TestMethod( po, "xbWrite()", f.xbFwrite( sTest.Str(), 9, 1 ), XB_NO_ERROR );
- rc += TestMethod( po, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbWrite()", f.xbFwrite( sTest.Str(), 9, 1 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
- rc += TestMethod( po, "xbFopen()", f.xbFopen( "r+b", XB_MULTI_USER ), XB_NO_ERROR );
- rc += TestMethod( po, "xbFseek()", f.xbFseek( 0, SEEK_SET ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFopen()", f.xbFopen( "r+b", XB_MULTI_USER ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFseek()", f.xbFseek( 0, SEEK_SET ), XB_NO_ERROR );
char buf[10];
for( int i = 0; i < 10; i++ )
buf[i] = 0x00;
- rc += TestMethod( po, "xbFread()", f.xbFread( buf, 5, 1 ), XB_NO_ERROR );
- rc += TestMethod( po, "xbFread()", buf, "Test ", 5 );
+ iRc += TestMethod( iPo, "xbFread()", f.xbFread( buf, 5, 1 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFread()", buf, "Test ", 5 );
- rc += TestMethod( po, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
- rc += TestMethod( po, "xbRemove()", f.xbRemove(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbRemove()", f.xbRemove(), XB_NO_ERROR );
xbInt16 iWork = 100;
char cBuf[9];
char *p = cBuf;
f.ePutInt16( cBuf, iWork );
- rc += TestMethod( po, "Put/GetShort()", f.eGetInt16( p ), 100 );
+ iRc += TestMethod( iPo, "Put/GetShort()", f.eGetInt16( p ), 100 );
xbInt32 lWork = 10101;
f.ePutInt32( p, lWork );
- rc += TestMethod( po, "Put/GetLong()", f.eGetInt32( p ), 10101 );
+ iRc += TestMethod( iPo, "Put/GetLong()", f.eGetInt32( p ), 10101 );
lWork = 2147483647;
f.ePutInt32( p, lWork );
- rc += TestMethod( po, "Put/GetLong()", f.eGetInt32( p ), 2147483647 );
- rc += TestMethod( po, "Put/GetLong()", (xbInt32) f.eGetUInt32( p ), 2147483647 );
+ iRc += TestMethod( iPo, "Put/GetLong()", f.eGetInt32( p ), 2147483647 );
+ iRc += TestMethod( iPo, "Put/GetLong()", (xbInt32) f.eGetUInt32( p ), 2147483647 );
xbDouble d = 123456.789;
f.ePutDouble( p, d );
- rc += TestMethod( po, "Put/GetDouble()", f.eGetDouble( p ), 123456.789 );
+ iRc += TestMethod( iPo, "Put/GetDouble()", f.eGetDouble( p ), 123456.789 );
xbString sFqnS;
xbString sFqnT;
xbFile f2( &x );
- rc += TestMethod( po, "CreateUniqueFileName()", f2.CreateUniqueFileName( PROJECT_DATA_DIR, "dbf", sFqnS ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "CreateUniqueFileName()", f2.CreateUniqueFileName( PROJECT_DATA_DIR, "dbf", sFqnS ), XB_NO_ERROR );
- rc += TestMethod( po, "FileExists()", f2.FileExists( sFqnS ), xbFalse );
- rc += TestMethod( po, "xbFopen()", f2.xbFopen( "w+b", sFqnS, XB_SINGLE_USER ), XB_NO_ERROR );
- rc += TestMethod( po, "xbFclose()", f2.xbFclose(), XB_NO_ERROR );
- rc += TestMethod( po, "FileExists()", f2.FileExists( sFqnS ), xbTrue );
+ iRc += TestMethod( iPo, "FileExists()", f2.FileExists( sFqnS ), xbFalse );
+ iRc += TestMethod( iPo, "xbFopen()", f2.xbFopen( "w+b", sFqnS, XB_SINGLE_USER ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFclose()", f2.xbFclose(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "FileExists()", f2.FileExists( sFqnS ), xbTrue );
- rc += TestMethod( po, "CreateUniqueFileName()", f2.CreateUniqueFileName( PROJECT_DATA_DIR, "dbf", sFqnT ), XB_NO_ERROR );
- rc += TestMethod( po, "xbRename()", f2.xbRename( sFqnS, sFqnT ), XB_NO_ERROR );
- rc += TestMethod( po, "xbRemove()", f.xbRemove( sFqnT ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "CreateUniqueFileName()", f2.CreateUniqueFileName( PROJECT_DATA_DIR, "dbf", sFqnT ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbRename()", f2.xbRename( sFqnS, sFqnT ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbRemove()", f.xbRemove( sFqnT ), XB_NO_ERROR );
xbString sFn;
- rc += TestMethod( po, "GetFileNamePart()", f2.GetFileNamePart( sFqnS , sFn ), XB_NO_ERROR );
- rc += TestMethod( po, "GetFileExtPart()", f2.GetFileExtPart( sFqnS , sFn ), XB_NO_ERROR );
- rc += TestMethod( po, "GetFileExtPart()", f2.GetFileDirPart( sFqnS , sFn ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "GetFileNamePart()", f2.GetFileNamePart( sFqnS , sFn ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "GetFileExtPart()", f2.GetFileExtPart( sFqnS , sFn ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "GetFileExtPart()", f2.GetFileDirPart( sFqnS , sFn ), XB_NO_ERROR );
- rc += TestMethod( po, "SetBlockSize()", f.SetBlockSize( 100 ), XB_INVALID_BLOCK_SIZE );
- rc += TestMethod( po, "SetBlockSize()", f.SetBlockSize( 512 ), XB_NO_ERROR );
- rc += TestMethod( po, "GetBlockSize()", (xbInt32) f.GetBlockSize(), 512 );
+ iRc += TestMethod( iPo, "SetBlockSize()", f.SetBlockSize( 100 ), XB_INVALID_BLOCK_SIZE );
+ iRc += TestMethod( iPo, "SetBlockSize()", f.SetBlockSize( 512 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "GetBlockSize()", (xbInt32) f.GetBlockSize(), 512 );
char BlockBuf[513];
memset( BlockBuf, 0x00, 513 );
- rc += TestMethod( po, "xbFopen()", f.xbFopen( "w+b", XB_SINGLE_USER ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbFopen()", f.xbFopen( "w+b", XB_SINGLE_USER ), XB_NO_ERROR );
for( int i = 0; i < 512; i++ )
BlockBuf[i] = 'A';
- rc += TestMethod( po, "WriteBlock()", f.WriteBlock( 0L, 512, BlockBuf ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "WriteBlock()", f.WriteBlock( 0L, 512, BlockBuf ), XB_NO_ERROR );
for( int i = 0; i < 512; i++ )
BlockBuf[i] = 'B';
- rc += TestMethod( po, "WriteBlock()", f.WriteBlock( 1L, 512, BlockBuf ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "WriteBlock()", f.WriteBlock( 1L, 512, BlockBuf ), XB_NO_ERROR );
for( int i = 0; i < 512; i++ )
BlockBuf[i] = 'C';
- rc += TestMethod( po, "WriteBlock()", f.WriteBlock( 2L, 512, BlockBuf ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "WriteBlock()", f.WriteBlock( 2L, 512, BlockBuf ), XB_NO_ERROR );
char BlockBuf2[513];
memset( BlockBuf2, 0x00, 513 );
- rc += TestMethod( po, "ReadBlock()", f.ReadBlock( 2L, 512, BlockBuf2 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "ReadBlock()", f.ReadBlock( 2L, 512, BlockBuf2 ), XB_NO_ERROR );
xbString s1 = BlockBuf;
xbString s2 = BlockBuf2;
- rc += TestMethod( po, "ReadBlock()", s1, s2, 512 );
-
- rc += TestMethod( po, "xbTruncate()", f.xbTruncate( 1000 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "ReadBlock()", s1, s2, 512 );
+ iRc += TestMethod( iPo, "xbTruncate()", f.xbTruncate( 1000 ), XB_NO_ERROR );
xbUInt64 ullFsize;
- rc += TestMethod( po, "GetFileSize()", f.GetFileSize( ullFsize ), XB_NO_ERROR );
- rc += TestMethod( po, "xbGetFileSize()", (xbInt32) ullFsize, 1000 );
- rc += TestMethod( po, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "GetFileSize()", f.GetFileSize( ullFsize ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "xbGetFileSize()", (xbInt32) ullFsize, 1000 );
+ iRc += TestMethod( iPo, "xbFclose()", f.xbFclose(), XB_NO_ERROR );
+
- if( po > 0 || rc < 0 )
- fprintf( stdout, "Total Errors = %d\n", rc * -1 );
+ if( iPo > 0 || iRc < 0 )
+ fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
#ifdef XB_LOGGING_SUPPORT
- sMsg.Sprintf( "Program [%s] terminating with [%d] errors...", av[0], rc * -1 );
+ sMsg.Sprintf( "Program [%s] terminating with [%d] errors...", av[0], iRc * -1 );
x.WriteLogMessage( sMsg );
#endif
- return rc;
+ return iRc;
}
diff --git a/src/tests/xb_test_funcs.cpp b/src/tests/xb_test_funcs.cpp
index c7bf0d3..7eb8b16 100755
--- a/src/tests/xb_test_funcs.cpp
+++ b/src/tests/xb_test_funcs.cpp
@@ -125,6 +125,8 @@ int main( int argCnt, char **av )
iRc += TestMethod( po, "CTOD( \"01\\03\\87\", dtResult )", x.CTOD( "01\\03\\87", dtResult ), XB_NO_ERROR );
iRc += TestMethod( po, "CTOD( \"01\\03\\87\", dtResult )", dtResult.Str(), "19870103", 8 );
iRc += TestMethod( po, "DATE( dtResult )", x.DATE( dtResult ), XB_NO_ERROR );
+
+ d.Sysdate();
iRc += TestMethod( po, "DATE( dtResult )", dtResult.Str(), d.Str(), 8 );
iRc += TestMethod( po, "DAY(\"19870103\", dResult )", x.DAY( "19870103", dResult ), XB_NO_ERROR );
iRc += TestMethod( po, "DAY(\"19870103\", dResult )", dResult, (xbDouble) 3 );
@@ -229,6 +231,7 @@ int main( int argCnt, char **av )
iRc += TestMethod( po, "x.RTRIM( \"zzz \", sResult )", sResult, "zzz", 3 );
iRc += TestMethod( po, "x.TRIM( \"aaa \", sResult )", x.TRIM( "aaa ", sResult ), XB_NO_ERROR );
iRc += TestMethod( po, "x.TRIM( \"aaa \", sResult )", sResult, "aaa", 3 );
+
iRc += TestMethod( po, "x.SPACE( 3, sResult )", x.SPACE( 3, sResult ), XB_NO_ERROR );
iRc += TestMethod( po, "x.SPACE( 3, sResult )", sResult, " ", 3 );
iRc += TestMethod( po, "x.SQRT( 9, dResult )", x.SQRT( 9, dResult ), XB_NO_ERROR );
diff --git a/src/tests/xb_test_lock.cpp b/src/tests/xb_test_lock.cpp
index 39332ad..2df71a8 100755
--- a/src/tests/xb_test_lock.cpp
+++ b/src/tests/xb_test_lock.cpp
@@ -34,7 +34,8 @@ int main( int argCnt, char **av )
/* 2 - VERBOSE */
xbInt16 iErrorStop = 0;
- xbString sLockFile = "locktest.txt";
+ xbString sLockFile;
+ xbString sLockFile2;
xbString sLockCmd;
xbString sResult;
@@ -69,23 +70,34 @@ int main( int argCnt, char **av )
x.WriteLogMessage( sMsg );
#endif
+
x.SetDataDirectory( PROJECT_DATA_DIR );
InitTime();
#ifdef XB_DBF4_SUPPORT
- MyFile = new xbDbf4( &x ); /* version 4 dbf file */
+ MyFile = new xbDbf4( &x ); // version 4 dbf file
#else
- MyFile = new xbDbf3( &x ); /* version 3 dbf file */
+ MyFile = new xbDbf3( &x ); // version 3 dbf file
#endif
iRc2 = MyFile->CreateTable( "LockTest.DBF", "LockTest", MyRecord, XB_OVERLAY, XB_MULTI_USER );
iRc += TestMethod( po, "CreateTable()", iRc2, XB_NO_ERROR );
+
+ #ifdef XB_MDX_SUPPORT
+ xbIx *ixPtr;
+ void *pTag;
+ iRc2 = MyFile->CreateTag( "MDX", "LockTag", "LOCKTEST", "", 0, 0, XB_OVERLAY, &ixPtr, &pTag );
+ iRc += TestMethod( po, "CreateTag()", iRc2, XB_NO_ERROR );
+ #endif // XB_MDX_SUPPORT
+
+
iRc += TestMethod( po, "PutField()", MyFile->PutField( "LOCKTEST", "TEST" ), XB_NO_ERROR );
iRc += TestMethod( po, "AppendRecord()", MyFile->AppendRecord(), XB_NO_ERROR );
- iRc += TestMethod( po, "Close()", MyFile->Close(), XB_NO_ERROR );
- MyFile->Close();
+ iRc += TestMethod( po, "Close()", MyFile->Close(), XB_NO_ERROR );
+
+ sLockFile.Sprintf( "%slocktest.txt", PROJECT_DATA_DIR );
+ // std::cout << "xb_test_lock - lockfile = [ " << sLockFile.Str() << "]\n";
- //unlink( sLockFile );
- remove( sLockFile );
+ remove( sLockFile.Str() );
#if defined (HAVE_FORK_F)
pid_t pid;
@@ -104,14 +116,15 @@ int main( int argCnt, char **av )
xbString sLastLockCmd;
#ifdef XB_DBF4_SUPPORT
- MyFileChld = new xbDbf4( &x ); /* version 4 dbf file */
+ MyFileChld = new xbDbf4( &x ); // version 4 dbf file
#else
- MyFileChld = new xbDbf3( &x ); /* version 3 dbf file */
+ MyFileChld = new xbDbf3( &x ); // version 3 dbf file
#endif
x.xbSleep( 250 );
while( !bDone ){
+
iRc2 = GetCmd( x, sLockFile, sLockCmd, 'C', po );
if( sLockCmd == sLastLockCmd )
@@ -139,7 +152,6 @@ int main( int argCnt, char **av )
x.xbSleep( 250 );
} else {
-
if( sLockCmd == "START" ){
// begin the process
iRcChld = MyFileChld->Open( "LockTest.DBF" );
@@ -199,8 +211,31 @@ int main( int argCnt, char **av )
#else
sLockCmd = "OK";
#endif
+
+ } else if( sLockCmd == "IL" ){
+ // index lock
+ #ifdef XB_MDX_SUPPORT
+ if(( iRcChld = MyFileChld->LockIndices( XB_LOCK )) != XB_NO_ERROR )
+ sResult = "FAIL";
+ else
+ sResult = "OK";
+ #else
+ sLockCmd = "OK";
+ #endif // XB_MDX_SUPPORT
+
+ } else if( sLockCmd == "IU" ){
+ // index unlock
+ #ifdef XB_MDX_SUPPORT
+ if(( iRcChld = MyFileChld->LockIndices( XB_UNLOCK )) != XB_NO_ERROR )
+ sResult = "FAIL";
+ else
+ sResult = "OK";
+ #else
+ sLockCmd = "OK";
+ #endif // XB_MDX_SUPPORT
}
+
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Child task [%s] Result [%s] RC = [%d]", av[0], sLockCmd.Str(), sResult.Str(), iRcChld );
x.WriteLogMessage( sMsg );
@@ -212,7 +247,6 @@ int main( int argCnt, char **av )
delete MyFileChld;
}
}
-
} else {
iRc = iRc2;
bDone = xbTrue;
@@ -226,6 +260,8 @@ int main( int argCnt, char **av )
delete MyFile;
delete MyFileChld;
+ remove( sLockFile );
+
if( po > 0 )
std::cout << "Exiting child\n";
@@ -241,9 +277,7 @@ int main( int argCnt, char **av )
xbInt16 iLoopCtr = 0;
try{
-
// start
-
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing START command", av[0] );
x.WriteLogMessage( sMsg );
@@ -266,7 +300,7 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 10;
+ iErrorStop = 100;
iRc2 = -1;
throw iRc2;
}
@@ -294,19 +328,19 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 20;
+ iErrorStop = 110;
iRc2 = -1;
throw iRc2;
}
// attempt to lock table, should fail
if(( iRc2 = MyFile->Open( "LockTest.DBF" )) != XB_NO_ERROR ){
- iErrorStop = 30;
+ iErrorStop = 120;
throw iRc2;
}
if(( iRc2 = MyFile->LockTable( XB_LOCK )) == XB_NO_ERROR ){
- iErrorStop = 40;
+ iErrorStop = 130;
throw iRc2;
}
@@ -336,24 +370,24 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 50;
+ iErrorStop = 140;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockTable( XB_LOCK )) != XB_NO_ERROR ){
- iErrorStop = 60;
+ iErrorStop = 150;
throw iRc2;
}
if( po > 0 )
std::cout << "[PASS] LockTable Test 2\n";
if(( iRc2 = MyFile->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
- iErrorStop = 70;
+ iErrorStop = 160;
throw iRc2;
}
- /* record lock */
+ // record lock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing RL command", av[0] );
x.WriteLogMessage( sMsg );
@@ -376,19 +410,19 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 80;
+ iErrorStop = 170;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockRecord( XB_LOCK, 1 )) == XB_NO_ERROR ){
- iErrorStop = 90;
+ iErrorStop = 180;
throw iRc2;
}
if( po > 0 )
std::cout << "[PASS] LockRecord Test 1\n";
- /* record unlock */
+ // record unlock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing RU command", av[0] );
x.WriteLogMessage( sMsg );
@@ -411,29 +445,29 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 100;
+ iErrorStop = 190;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockRecord( XB_LOCK, 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
+ iErrorStop = 200;
throw iRc2;
}
std::cout << "[PASS] LockRecord Test 2\n";
if(( iRc2 = MyFile->LockRecord( XB_UNLOCK, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
+ iErrorStop = 210;
throw iRc2;
}
- /* memo lock */
+ // memo lock
#ifdef XB_MEMO_SUPPORT
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing ML command", av[0] );
x.WriteLogMessage( sMsg );
- #endif
+ #endif // XB_LOGGING_SUPPORT
sLockCmd = "ML";
SetCmd( x, sLockFile, sLockCmd, 'P', po );
@@ -449,26 +483,26 @@ int main( int argCnt, char **av )
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
x.WriteLogMessage( sMsg );
- #endif
+ #endif // XB_LOGGING_SUPPORT
if( sResult != "OK" ){
- iErrorStop = 130;
+ iErrorStop = 220;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockMemo( XB_LOCK )) == XB_NO_ERROR ){
- iErrorStop = 140;
+ iErrorStop = 230;
throw iRc2;
}
if( po > 0 )
std::cout << "[PASS] LockMemo Test 1\n";
- /* memo unlock */
+ // memo unlock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing MU command", av[0] );
x.WriteLogMessage( sMsg );
- #endif
+ #endif // XB_LOGGING_SUPPORT
sLockCmd = "MU";
SetCmd( x, sLockFile, sLockCmd, 'P', po );
@@ -484,30 +518,110 @@ int main( int argCnt, char **av )
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
x.WriteLogMessage( sMsg );
- #endif
+ #endif // XB_LOGGING_SUPPORT
if( sResult != "OK" ){
- iErrorStop = 150;
+ iErrorStop = 240;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockMemo( XB_LOCK )) != XB_NO_ERROR ){
- iErrorStop = 160;
+ iErrorStop = 250;
throw iRc2;
}
std::cout << "[PASS] LockMemo Test 2\n";
if(( iRc2 = MyFile->LockMemo( XB_UNLOCK )) != XB_NO_ERROR ){
- iErrorStop = 170;
+ iErrorStop = 260;
throw iRc2;
}
- #endif
+ #endif // XB_MEMO_SUPPORT
+
+ // index lock
+ #ifdef XB_MDX_SUPPORT
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task issuing IL command", av[0] );
+ x.WriteLogMessage( sMsg );
+ #endif // XB_LOGGING_SUPPORT
+
+ sLockCmd = "IL";
+ SetCmd( x, sLockFile, sLockCmd, 'P', po );
+ sResult = "";
+
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 30 ){
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ x.xbSleep( 250 );
+ iLoopCtr++;
+ }
+
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
+ x.WriteLogMessage( sMsg );
+ #endif // XB_LOGGING_SUPPORT
+
+ if( sResult != "OK" ){
+ iErrorStop = 270;
+ iRc2 = -1;
+ throw iRc2;
+ }
+
+ if(( iRc2 = MyFile->LockIndices( XB_LOCK )) == XB_NO_ERROR ){
+ iErrorStop = 280;
+ throw iRc2;
+ }
+ if( po > 0 )
+ std::cout << "[PASS] LockIndex Test 1\n";
+
+ // memo unlock
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task issuing IU command", av[0] );
+ x.WriteLogMessage( sMsg );
+ #endif // XB_LOGGING_SUPPORT
+
+ sLockCmd = "IU";
+ SetCmd( x, sLockFile, sLockCmd, 'P', po );
+ sResult = "";
+
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 30 ){
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ x.xbSleep( 250 );
+ iLoopCtr++;
+ }
+
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
+ x.WriteLogMessage( sMsg );
+ #endif // XB_LOGGING_SUPPORT
+
+ if( sResult != "OK" ){
+ iErrorStop = 290;
+ iRc2 = -1;
+ throw iRc2;
+ }
+
+ if(( iRc2 = MyFile->LockIndices( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 300;
+ throw iRc2;
+ }
+
+ std::cout << "[PASS] LockIndex Test 2\n";
+ if(( iRc2 = MyFile->LockMemo( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 310;
+ throw iRc2;
+ }
+ #endif // XB_MDX_SUPPORT
+
+
// exit
sLockCmd = "EXIT";
SetCmd( x, sLockFile, sLockCmd, 'P', po );
+
+
} catch (xbInt16 iRc3 ){
iRc = iRc3;
if( po > 0 )
@@ -533,6 +647,7 @@ int main( int argCnt, char **av )
SetCmd( x, sLockFile, sLockCmd, 'P', po );
MyFile->Close();
delete MyFile;
+
}
#elif defined (HAVE_CREATEPROCESSW_F)
@@ -578,7 +693,7 @@ int main( int argCnt, char **av )
GetCmd( x, sLockFile, sResult, 'P', po );
while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 10 ){
GetCmd( x, sLockFile, sResult, 'P', po );
- x.xbSleep( 250 );
+ x.xbSleep( 300 );
iLoopCtr++;
}
@@ -600,7 +715,7 @@ int main( int argCnt, char **av )
GetCmd( x, sLockFile, sResult, 'P', po );
while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 10 ){
GetCmd( x, sLockFile, sResult, 'P', po );
- x.xbSleep( 250 );
+ x.xbSleep( 310 );
iLoopCtr++;
}
@@ -610,19 +725,19 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 200;
+ iErrorStop = 320;
iRc2 = -1;
throw iRc2;
}
// attempt to lock table, should fail
if(( iRc2 = MyFile->Open( "LockTest.DBF" )) != XB_NO_ERROR ){
- iErrorStop = 210;
+ iErrorStop = 330;
throw iRc2;
}
if(( iRc2 = MyFile->LockTable( XB_LOCK )) == XB_NO_ERROR ){
- iErrorStop = 220;
+ iErrorStop = 340;
throw iRc2;
}
@@ -658,13 +773,13 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 230;
+ iErrorStop = 350;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockTable( XB_LOCK )) != XB_NO_ERROR ){
- iErrorStop = 240;
+ iErrorStop = 360;
throw iRc2;
}
if( po > 0 ){
@@ -676,11 +791,11 @@ int main( int argCnt, char **av )
}
if(( iRc2 = MyFile->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
- iErrorStop = 250;
+ iErrorStop = 370;
throw iRc2;
}
- /* record lock */
+ // record lock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing RL command", av[0] );
x.WriteLogMessage( sMsg );
@@ -693,7 +808,7 @@ int main( int argCnt, char **av )
GetCmd( x, sLockFile, sResult, 'P', po );
while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 10 ){
GetCmd( x, sLockFile, sResult, 'P', po );
- x.xbSleep( 250 );
+ x.xbSleep( 380 );
iLoopCtr++;
}
@@ -703,19 +818,19 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 260;
+ iErrorStop = 390;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockRecord( XB_LOCK, 1 )) == XB_NO_ERROR ){
- iErrorStop = 270;
+ iErrorStop = 400;
throw iRc2;
}
if( po > 0 )
std::cout << "[PASS] LockRecord Test 1\n";
- /* record unlock */
+ // record unlock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing RU command", av[0] );
x.WriteLogMessage( sMsg );
@@ -738,24 +853,23 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 280;
+ iErrorStop = 410;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockRecord( XB_LOCK, 1 )) != XB_NO_ERROR ){
- iErrorStop = 290;
+ iErrorStop = 420;
throw iRc2;
}
std::cout << "[PASS] LockRecord Test 2\n";
if(( iRc2 = MyFile->LockRecord( XB_UNLOCK, 1 )) != XB_NO_ERROR ){
- iErrorStop = 300;
+ iErrorStop = 430;
throw iRc2;
}
-
- /* memo lock */
+ // memo lock
#ifdef XB_MEMO_SUPPORT
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing ML command", av[0] );
@@ -779,19 +893,19 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 310;
+ iErrorStop = 440;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockMemo( XB_LOCK )) == XB_NO_ERROR ){
- iErrorStop = 320;
+ iErrorStop = 450;
throw iRc2;
}
if( po > 0 )
std::cout << "[PASS] LockMemo Test 1\n";
- /* memo unlock */
+ // memo unlock
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Parent task issuing MU command", av[0] );
x.WriteLogMessage( sMsg );
@@ -814,19 +928,95 @@ int main( int argCnt, char **av )
#endif
if( sResult != "OK" ){
- iErrorStop = 330;
+ iErrorStop = 460;
iRc2 = -1;
throw iRc2;
}
if(( iRc2 = MyFile->LockMemo( XB_LOCK )) != XB_NO_ERROR ){
- iErrorStop = 340;
+ iErrorStop = 470;
throw iRc2;
}
std::cout << "[PASS] LockMemo Test 2\n";
if(( iRc2 = MyFile->LockMemo( XB_UNLOCK )) != XB_NO_ERROR ){
- iErrorStop = 350;
+ iErrorStop = 480;
+ throw iRc2;
+ }
+ #endif
+
+ // index lock
+ #ifdef XB_MDX_SUPPORT
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task issuing IL command", av[0] );
+ x.WriteLogMessage( sMsg );
+ #endif
+
+ sLockCmd = "IL";
+ SetCmd( x, sLockFile, sLockCmd, 'P', po );
+ sResult = "";
+
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 10 ){
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ x.xbSleep( 490 );
+ iLoopCtr++;
+ }
+
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
+ x.WriteLogMessage( sMsg );
+ #endif
+
+ if( sResult != "OK" ){
+ iErrorStop = 500;
+ iRc2 = -1;
+ throw iRc2;
+ }
+
+ if(( iRc2 = MyFile->LockIndices( XB_LOCK )) == XB_NO_ERROR ){
+ iErrorStop = 510;
+ throw iRc2;
+ }
+ if( po > 0 )
+ std::cout << "[PASS] LockIndex Test 1\n";
+
+ // index unlock
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task issuing IU command", av[0] );
+ x.WriteLogMessage( sMsg );
+ #endif
+
+ sLockCmd = "IU";
+ SetCmd( x, sLockFile, sLockCmd, 'P', po );
+ sResult = "";
+
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ while( sResult != "OK" && sResult != "FAIL" && iLoopCtr < 10 ){
+ GetCmd( x, sLockFile, sResult, 'P', po );
+ x.xbSleep( 250 );
+ iLoopCtr++;
+ }
+
+ #ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] Parent task retrieved result [%s]", av[0], sResult.Str() );
+ x.WriteLogMessage( sMsg );
+ #endif
+
+ if( sResult != "OK" ){
+ iErrorStop = 520;
+ iRc2 = -1;
+ throw iRc2;
+ }
+
+ if(( iRc2 = MyFile->LockIndices( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 530;
+ throw iRc2;
+ }
+
+ std::cout << "[PASS] LockIndex Test 2\n";
+ if(( iRc2 = MyFile->LockIndices( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 540;
throw iRc2;
}
#endif
@@ -835,6 +1025,7 @@ int main( int argCnt, char **av )
sLockCmd = "EXIT";
SetCmd( x, sLockFile, sLockCmd, 'P', po );
+
} catch (xbInt16 iRc3 ){
if( po > 0 )
std::cout << "Parent lock task exiting on failure [" << sLockCmd.Str() << "][" << iErrorStop << "]\n";
@@ -852,6 +1043,7 @@ int main( int argCnt, char **av )
}
#else
+
iRc--;
sMsg.Sprintf( "Program [%s] not executed. Library does not support 'fork' or 'CreateProcess' function call", av[0] );
#ifdef XB_LOGGING_SUPPORT
diff --git a/src/tests/xb_test_lock2.cpp b/src/tests/xb_test_lock2.cpp
index d5534ec..82b4dea 100755
--- a/src/tests/xb_test_lock2.cpp
+++ b/src/tests/xb_test_lock2.cpp
@@ -38,8 +38,7 @@ int main( int argCnt, char **av )
/* 2 - VERBOSE */
xbBool bDone = xbFalse;
-// xbInt16 iErrorStop = 0;
- xbString sLockFile = "locktest.txt";
+ xbString sLockFile;
xbString sLockCmd;
xbString sResult;
xbInt32 iChildLoop = 0;
@@ -74,6 +73,9 @@ int main( int argCnt, char **av )
x.SetDataDirectory( PROJECT_DATA_DIR );
InitTime();
+ sLockFile.Sprintf( "%slocktest.txt", PROJECT_DATA_DIR );
+ // std::cout << "xb_test_lock2 - lockfile = [ " << sLockFile.Str() << "]\n";
+
#ifdef XB_DBF4_SUPPORT
MyFile = new xbDbf4( &x ); /* version 4 dbf file */
#else
@@ -166,7 +168,31 @@ int main( int argCnt, char **av )
#else
sLockCmd = "OK";
#endif
+
+ } else if( sLockCmd == "IL" ){
+ // index lock
+ #ifdef XB_MDX_SUPPORT
+ if(( iRc2 = MyFile->LockIndices( XB_LOCK )) != XB_NO_ERROR )
+ sResult = "FAIL";
+ else
+ sResult = "OK";
+ #else
+ sLockCmd = "OK";
+ #endif
+
+ } else if( sLockCmd == "IU" ){
+ // index unlock
+ #ifdef XB_MDX_SUPPORT
+ if(( iRc2 = MyFile->LockIndices( XB_UNLOCK )) != XB_NO_ERROR )
+ sResult = "FAIL";
+ else
+ sResult = "OK";
+ #else
+ sLockCmd = "OK";
+ #endif
}
+
+
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Child task [%s] Result [%s] RC = [%d]", av[0], sLockCmd.Str(), sResult.Str(), iRc2 );
x.WriteLogMessage( sMsg );
@@ -188,7 +214,7 @@ int main( int argCnt, char **av )
if( po > 0 )
std::cout << "Exiting child\n";
- remove( sLockFile );
+ remove( sLockFile.Str() );
#ifdef XB_LOGGING_SUPPORT
sMsg.Sprintf( "Program [%s] Child task terminating", av[0] );
x.WriteLogMessage( sMsg );
@@ -202,6 +228,6 @@ int main( int argCnt, char **av )
x.WriteLogMessage( sMsg );
#endif
- ExitProcess( iRc );
+ ExitProcess( (xbUInt32) iRc );
}
diff --git a/src/tests/xb_test_log.cpp b/src/tests/xb_test_log.cpp
index 28ae552..a586809 100755
--- a/src/tests/xb_test_log.cpp
+++ b/src/tests/xb_test_log.cpp
@@ -41,7 +41,7 @@ int main( int argCnt, char **av )
}
xbXBase x;
- x.SetLogDirectory( PROJECT_LOG_DIR );
+
x.EnableMsgLogging();
InitTime();
if( po ){
@@ -51,28 +51,58 @@ int main( int argCnt, char **av )
sMsg.Sprintf( "Program [%s] initializing...", av[0] );
x.WriteLogMessage( sMsg );
- xbString sNewLogFileName = "Logfile2.txt";
- sMsg.Sprintf( "Switching to logfile [%s]", sNewLogFileName.Str() );
- x.WriteLogMessage( sMsg );
+ // verify first logfile location is correct
+ xbString sWork;
+ x.GetHomeDir( sWork );
+ std::cout << "Home Dir = " << sWork.Str() << std::endl;
+
+ // verify home directory > 0 length
+ xbInt32 iLen = (xbInt32) sWork.Len();
+ if( sWork.Len() == 0 )
+ rc += TestMethod( po, "GetHomeDir()", iLen, 1 );
+ else
+ rc += TestMethod( po, "GetHomeDir()", iLen, iLen );
+
+ sWork.Sprintf( "%s%cxbase64%clogs", sWork.Str(),
+ x.GetPathSeparator(), x.GetPathSeparator());
+
+ // verify path exists
+ // std::cout << "Home Dir = " << sHomeDir.Str() << std::endl;
+ xbFile f( &x );
+ rc += TestMethod( po, "FileExists()", f.FileExists( sWork ), xbTrue );
+
+
+ sWork.Sprintf( "%s%c%s", sWork.Str(),
+ x.GetPathSeparator(), x.GetLogFileName().Str() );
+
+ // std::cout << "Home Dir = " << sWork.Str() << std::endl;
+ rc += TestMethod( po, "FileExists()", f.FileExists( sWork ), xbTrue );
+ rc += TestMethod( po, "Get Log Status()", x.GetLogStatus(), xbTrue );
+
x.DisableMsgLogging();
- rc += TestMethod( po, "Set/Get Log Status()", x.GetLogStatus(), xbFalse );
- x.SetLogFileName( sNewLogFileName );
+ rc += TestMethod( po, "Get Log Status()", x.GetLogStatus(), xbFalse );
+ xbString sNewLogFileName = "Logfile2.txt";
+ x.SetLogDirectory( PROJECT_LOG_DIR );
+ x.SetLogFileName( sNewLogFileName );
+ sWork.Sprintf( "%s%c%s",
+ PROJECT_LOG_DIR, x.GetPathSeparator(), sNewLogFileName.Str());
+
+ sMsg.Sprintf( "Switching to logfile [%s]", sWork.Str() );
x.EnableMsgLogging();
- rc += TestMethod( po, "Set/Get Log Status()", x.GetLogStatus(), 1 );
- rc += TestMethod( po,"WriteLogMessage()", x.WriteLogMessage( "Test log message........" ), XB_NO_ERROR );
+ rc += TestMethod( po, "Get Log Status()", x.GetLogStatus(), xbTrue );
+ rc += TestMethod( po, "FileExists()", f.FileExists( sWork ), xbTrue );
- sMsg.Sprintf( "Program [%s] terminating with [%d] errors...", av[0], rc * -1 );
x.WriteLogMessage( sMsg );
+ rc += TestMethod( po, "Get Log Status()", x.GetLogStatus(), xbTrue );
+ x.WriteLogMessage( "Test Log Message" );
if( po > 0 || rc < 0 )
fprintf( stdout, "Total Errors = %d\n", rc * -1 );
-
#endif /* XB_LOGGING_SUPPORT */
-
return rc;
}
diff --git a/src/tests/xb_test_mdx.cpp b/src/tests/xb_test_mdx.cpp
index 2ef5ffb..680be5c 100755
--- a/src/tests/xb_test_mdx.cpp
+++ b/src/tests/xb_test_mdx.cpp
@@ -1,4 +1,4 @@
-/* xb_test_ndx.cpp
+/* xb_test_mdx.cpp
XBase64 Software Library
@@ -280,9 +280,18 @@ int main( int argCnt, char **av )
iRc += TestMethod( iPo, "CheckTagIntegrity(7)", V4DbfX2->CheckTagIntegrity( 1, 2 ), XB_NO_ERROR );
+
+
+ iRc2 = V4DbfX2->CreateTag( "MDX", "TAG2", "CHAR27", ".NOT. DELETED()", 0, 1, XB_OVERLAY, &pIx, &pTag );
+ iRc += TestMethod( iPo, "CreateTag(5)", iRc2, 0 );
+
+ iRc2 += V4DbfX2->Reindex( 1 );
+ iRc += TestMethod( iPo, "Reindex()", iRc2, XB_KEY_NOT_UNIQUE );
+
+
x.CloseAllTables();
- delete V4DbfX1;
- delete V4DbfX2;
+// delete V4DbfX1;
+// delete V4DbfX2;
if( iPo > 0 || iRc < 0 )
fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
diff --git a/src/tests/xb_test_ndx.cpp b/src/tests/xb_test_ndx.cpp
index 34496b6..320a1c9 100755
--- a/src/tests/xb_test_ndx.cpp
+++ b/src/tests/xb_test_ndx.cpp
@@ -117,6 +117,14 @@ int main( int argCnt, char **av )
iRc2 = V3Dbf->AssociateIndex( "NDX", "TestNdxN.NDX", 0 );
iRc += TestMethod( iPo, "Associate()", (xbInt32) iRc2, XB_NO_ERROR );
+ xbInt16 iTagCnt = ixPtr->GetTagCount();
+ iRc += TestMethod( iPo, "GetTagCount()", (xbInt32) iTagCnt, 1 );
+
+ xbString sTagName;
+ sTagName = ixPtr->GetTagName( &ndx );
+ iRc += TestMethod( iPo, "GetTagName()", sTagName.Str(), "TestNdxN", 8 );
+
+
#ifdef XB_LOCKING_SUPPORT
iRc += TestMethod( iPo, "LockTable()", V3Dbf->LockTable( XB_LOCK ), XB_NO_ERROR );
#endif
@@ -307,13 +315,12 @@ int main( int argCnt, char **av )
xbIxList *ixl = V3Dbf->GetIxList();
xbIxNdx *ix;
- xbString sTagName;
while( ixl ){
if( *ixl->sFmt == "NDX" ){
ix = (xbIxNdx *) ixl->ix;
//ix->GetTagName( 0, sTagName );
sMsg.Sprintf( "CheckTagIntegrity() - [%s]", ix->GetTagName(ix->GetCurTag()).Str());
- iRc += TestMethod( iPo, sMsg, ix->CheckTagIntegrity( ix->GetCurTag(), 2 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, sMsg, ix->CheckTagIntegrity( ix->GetCurTag(), 0 ), XB_NO_ERROR );
ixl = ixl->next;
}
}
@@ -382,14 +389,54 @@ int main( int argCnt, char **av )
ix = (xbIxNdx *) ixl->ix;
//ix->GetTagName( 0, sTagName );
sMsg.Sprintf( "CheckTagIntegrity() - [%s]", ix->GetTagName(ix->GetCurTag()).Str());
- iRc += TestMethod( iPo, sMsg, ix->CheckTagIntegrity( ix->GetCurTag(), 2 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, sMsg, ix->CheckTagIntegrity( ix->GetCurTag(), 0 ), XB_NO_ERROR );
}
ixl = ixl->next;
}
-// iRc += TestMethod( iPo, "DeleteTable()", V3Dbf->DeleteTable(), XB_NO_ERROR );
+ iRc2 = V3Dbf->Reindex( 1 ); // reindex all tags
+ iRc += TestMethod( iPo, "Reindex()", (xbInt32) iRc2, XB_NO_ERROR );
+
+ iRc += TestMethod( iPo, "DeleteTable()", V3Dbf->DeleteTable(), XB_NO_ERROR );
+
+
+
+ // test tag delete on unsuccessful reindex
+
+ iRc2 = V3Dbf->CreateTable( "TestNdx.DBF", "TestNdx", MyV3Record, XB_OVERLAY, XB_MULTI_USER );
+ iRc += TestMethod( iPo, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
+
+ iRc += TestMethod( iPo, "BlankRecord()", V3Dbf->BlankRecord(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "CFLD", "AAA" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "DFLD", "19611109" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "PutfieldDouble()", V3Dbf->PutDoubleField( "NFLD", 50 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "AppendRecord()", V3Dbf->AppendRecord(), XB_NO_ERROR );
+
+ iRc += TestMethod( iPo, "BlankRecord()", V3Dbf->BlankRecord(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "CFLD", "BBB" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "DFLD", "19611109" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "PutfieldDouble()", V3Dbf->PutDoubleField( "NFLD", 50 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "AppendRecord()", V3Dbf->AppendRecord(), XB_NO_ERROR );
+
+ iRc += TestMethod( iPo, "BlankRecord()", V3Dbf->BlankRecord(), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "CFLD", "BBB" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "Putfield()", V3Dbf->PutField( "DFLD", "19611109" ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "PutfieldDouble()", V3Dbf->PutDoubleField( "NFLD", 50 ), XB_NO_ERROR );
+ iRc += TestMethod( iPo, "AppendRecord()", V3Dbf->AppendRecord(), XB_NO_ERROR );
+
+ iRc2 = V3Dbf->Reindex( 1 ); // verify reindex works with no tags
+ iRc += TestMethod( iPo, "Reindex()", (xbInt32) iRc2, XB_NO_ERROR );
+
+
+ x.SetUniqueKeyOpt( XB_HALT_ON_DUPKEY );
+ iRc2 = V3Dbf->CreateTag( "NDX", "TestNdxX.NDX", "CFLD", "", 0, 1, XB_OVERLAY, &ixPtr, &ndx );
+ iRc += TestMethod( iPo, "CreateTag()", (xbInt32) iRc2, XB_NO_ERROR );
+
+ iRc2 = V3Dbf->Reindex( 1 ); // verify reindex fails with dup key
+ iRc += TestMethod( iPo, "Reindex()", (xbInt32) iRc2, XB_KEY_NOT_UNIQUE );
x.CloseAllTables();
+// delete V3Dbf;
if( iPo > 0 || iRc < 0 )
fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
diff --git a/src/tests/xb_test_sql.cpp b/src/tests/xb_test_sql.cpp
index 99a4f0b..3341895 100755
--- a/src/tests/xb_test_sql.cpp
+++ b/src/tests/xb_test_sql.cpp
@@ -57,11 +57,12 @@ int main( int argCnt, char **av )
{ "",0,0,0 }
};
- above structure below, depending on how table is created
+ above structure corresponds to sql below
sSql = "CREATE TABLE Address.DBF ( ADDRESS CHAR(30), CITY CHAR(30), STATE CHAR(2), ZIPCODE NUMERIC(9,0), NOTES VARCHAR, LASTUPDATE DATE, ACTIVE LOGICAL )";
*/
+/*
xbSchema MyZipRecord[] =
{
{ "ZIPCODE", XB_NUMERIC_FLD, 9, 0 },
@@ -69,7 +70,7 @@ int main( int argCnt, char **av )
{ "STATE", XB_CHAR_FLD, 2, 0 },
{ "",0,0,0 }
};
-
+*/
xbXBase x;
#ifdef XB_LOGGING_SUPPORT
@@ -85,54 +86,32 @@ int main( int argCnt, char **av )
x.SetDataDirectory( PROJECT_DATA_DIR );
- InitTime();
xbSql sql( &x );
if( po > 0 )
std::cout << "Default Data Directory is [" << x.GetDataDirectory().Str() << "]" << std::endl;
-
- xbDbf4 SqlDbf( &x ); // version 4 dbf file
- xbDbf4 SqlDbfZ( &x ); // version 4 dbf file
-
-
-
-
-
- sSql = "DROP TABLE IF EXISTS AddressR.DBF";
+/*
+ // verify a delete on a non existant table doesn't crash things
+ sSql = "DROP TABLE IF EXISTS NoTable.DBF";
iRc2 = sql.ExecuteNonQuery( sSql );
iRc += TestMethod( po, "DropTable()", (xbInt32) iRc2, XB_NO_ERROR );
if( iRc2 )
x.DisplayError( iRc2 );
-
-
sSql = "DROP TABLE IF EXISTS Address.DBF";
iRc2 = sql.ExecuteNonQuery( sSql );
iRc += TestMethod( po, "DropTable()", (xbInt32) iRc2, XB_NO_ERROR );
if( iRc2 )
x.DisplayError( iRc2 );
-
-
sSql = "CREATE TABLE Address.DBF ( ADDRESS CHAR(30), CITY CHAR(30), STATE CHAR(2), ZIPCODE NUMERIC(9,0), NOTES VARCHAR, LASTUPDATE DATE, ACTIVE LOGICAL )";
-
iRc2 = sql.ExecuteNonQuery( sSql );
iRc += TestMethod( po, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
if( iRc2 )
x.DisplayError( iRc2 );
-/*
- non sql way to create a table
- iRc2 = SqlDbf.CreateTable( "Address.DBF", "Address", MyAddressRecord, XB_OVERLAY, XB_MULTI_USER );
- iRc += TestMethod( po, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
- if( iRc2 )
- x.DisplayError( iRc2 );
-*/
-
-// return 0;
-
#ifdef XB_MDX_SUPPORT
sSql = "CREATE INDEX tag1 ON Address.DBF( CITY, STATE, DTOS( LASTUPDATE )) FILTER .NOT. DELETED()";
// xbString sSql = "CREATE INDEX tag1 ON Address.DBF( CITY, STATE )";
@@ -155,8 +134,13 @@ int main( int argCnt, char **av )
if( iRc2 )
x.DisplayError( iRc2 );
- sSql = "ALTER TABLE Address.DBF RENAME TO AddressR.DBF";
+ sSql = "DROP TABLE IF EXISTS AddressR.DBF";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "DropTable()", (xbInt32) iRc2, XB_NO_ERROR );
+ if( iRc2 )
+ x.DisplayError( iRc2 );
+ sSql = "ALTER TABLE Address.DBF RENAME TO AddressR.DBF";
iRc2 = sql.ExecuteNonQuery( sSql );
iRc += TestMethod( po, "SqlAlterTable()", (xbInt32) iRc2, XB_NO_ERROR );
if( iRc2 )
@@ -186,64 +170,91 @@ int main( int argCnt, char **av )
if( iRc2 )
x.DisplayError( iRc2 );
+ sSql = "DELETE FROM AddressR.DBF WHERE BAD='EXPRESSION'";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "SqlDelete()", (xbInt32) iRc2, XB_INVALID_FIELD_NAME );
- iRc2 = SqlDbfZ.CreateTable( "ZipCode.DBF", "", MyZipRecord, XB_OVERLAY, XB_MULTI_USER );
- iRc += TestMethod( po, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
+
+ sSql = "DROP TABLE IF EXISTS AddressR.DBF";
+ iRc += TestMethod( po, "Drop Table()", sql.ExecuteNonQuery( sSql ), XB_NO_ERROR );
+ iRc += TestMethod( po, "Drop Table()", sql.ExecuteNonQuery( sSql ), XB_NO_ERROR );
+
+*/
+
+
+ sSql = "DROP TABLE IF EXISTS ZipCode.DBF";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "DropTable()", (xbInt32) iRc2, XB_NO_ERROR );
if( iRc2 )
x.DisplayError( iRc2 );
-// sSql = "INSERT INTO ZipCode.DBF ( ZIPCODE, CITY, STATE ) VALUES ( 75087, 'Rockwall', 'TX' )";
-
+ sSql = "CREATE TABLE ZipCode.DBF ( ZIPCODE NUMERIC(9,0), CITY CHAR(30), STATE CHAR(2) )";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
+ if( iRc2 )
+ x.DisplayError( iRc2 );
-// std::cout << "---------------------------------------------------------\n";
-// std::cout << sSql.Str() << "\n";
+ sSql = "INSERT INTO ZipCode.DBF ( ZIPCODE, CITY, STATE ) VALUES ( 75087, 'Rockwall', 'TX' )";
+ iRc2 = sql.ExecuteNonQuery( sSql );
- sSql = "INSERT INTO ZipCode ( CITY ) VALUES ( 'city' )";
+ sSql = "INSERT INTO ZipCode.DBF ( ZIPCODE, CITY, STATE ) VALUES ( 75087, 'Rockwall', 'TX' )";
iRc2 = sql.ExecuteNonQuery( sSql );
- iRc += TestMethod( po, "SqlInsert()", (xbInt32) iRc2, XB_NO_ERROR );
+
+/*
+
+ sSql = "CREATE INDEX ZipCode1.NDX ON ZipCode.DBF( ZIPCODE ) ASSOCIATE";
+ iRc2 = sql.ExecuteNonQuery( sSql );
if( iRc2 )
x.DisplayError( iRc2 );
+ iRc += TestMethod( po, "Create Index()", (xbInt32) iRc2, XB_NO_ERROR );
+*/
+ sSql = "CREATE UNIQUE INDEX ZipCode2.NDX ON ZipCode.DBF( ZIPCODE ) ASSOCIATE";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "Create Index()", (xbInt32) iRc2, XB_KEY_NOT_UNIQUE );
+
-//**************** work in progress
/*
- sSql = "DELETE FROM AddressR.DBF WHERE BAD='EXPRESSION'";
+ sSql = "DROP TABLE IF EXISTS ZipCode.DBF";
iRc2 = sql.ExecuteNonQuery( sSql );
- iRc += TestMethod( po, "SqlDelete()", (xbInt32) iRc2, XB_INVALID_FIELD_NAME );
+ iRc += TestMethod( po, "DropTable()", (xbInt32) iRc2, XB_NO_ERROR );
+ if( iRc2 )
+ x.DisplayError( iRc2 );
*/
-// if( iRc2 )
-// x.DisplayError( iRc2 );
+// sSql = "INSERT INTO ZipCode.DBF ( ZIPCODE, CITY, STATE ) VALUES ( 75087, 'Rockwall', 'TX' )";
+// iRc2 = sql.ExecuteNonQuery( sSql );
+
+
+ x.DisplayTableList();
- iRc += TestMethod( po, "Close()", SqlDbf.Close(), XB_NO_ERROR );
- iRc += TestMethod( po, "Close()", SqlDbfZ.Close(), XB_NO_ERROR );
-// return 0;
-// std::cout << "---------------------------------------------------------\n";
+/*
+ sSql = "CREATE INDEX ZipCode.NDX ON Addres.DBF( ZIPCODE )";
- xbStmt sqlQry1( &x );
-// sSql = "SELECT CITY, STATE, ZIPCODE FROM Address.DBF T LEFT JOIN LJ.DBF LJ WHERE CITY IS NOT NULL ORDER BY 2 GROUP BY STATE HAVING ZIPCODE .NOT. NULL";
-// sSql = "SELECT CITY, STATE, ZIPCODE FROM AddressR.DBF T WHERE CITY IS NOT NULL ORDER BY 2 GROUP BY STATE HAVING ZIPCODE .NOT. NULL";
+ iRc2 = sql.ExecuteNonQuery( sSql );
+ iRc += TestMethod( po, "CreateTable()", (xbInt32) iRc2, XB_NO_ERROR );
+ if( iRc2 )
+ x.DisplayError( iRc2 );
+*/
-// sSql = "SELECT CITY, STATE, ZIPCODE FROM AddressR A LEFT JOIN ZipCode Z ON A.ZIPCODE = Z.ZIPCODE WHERE CITY IS NOT NULL ORDER BY 2 GROUP BY STATE HAVING ZIPCODE .NOT. NULL";
-// sSql = "SELECT M.ID, M.LEFTFK0, L0.CFLD FROM MAIN0 M LEFT JOIN LEFT0 L0 ON M.LEFTFK0 = L0.LEFTFK0 WHERE M.ID IS NOT NULL";
- iRc += TestMethod( po, "Select()", sqlQry1.ExecuteQuery( sSql ), XB_NO_ERROR );
+// sSql = "DROP TABLE IF EXISTS AddressR.DBF";
+// iRc += TestMethod( po, "Drop Table()", sqlQry1.ExecuteQuery( sSql ), XB_NO_ERROR );
- sqlQry1.DumpStmtInternals();
- // sqlQry1.Test();
- x.DisplayTableList();
+ // x.DisplayTableList();
+ x.CloseAllTables();
if( po > 0 || iRc < 0 )
fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
diff --git a/src/tests/xb_test_string.cpp b/src/tests/xb_test_string.cpp
index 2f01e51..9dd48af 100755
--- a/src/tests/xb_test_string.cpp
+++ b/src/tests/xb_test_string.cpp
@@ -188,6 +188,19 @@ int main( int argCnt, char **av = NULL )
s2 = "!@#";
rc += TestMethod( po, "s1.Append( '!@#' )", s1.Append( s2 ), "ABCDEFGZ999!@#", 14 );
+ xbString sAppend1;
+ sAppend1.Append( "abc123", 6 );
+ rc += TestMethod( po, "Append", sAppend1, "abc123", 6 );
+
+ xbString sAppend2;
+ sAppend2.Append( "abc123", 8 );
+ rc += TestMethod( po, "Append", sAppend2, "abc123", 6 );
+
+ xbString sAppend3;
+ sAppend3.Append( "abc123", 3 );
+ rc += TestMethod( po, "Append", sAppend3, "abc", 3 );
+
+
rc += TestMethod( po, "s1.Assign( 'ABCDE', 3, 2 )", s1.Assign( "ABCDE", 3, 2 ), "CD", 2 );
rc += TestMethod( po, "s1.Assign( 'ABCDE', 2, 7 )", s1.Assign( "ABCDE", 2, 7 ), "BCDE", 4 );
rc += TestMethod( po, "s1.Assign( 'ABCDE', 1, 4 )", s1.Assign( "ABCDE", 1, 4 ), "ABCD", 4 );
@@ -222,10 +235,24 @@ int main( int argCnt, char **av = NULL )
s1.CvtHexString( s2 );
rc += TestMethod( po, "CvtHexString() ", s2, "abcde", 5 );
- s1 = "123";
- s2 = "ABC";
- rc += TestMethod( po, "HasAlphaChars()", s1.HasAlphaChars(), 0 );
- rc += TestMethod( po, "HasAlphaChars()", s2.HasAlphaChars(), 1 );
+ s1.ExtractElement( "aaaa|bbbb|cccc|dddd", '|', 2, 0 );
+ rc += TestMethod( po, "ExtractElement() ", s1, "bbbb", 4 );
+
+ s1.ExtractElement( "aaaa|b'bb|c'ccc|dddd", '|', 3, 1 );
+ rc += TestMethod( po, "ExtractElement() ", s1, "dddd", 4 );
+
+ s1 = "aaaa|bbbb|cccc|dddd";
+ s2.ExtractElement( s1, '|', 2, 0 );
+ rc += TestMethod( po, "ExtractElement() ", s2, "bbbb", 4 );
+
+ s1 = "abcabcabx";
+ rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( 'b' ), 8 );
+ s1 = "abcabcabx";
+ rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( 'x' ), 9 );
+ s1 = "abcabcabx";
+ rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( '$' ), 0 );
+ rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( "ab" ), 7 );
+
s1 = "\\ABC\\XYZ";
rc += TestMethod( po, "GetPathSeparator()", s1.GetPathSeparator(), '\\' );
@@ -233,14 +260,36 @@ int main( int argCnt, char **av = NULL )
s1 = "/ABC/XYZ";
rc += TestMethod( po, "GetPathSeparator()", s1.GetPathSeparator(), '/' );
+
+ s1 = "123";
+ s2 = "ABC";
+ rc += TestMethod( po, "HasAlphaChars()", s1.HasAlphaChars(), 0 );
+ rc += TestMethod( po, "HasAlphaChars()", s2.HasAlphaChars(), 1 );
+
+
s2 = "";
rc += TestMethod( po, "IsEmpty()", s2.IsEmpty(), 1 );
+
+ s1.SetNum( (long) 123456 );
+
+ s1 = "abcZZZ123";
+ s1.Left( 4 );
+ rc += TestMethod( po, "Left(4) ", s1, "abcZ", 4 );
+
+ s1.Left( 1 );
+ rc += TestMethod( po, "Left(1) ", s1, "a", 1 );
+
+ s1.Left( 0 );
+ rc += TestMethod( po, "Left(0) ", s1, "", 0 );
+
// trim tests
s1 = " ABC ";
rc += TestMethod( po, "Ltrim()", s1.Ltrim(), "ABC ", 6 );
+
s1 = " ABC ";
rc += TestMethod( po, "Rtrim()", s1.Rtrim(), " ABC", 6 );
+
s1 = " ABC ";
rc += TestMethod( po, "Trim() ", s1.Trim(), "ABC", 3 );
@@ -253,6 +302,20 @@ int main( int argCnt, char **av = NULL )
s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
rc += TestMethod( po, "Mid(4,5) ", s1.Mid(4,5), "DEFGH", 5 );
+ s1 = "123";
+ s1.PadLeft( '0', 9 );
+ rc += TestMethod( po, "PadLeft() ", s1, "000000123", 9 );
+
+ s1 = "abc";
+ s1.PadRight( 'Z', 9 );
+ rc += TestMethod( po, "PadRight() ", s1, "abcZZZZZZ", 9 );
+
+ s1.PadRight( 'Z', 4 );
+ rc += TestMethod( po, "PadRight() ", s1, "abcZZZZZZ", 9 );
+
+
+
+ s1 = "DEFGHI";
rc += TestMethod( po, "Pos('G') ", (xbInt32) s1.Pos( 'G' ), 4 );
rc += TestMethod( po, "Pos(\"EFG\") ", (xbInt32) s1.Pos( "EFG" ), 2 );
@@ -269,48 +332,32 @@ int main( int argCnt, char **av = NULL )
s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
rc += TestMethod( po, "Remove(3,5) ", s1.Remove( 3, 5 ), "ABHIJKLMNOPQRSTUVWXYZ", 21 );
+ s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ rc += TestMethod( po, "Remove(22,5) ", s1.Remove( 22, 5 ), "ABCDEFGHIJKLMNOPQRSTU", 21 );
+ s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ rc += TestMethod( po, "Remove(24,5) ", s1.Remove( 24, 5 ), "ABCDEFGHIJKLMNOPQRSTUVW", 23 );
- s1 = "ABCABCABZ";
- s1.SwapChars( 'A', '9' );
- rc += TestMethod( po, "SwapChars() ", s1, "9BC9BC9BZ", 9 );
-
- s1.ToLowerCase();
- rc += TestMethod( po, "ToLowerCase() ", s1, "9bc9bc9bz", 9 );
-
- s1.ToUpperCase();
- rc += TestMethod( po, "ToUpperCase() ", s1, "9BC9BC9BZ", 9 );
-
- s1.ZapChar( '9' );
- rc += TestMethod( po, "ZapChar('9') ", s1, "BCBCBZ", 6 );
-
- s1.ZapLeadingChar( 'B' );
- rc += TestMethod( po, "ZapLeadingChar('B') ", s1, "CBCBZ", 5 );
-
- s1.ZapTrailingChar( 'Z' );
- rc += TestMethod( po, "ZapLeadingChar('B') ", s1, "CBCB", 4 );
-
- s1.ExtractElement( "aaaa|bbbb|cccc|dddd", '|', 2, 0 );
- rc += TestMethod( po, "ExtractElement() ", s1, "bbbb", 4 );
-
- s1.ExtractElement( "aaaa|b'bb|c'ccc|dddd", '|', 3, 1 );
- rc += TestMethod( po, "ExtractElement() ", s1, "dddd", 4 );
-
- s1 = "123";
- s1.PadLeft( '0', 9 );
- rc += TestMethod( po, "PadLeft() ", s1, "000000123", 9 );
-
- s1 = "abc";
- s1.PadRight( 'Z', 9 );
- rc += TestMethod( po, "PadRight() ", s1, "abcZZZZZZ", 9 );
+ s1.Set( "abcdef.dbf" );
+ s1.Replace( "def", "DEF" );
+ rc += TestMethod( po, "Replace", s1, "abcDEF.dbf", 10 );
+ s1.Replace( ".dbf", ".DBF" );
+ rc += TestMethod( po, "Replace", s1, "abcDEF.DBF", 10 );
+ s1.Set( "abcdef.dbf" );
+ s1.Replace( "def", "DEFG" );
+ rc += TestMethod( po, "Replace", s1, "abcDEFG.dbf", 11 );
+ s1.Set( "abcdefdef.dbf" );
+ s1.Replace( "def", "DEFG" );
+ rc += TestMethod( po, "Replace", s1, "abcDEFGDEFG.dbf", 15 );
- s1.Left( 4 );
- rc += TestMethod( po, "Left(4) ", s1, "abcZ", 4 );
- s1.Left( 1 );
- rc += TestMethod( po, "Left(1) ", s1, "a", 1 );
+ s1.SetNum( (long) 123456 );
+ rc += TestMethod( po, "SetNum() ", s1, "123456", 6 );
- s1.Left( 0 );
- rc += TestMethod( po, "Left(0) ", s1, "", 0 );
+ xbFloat f = (xbFloat) 12.35;
+ // %f format varies depending on compiler
+ s1.Sprintf( "%6.2f", f );
+ s1.Ltrim();
+ rc += TestMethod( po, "s1.Sprintf()/s.Trim()", s1, "12.35", 5 );
char buf[5];
buf[0] = 'W';
@@ -319,18 +366,20 @@ int main( int argCnt, char **av = NULL )
buf[3] = 'Z';
buf[4] = 0x00;
xbInt32 l = 1234567;
- xbFloat f = (xbFloat) 12.35;
s2 = "test string";
rc += TestMethod( po, "s1.Sprintf()", s1.Sprintf( "%s %d %s %ld", buf, 12, s2.Str(), l ), "WXYZ 12 test string 1234567", 27 );
- // %f format varies depending on compiler
- s1.Sprintf( "%6.2f", f );
- s1.Ltrim();
- rc += TestMethod( po, "s1.Sprintf()/s.Trim()", s1, "12.35", 5 );
- s1.SetNum( (long) 123456 );
- rc += TestMethod( po, "SetNum() ", s1, "123456", 6 );
+ s1 = "ABCABCABZ";
+ s1.SwapChars( 'A', '9' );
+ rc += TestMethod( po, "SwapChars() ", s1, "9BC9BC9BZ", 9 );
+
+ s1.ToLowerCase();
+ rc += TestMethod( po, "ToLowerCase() ", s1, "9bc9bc9bz", 9 );
+
+ s1.ToUpperCase();
+ rc += TestMethod( po, "ToUpperCase() ", s1, "9BC9BC9BZ", 9 );
s1 = "T";
rc += TestMethod( po, "ValidLogicalValue", s1.ValidLogicalValue(), 1 );
@@ -344,13 +393,19 @@ int main( int argCnt, char **av = NULL )
s1 = "ABC-123456.89";
rc += TestMethod( po, "ValidNumericValue", s1.ValidNumericValue(), 0 );
- s1 = "abcabcabx";
- rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( 'b' ), 8 );
- s1 = "abcabcabx";
- rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( 'x' ), 9 );
- s1 = "abcabcabx";
- rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( '$' ), 0 );
- rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( "ab" ), 7 );
+
+ s1 = "BC9BC99BZ";
+ s1.ZapChar( '9' );
+ rc += TestMethod( po, "ZapChar('9') ", s1, "BCBCBZ", 6 );
+
+ s1.ZapLeadingChar( 'B' );
+ rc += TestMethod( po, "ZapLeadingChar('B') ", s1, "CBCBZ", 5 );
+
+ s1.ZapTrailingChar( 'Z' );
+ rc += TestMethod( po, "ZapTrailingChar('Z') ", s1, "CBCB", 4 );
+ s1.ZapTrailingChar( 'Z' );
+ rc += TestMethod( po, "ZapTrailingChar('Z') ", s1, "CBCB", 4 );
+
s1 = ")";
rc += TestMethod( po, "GetLastPos", (xbInt16) s1.GetLastPos( ')' ), 1 );
@@ -385,17 +440,12 @@ int main( int argCnt, char **av = NULL )
s3.Sprintf( "%s and %s", s1.Str(), s2.Str());
rc += TestMethod( po, "Sprintf", s3, "string 1 and string 2.0", 23 );
- s1.Set( "abcdef.dbf" );
- s1.Replace( "def", "DEF" );
- rc += TestMethod( po, "Replace", s1, "abcDEF.dbf", 10 );
- s1.Replace( ".dbf", ".DBF" );
- rc += TestMethod( po, "Replace", s1, "abcDEF.DBF", 10 );
-
+/*
xbInt16 iErrorStop = 10;
xbInt16 iRc = -100;
sMsg.Sprintf( "class::method() Exception Caught. Error Stop = [%d] iRc = [%d] Expression = [%s]", iErrorStop, iRc, s3.Str() );
-
+*/
if( po > 0 || rc < 0 )
fprintf( stdout, "Total Errors = %d\n", rc * -1 );
diff --git a/src/tests/xb_test_tblmgr.cpp b/src/tests/xb_test_tblmgr.cpp
index d048594..4e177d0 100755
--- a/src/tests/xb_test_tblmgr.cpp
+++ b/src/tests/xb_test_tblmgr.cpp
@@ -96,39 +96,6 @@ int main( int argCnt, char **av )
}
-std::cout << "cp0\n";
- x.SetDataDirectory( "/ABCDEFG/" );
-
- #ifdef WIN32
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG\\", 9 );
- #else
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG/", 9 );
- #endif
-std::cout << "cp1\n";
- x.SetDataDirectory( "/ABCDEFG" );
- #ifdef WIN32
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG", 8 );
- #else
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG", 8 );
- #endif
-
-
- x.SetDataDirectory( "\\ABCDEFG\\");
- #ifdef WIN32
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG\\", 9 );
- #else
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG/", 9 );
- #endif
-
- x.SetDataDirectory( "\\ABCDEFG" );
- #ifdef WIN32
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG", 8 );
- #else
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG", 8 );
- #endif
-
- x.SetDataDirectory( "ABCDEFG" );
- iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "ABCDEFG", 7 );
iRc += TestMethod( iPo, "RemoveTblFromDbList()", x.RemoveTblFromTblList( "TestTableB" ), 0 );
iRc += TestMethod( iPo, "RemoveTblFromDbList()", x.RemoveTblFromTblList( "TestTableB" ), XB_NOT_FOUND );
diff --git a/src/tests/xb_test_tdx.cpp b/src/tests/xb_test_tdx.cpp
new file mode 100755
index 0000000..5d79f04
--- /dev/null
+++ b/src/tests/xb_test_tdx.cpp
@@ -0,0 +1,162 @@
+/* xb_test_tdx.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 program tests the class xbIxNdx
+
+// usage: xb_test_ndx QUITE|NORMAL|VERBOSE
+
+
+#include "xbase.h"
+
+using namespace xb;
+
+#include "tstfuncs.cpp"
+
+int main( int argCnt, char **av )
+{
+ int iRc = 0;
+ int iRc2;
+ int iPo = 1; /* print option */
+ /* 0 - QUIET */
+ /* 1 - NORMAL */
+ /* 2 - VERBOSE */
+
+ xbString sMsg;
+ char c;
+ xbString s;
+
+ if( argCnt > 1 ) {
+ if( av[1][0] == 'Q' )
+ iPo = 0;
+ else if( av[1][0] == 'V' )
+ iPo = 2;
+ }
+
+
+ xbSchema MyV4Record[] =
+ {
+ { "CITY", XB_CHAR_FLD, 100, 0 },
+ { "STATE", XB_CHAR_FLD, 2, 0 },
+ { "ZIP", XB_NUMERIC_FLD, 9, 0 },
+ { "DATE1", XB_DATE_FLD, 8, 0 },
+ { "",0,0,0 }
+ };
+
+
+
+ xbXBase x;
+
+ #ifdef XB_LOGGING_SUPPORT
+ x.SetLogDirectory( PROJECT_LOG_DIR );
+ x.EnableMsgLogging();
+ if( iPo ){
+ std::cout << "Logfile is [" << x.GetLogFqFileName().Str() << "]" << std::endl;
+ }
+ sMsg.Sprintf( "Program [%s] initializing...", av[0] );
+ x.WriteLogMessage( sMsg );
+ #endif
+
+ x.SetDataDirectory( PROJECT_DATA_DIR );
+ x.SetTempDirectory( PROJECT_TEMP_DIR );
+ x.SetMultiUser( xbFalse );
+ InitTime();
+
+ if( iPo > 0 )
+ std::cout << "Default Data Directory is [" << x.GetDataDirectory().Str() << "]" << std::endl;
+
+
+ xbFile f( &x );
+ xbIx *pIx;
+ void *pTag;
+ xbDate dt = "19890209";
+ xbString sKey;
+
+ xbDbf *V4DbfX1 = new xbDbf4( &x );
+
+
+ iRc2 = V4DbfX1->CreateTable( "TTDXDB01.DBF", "TestMdxX2", MyV4Record, XB_OVERLAY, XB_MULTI_USER );
+ iRc += TestMethod( iPo, "CreateTable(1)", iRc2, 0 );
+
+ iRc2 = V4DbfX1->CreateTag( "TDX", "CITY_TAGA", "CITY", "", 0, 0, XB_OVERLAY, &pIx, &pTag );
+ iRc += TestMethod( iPo, "CreateTag(1)", iRc2, 0 );
+
+ std::cout << "Cur Tag Name = " << V4DbfX1->GetCurTagName().Str() << "\n";
+
+ xbString sFqFileName = pIx->GetFqFileName();
+ iRc2 = V4DbfX1->DeleteTag( "TDX", V4DbfX1->GetCurTagName() );
+
+ iRc += TestMethod( iPo, "DeleteTag(3)", iRc2, 0 );
+
+ // only one tag, file should not exist anymore
+ iRc2 = pIx->FileExists(sFqFileName);
+ iRc += TestMethod( iPo, "FileExists()", iRc2, 0 );
+
+ iRc2 = V4DbfX1->CreateTag( "TDX", "ZIP_TAG", "ZIP", "", xbTrue, 0, XB_OVERLAY, &pIx, &pTag );
+ iRc += TestMethod( iPo, "CreateTag(2)", iRc2, 0 );
+
+ xbInt32 uZip = 10000;
+ for( xbUInt16 i = 0; i < 5; i++ ){
+ for( xbUInt16 j = 0; j < 4; j++ ){
+
+ c = j + 65;
+ s = c;
+ s.PadRight( c, (xbUInt32) i + 1 );
+ //std::cout << "*********** adding s=[" << s.Str() << "] length = " << s.Len() << "\n";
+ iRc2 = V4DbfX1->BlankRecord();
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "BlankRecord()", iRc2, XB_NO_ERROR );
+
+ iRc2 = V4DbfX1->PutField( "CITY", s );
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "PutField()", iRc2, XB_NO_ERROR );
+
+ iRc2 = V4DbfX1->PutLongField( "ZIP", uZip++ );
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "PutField()", iRc2, XB_NO_ERROR );
+
+ iRc2 = V4DbfX1->PutDateField( "DATE1", dt );
+ dt++;
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "PutField()", iRc2, XB_NO_ERROR );
+
+ iRc2 = V4DbfX1->AppendRecord();
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "AppendRecord()", iRc2, XB_NO_ERROR );
+
+ iRc2 = V4DbfX1->Commit();
+ if( iRc2 != XB_NO_ERROR )
+ iRc += TestMethod( iPo, "Commit()", iRc2, XB_NO_ERROR );
+ }
+ }
+
+
+ iRc += TestMethod( iPo, "CheckTagIntegrity(1)", V4DbfX1->CheckTagIntegrity( 1, 2 ), XB_NO_ERROR );
+
+
+ x.CloseAllTables();
+
+// delete V4DbfX1;
+// delete V4DbfX2;
+
+ if( iPo > 0 || iRc < 0 )
+ fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
+
+#ifdef XB_LOGGING_SUPPORT
+ sMsg.Sprintf( "Program [%s] terminating with [%d] errors...", av[0], iRc * -1 );
+ x.WriteLogMessage( sMsg );
+#endif
+
+ return iRc;
+}
diff --git a/src/tests/xb_test_xbase.cpp b/src/tests/xb_test_xbase.cpp
index 4751c25..a0affd6 100755
--- a/src/tests/xb_test_xbase.cpp
+++ b/src/tests/xb_test_xbase.cpp
@@ -90,6 +90,119 @@ int main( int argCnt, char **av )
std::cout << "DisplayError Test ==> ";
x.DisplayError( 0 );
}
+
+ #ifdef WIN32
+ char cSep = '\\';
+ iRc += TestMethod( iPo, "GetPathSeparator()", x.GetPathSeparator(), cSep );
+ #else
+ char cSep = '/';
+ iRc += TestMethod( iPo, "GetPathSeparator()", x.GetPathSeparator(), cSep );
+ #endif
+
+
+
+ xbString sDir = "\\dir\\path";
+ xbString sFile = "myfile";
+ xbString sExt = "DBF";
+ xbString sFqn;
+ iRc += TestMethod( iPo, "CreateFQN()", x.CreateFqn( sDir, sFile, sExt, sFqn ), XB_NO_ERROR );
+ //std::cout << "FQN = [" << sFqn.Str() << "]\n";
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "CreateFQN()", sFqn.Str(), "\\dir\\path\\myfile.DBF", 20 );
+ #else
+ iRc += TestMethod( iPo, "CreateFQN()", sFqn.Str(), "/dir/path/myfile.DBF", 20 );
+ #endif
+
+ sDir = "/dir/path";
+ iRc += TestMethod( iPo, "CreateFQN()", x.CreateFqn( sDir, sFile, sExt, sFqn ), XB_NO_ERROR );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "CreateFQN()", sFqn.Str(), "\\dir\\path\\myfile.DBF", 20 );
+ #else
+ iRc += TestMethod( iPo, "CreateFQN()", sFqn.Str(), "/dir/path/myfile.DBF", 20 );
+ #endif
+
+
+ x.SetDataDirectory( "/ABCDEFG/" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+ x.SetDataDirectory( "/ABCDEFG" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG", 8 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG", 8 );
+ #endif
+
+ x.SetDataDirectory( "\\ABCDEFG\\");
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+ x.SetDataDirectory( "\\ABCDEFG" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "\\ABCDEFG", 8 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetDataDirectory()", x.GetDataDirectory(), "/ABCDEFG", 8 );
+ #endif
+
+#ifdef XB_LOGGING_SUPPORT
+
+ x.SetLogDirectory( "ABCDEFG" );
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "ABCDEFG", 7 );
+ x.SetLogDirectory( "/ABCDEFG/" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+ x.SetLogDirectory( "/ABCDEFG" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "\\ABCDEFG", 8 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "/ABCDEFG", 8 );
+ #endif
+
+ x.SetLogDirectory( "\\ABCDEFG\\");
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetLogDirectory()", x.GetLogDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+ x.SetLogFileName( "LogFileNameTest" );
+ iRc += TestMethod( iPo, "Set/GetLogFileName()", x.GetLogFileName(), "LogFileNameTest", 15 );
+#endif
+
+ x.SetTempDirectory( "/ABCDEFG/" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+ x.SetTempDirectory( "/ABCDEFG" );
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "\\ABCDEFG", 8 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "/ABCDEFG", 8 );
+ #endif
+
+ x.SetTempDirectory( "\\ABCDEFG\\");
+ #ifdef WIN32
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "\\ABCDEFG\\", 9 );
+ #else
+ iRc += TestMethod( iPo, "Set/GetTempDirectory()", x.GetTempDirectory(), "/ABCDEFG/", 9 );
+ #endif
+
+
+// std::cout << "path separator = [" << x.GetPathSeparator() << "]\n";
+
if( iPo > 0 || iRc < 0 )
fprintf( stdout, "Total Errors = %d\n", iRc * -1 );
diff --git a/src/utils/xb_cfg_check.cpp b/src/utils/xb_cfg_check.cpp
index 5489c51..c979bac 100755
--- a/src/utils/xb_cfg_check.cpp
+++ b/src/utils/xb_cfg_check.cpp
@@ -152,6 +152,13 @@ int main()
fprintf( stdout, "XB_MDX_SUPPORT = [OFF]\n" );
#endif
+ #ifdef XB_TDX_SUPPORT
+ fprintf( stdout, "XB_TDX_SUPPORT = [ON]\n" );
+ #else
+ fprintf( stdout, "XB_TDX_SUPPORT = [OFF]\n" );
+ #endif
+
+
#ifdef XB_SQL_SUPPORT
fprintf( stdout, "XB_SQL_SUPPORT = [ON]\n" );
#else
@@ -183,6 +190,7 @@ int main()
fprintf( stdout, "PROJECT_BINARY_DIR = [%s]\n", PROJECT_BINARY_DIR );
fprintf( stdout, "PROJECT_DATA_DIR = [%s]\n", PROJECT_DATA_DIR );
fprintf( stdout, "PROJECT_LOG_DIR = [%s]\n", PROJECT_LOG_DIR );
+ fprintf( stdout, "PROJECT_TEMP_DIR = [%s]\n", PROJECT_TEMP_DIR );
fprintf( stdout, "PROJECT_DFLT_LOGFILE = [%s]\n", PROJECT_DFLT_LOGFILE );
fprintf( stdout, "PROJECT_SOURCE_DIR = [%s]\n", PROJECT_SOURCE_DIR );
fprintf( stdout, "CMAKE_RUNTIME_OUTPUT_DIRECTORY = [%s]\n\n", CMAKE_RUNTIME_OUTPUT_DIRECTORY );
@@ -191,34 +199,33 @@ int main()
fprintf( stdout, "BUILD_SHARED_LIBS = [%s]\n", BUILD_SHARED_LIBS );
fprintf( stdout, "EXTRA_LIBS = [%s]\n\n", EXTRA_LIBS );
- fprintf( stdout, "Field sizes:\n" );
- fprintf( stdout, "SIZEOF_VOID_P = [%s]\n", CMAKE_SIZEOF_VOID_P );
- fprintf( stdout, "sizeof(char *) = [%zd]\n", sizeof( char *));
- fprintf( stdout, "sizeof(int) = [%zd]\n", sizeof( int ));
- fprintf( stdout, "sizeof(long) = [%zd]\n", sizeof( long ));
- fprintf( stdout, "sizeof(char) = [%zd]\n", sizeof( char ));
+
+ fprintf( stdout, "sizeof(char *) = [%d]\n", (xbInt32) sizeof( char *));
+ fprintf( stdout, "sizeof(int) = [%d]\n", (xbInt32) sizeof( int ));
+ fprintf( stdout, "sizeof(long) = [%d]\n", (xbInt32) sizeof( long ));
+ fprintf( stdout, "sizeof(char) = [%d]\n", (xbInt32) sizeof( char ));
#ifdef HAVE_WCHAR_H
- fprintf( stdout, "sizeof(wchar_t) = [%zd]\n", sizeof( wchar_t ));
+ fprintf( stdout, "sizeof(wchar_t) = [%d]\n", (xbInt32) sizeof( wchar_t ));
#endif
#ifdef HAVE_WINDOWS_H
- fprintf( stdout, "sizeof(DWORD) = [%zd]\n", sizeof( DWORD ));
- #endif
-
- fprintf( stdout, "sizeof(double) = [%zd]\n", sizeof( double ));
- fprintf( stdout, "sizeof(float) = [%zd]\n", sizeof( float ));
- fprintf( stdout, "sizeof(size_t) = [%zd]\n", sizeof( size_t ));
- fprintf( stdout, "sizeof(off_t) = [%zd]\n\n", sizeof( off_t ));
-
- fprintf( stdout, "sizeof(xbBool) = [%zd]\n", sizeof( xbBool ));
- fprintf( stdout, "sizeof(xbInt16) = [%zd]\n", sizeof( xbInt16 ));
- fprintf( stdout, "sizeof(xbUInt16) = [%zd]\n", sizeof( xbUInt16 ));
- fprintf( stdout, "sizeof(xbInt32) = [%zd]\n", sizeof( xbInt32 ));
- fprintf( stdout, "sizeof(xbUInt32) = [%zd]\n", sizeof( xbUInt32 ));
- fprintf( stdout, "sizeof(xbInt64) = [%zd]\n", sizeof( xbInt64 ));
- fprintf( stdout, "sizeof(xbUInt64) = [%zd]\n", sizeof( xbUInt64 ));
- fprintf( stdout, "sizeof(xbFloat) = [%zu]\n", sizeof( xbFloat ));
- fprintf( stdout, "sizeof(xbDouble) = [%zu]\n", sizeof( xbDouble ));
+ fprintf( stdout, "sizeof(DWORD) = [%d]\n", (xbInt32) sizeof( DWORD ));
+ #endif
+
+ fprintf( stdout, "sizeof(double) = [%d]\n", (xbInt32) sizeof( double ));
+ fprintf( stdout, "sizeof(float) = [%d]\n", (xbInt32) sizeof( float ));
+ fprintf( stdout, "sizeof(size_t) = [%d]\n", (xbInt32) sizeof( size_t ));
+ fprintf( stdout, "sizeof(off_t) = [%d]\n\n", (xbInt32) sizeof( off_t ));
+
+ fprintf( stdout, "sizeof(xbBool) = [%d]\n", (xbInt32) sizeof( xbBool ));
+ fprintf( stdout, "sizeof(xbInt16) = [%d]\n", (xbInt32) sizeof( xbInt16 ));
+ fprintf( stdout, "sizeof(xbUInt16) = [%d]\n", (xbInt32) sizeof( xbUInt16 ));
+ fprintf( stdout, "sizeof(xbInt32) = [%d]\n", (xbInt32) sizeof( xbInt32 ));
+ fprintf( stdout, "sizeof(xbUInt32) = [%d]\n", (xbInt32) sizeof( xbUInt32 ));
+ fprintf( stdout, "sizeof(xbInt64) = [%d]\n", (xbInt32) sizeof( xbInt64 ));
+ fprintf( stdout, "sizeof(xbUInt64) = [%d]\n", (xbInt32) sizeof( xbUInt64 ));
+ fprintf( stdout, "sizeof(xbFloat) = [%d]\n", (xbInt32) sizeof( xbFloat ));
+ fprintf( stdout, "sizeof(xbDouble) = [%d]\n", (xbInt32) sizeof( xbDouble ));
fprintf( stdout, "\nHeader files:\n" );
diff --git a/src/utils/xb_dbfutil.cpp b/src/utils/xb_dbfutil.cpp
index e50495e..76988c0 100755
--- a/src/utils/xb_dbfutil.cpp
+++ b/src/utils/xb_dbfutil.cpp
@@ -90,6 +90,7 @@ class xbUtil{
void UpdateTableAutoCommit();
void DisplayTableInfo();
void RenameTable();
+ void DeleteTable();
// 4 - RecordMenu options
void GetRecord();
@@ -776,7 +777,7 @@ void xbUtil::LockRecord(){
std::cin.getline( cBuf, 15 );
//iRc = dActiveTable->LockRecord( XB_LOCK, atol( cBuf ));
iRc = dActiveTable->LockRecord( XB_LOCK, strtoul( cBuf, NULL, 0 ));
-
+
x->DisplayError( iRc );
}
@@ -1453,6 +1454,24 @@ void xbUtil::DisplayTableInfo(){
}
/*************************************************************************************/
+void xbUtil::DeleteTable(){
+
+ if( !dActiveTable )
+ dActiveTable = GetTablePtr( " - select table" );
+
+ if( !dActiveTable ){
+ std::cout << "No table selected" << std::endl;
+ return;
+ }
+
+ dActiveTable->DeleteTable();
+ dActiveTable = NULL;
+ std::cout << "Table deleted.\n";
+
+}
+
+
+/*************************************************************************************/
void xbUtil::RenameTable(){
if( !dActiveTable )
@@ -1510,26 +1529,29 @@ void xbUtil::DisplayActiveTable() const{
if( dActiveTable ){
std::cout << "Active Table = [" << dActiveTable->GetTblAlias().Str() << "] ";
xbUInt32 ulRecCnt = 0;
- dActiveTable->ReadHeader( 0, 1 );
- dActiveTable->GetRecordCnt( ulRecCnt );
- std::cout << "Total Records = [" << ulRecCnt << "] ";
- std::cout << "Current Record = [" << dActiveTable->GetCurRecNo() << "] ";
-
- if( dActiveTable->GetAutoCommit())
- std::cout << " Auto Commit = [Enabled]";
- else
- std::cout << " Auto Commit = [Disabled]";
+ xbInt16 iRc;
+ if(( iRc = dActiveTable->GetRecordCnt( ulRecCnt )) == XB_NO_ERROR ){
+ std::cout << "Total Records = [" << ulRecCnt << "] ";
+ std::cout << "Current Record = [" << dActiveTable->GetCurRecNo() << "] ";
- std::cout << std::endl;
- #ifdef XB_INDEX_SUPPORT
- xbIx *pIx = dActiveTable->GetCurIx();
- if( pIx ){
- void *vpTag = dActiveTable->GetCurTag();
- std::cout << "Active Tag = [" << pIx->GetTagName( vpTag ).Str() << "] Type = [" << dActiveTable->GetCurIxType().Str() <<
+ if( dActiveTable->GetAutoCommit())
+ std::cout << " Auto Commit = [Enabled]";
+ else
+ std::cout << " Auto Commit = [Disabled]";
+
+ std::cout << std::endl;
+ #ifdef XB_INDEX_SUPPORT
+ xbIx *pIx = dActiveTable->GetCurIx();
+ if( pIx ){
+ void *vpTag = dActiveTable->GetCurTag();
+ std::cout << "Active Tag = [" << pIx->GetTagName( vpTag ).Str() << "] Type = [" << dActiveTable->GetCurIxType().Str() <<
"] \tFile Name = [" << pIx->GetFileName().Str() << "] Key = [" << pIx->GetKeyExpression( vpTag ).Str() << "]" << std::endl;
+ }
+ #endif // XB_INDEX_SUPPORT
+ std::cout << std::endl;
+ } else {
+ x->DisplayError( iRc );
}
- #endif // XB_INDEX_SUPPORT
- std::cout << std::endl;
}
}
/*************************************************************************************/
@@ -1716,7 +1738,7 @@ void xbUtil::DisplayTableStats(){
iOptionNo = 1;
}
if( iOptionNo < 5 ) {
- d->ReadHeader( xbTrue, 0 );
+ // d->ReadHeader( xbTrue, 0 ); moved to DumpHeader routine
d->DumpHeader( iOptionNo );
} else {
// DBMS settings
@@ -2192,6 +2214,8 @@ void xbUtil::ProcessOption( const xbString &sOption ){
DisplayTableInfo();
else if( sOption == "=3.15" )
RenameTable();
+ else if( sOption == "=3.16" )
+ DeleteTable();
else if( sOption == "=4" )
RecordMenu();
else if( sOption == "=4.1" )
@@ -2824,7 +2848,7 @@ void xbUtil::FileMenu()
std::cout << "13 - Update Table Auto Commit Setting" << std::endl;
std::cout << "14 - Display Table Info" << std::endl;
std::cout << "15 - Rename Table" << std::endl;
-
+ std::cout << "16 - Delete Table" << std::endl;
std::cout << "99 - Exit Menu" << std::endl;
option = GetOption();
@@ -2833,7 +2857,7 @@ void xbUtil::FileMenu()
case 0: break;
case 1: ListFilesInDataDirectory(); break;
case 2: UpdateDataDirectory(); break;
- case 3: x->DisplayTableList(); break;
+ case 3: x->DisplayTableList(); break;
case 4: Open(); break;
case 5: Close(); break;
case 6: CloseAllTables(); break;
@@ -2845,13 +2869,13 @@ void xbUtil::FileMenu()
case 13: UpdateTableAutoCommit(); break;
case 14: DisplayTableInfo(); break;
case 15: RenameTable(); break;
+ case 16: DeleteTable(); break;
case 99: break;
default: std::cout << "Invalid Option" << std::endl;
}
}
}
-
/************************************************************************/
#ifdef XB_NDXINF_SUPPORT
void xbUtil::InfFileMenu()
@@ -3391,7 +3415,7 @@ void xbUtil::FindKey(){
default:
std::cout << "Unknown key type [" << cKeyType << "]" << std::endl;
return;
- break;
+ // break;
}
char cBuf[128];
@@ -3457,8 +3481,9 @@ void xbUtil::Reindex(){
std::cout << "Tag not selected" << std::endl;
return;
}
- void *vpCurTag = dActiveTable->GetCurTag();
- xbInt16 iRc = pIx->Reindex( &vpCurTag );
+ //void *vpCurTag = dActiveTable->GetCurTag();
+ //xbInt16 iRc = pIx->Reindex( &vpCurTag );
+ xbInt16 iRc = dActiveTable->Reindex( 0 );
x->DisplayError( iRc );
}
diff --git a/src/utils/xb_execsql.cpp b/src/utils/xb_execsql.cpp
index daa6b6e..3441e91 100755
--- a/src/utils/xb_execsql.cpp
+++ b/src/utils/xb_execsql.cpp
@@ -15,12 +15,21 @@ Email Contact:
*/
#include <xbase.h>
-
using namespace xb;
-xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd );
-xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd )
-{
+void PrintHelp();
+void PrintHelp(){
+ std::cout << "Usage: xb_execsql [-h] [-?] [--help] [-v] [--version] -i filename.SQL -q --quiet" << std::endl << std::endl;
+ std::cout << "This program processes sql commands from input file 'filename.SQL'" << std::endl << std::endl;
+}
+void PrintVersion();
+void PrintVersion(){
+ std::cout << "Xbase64 Version: " << xbase_VERSION_MAJOR << "." << xbase_VERSION_MINOR << "." << xbase_VERSION_PATCH << std::endl;
+}
+
+
+xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd, xbBool bQuiet );
+xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd, xbBool bQuiet ){
sCmd = "";
xbString sLine;
xbInt16 iRc = XB_NO_ERROR;
@@ -31,6 +40,12 @@ xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd )
bDone = xbTrue;
} else {
+ if( !bQuiet ){
+ std::cout << sLine;
+ if( sLine.Pos( 0x0a ) == 0 )
+ std::cout << std::endl;
+ }
+
// don't need CR/LF chars
sLine.ZapChar( 0x0a );
sLine.ZapChar( 0x0d );
@@ -50,23 +65,43 @@ xbInt16 GetNextSqlCmd( xbFile &f, xbString &sCmd )
return iRc;
}
-int main(int ac,char** av)
+
+int main(int argc, char* argv[])
{
+ xbXBase x;
+ xbSql sql( &x );
+ xbFile f( sql.GetXbasePtr() );
+ xbInt16 iRc = XB_NO_ERROR;
+ xbString sFileName = "";
+ xbString sSqlLine = "";
+ xbString sParm = "";
+ xbBool bQuiet = xbFalse;
+
+ x.EnableMsgLogging();
- if (ac <= 1) {
- std::cout << "Usage: xb_execsql filename..." << std::endl;
+ if (argc < 2 || x.GetCmdLineOpt( argc, argv, "-h", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "-?", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--help", sParm )){
+ PrintHelp();
return 1;
}
- xbXBase x;
- x.EnableMsgLogging();
- xbSql sql( &x );
- xbFile f( sql.GetXbasePtr() );
- xbInt16 iRc = XB_NO_ERROR;
- xbString sFileName;
- xbString sSqlLine;
+ if ( x.GetCmdLineOpt( argc, argv, "-v", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--version", sParm )){
+ PrintVersion();
+ return 1;
+ }
+
+ if ( x.GetCmdLineOpt( argc, argv, "-q", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--quiet", sParm )){
+ bQuiet = xbTrue;
+ }
+
+ if( !x.GetCmdLineOpt( argc, argv, "-i", sFileName ) || sFileName == "" ){
+ PrintHelp();
+ return 1;
+ }
- sFileName = av[1];
if(( iRc = f.xbFopen( "r", sFileName, XB_SINGLE_USER )) != XB_NO_ERROR ){
xbString sMsg;
@@ -77,12 +112,12 @@ int main(int ac,char** av)
}
while( iRc == XB_NO_ERROR ){
- iRc = GetNextSqlCmd( f, sSqlLine );
+ iRc = GetNextSqlCmd( f, sSqlLine, bQuiet );
if( iRc == XB_NO_ERROR ){
sSqlLine.Trim();
- std::cout << "Processing line [" << sSqlLine.Str() << "]\n";
+ // std::cout << "Processing line [" << sSqlLine.Str() << "]\n";
iRc = sql.ExecuteNonQuery( sSqlLine );
if( iRc != XB_NO_ERROR )
x.DisplayError( iRc );
diff --git a/src/utils/xb_import.cpp b/src/utils/xb_import.cpp
new file mode 100755
index 0000000..272a0d0
--- /dev/null
+++ b/src/utils/xb_import.cpp
@@ -0,0 +1,242 @@
+/* xb_import.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2023 Gary A Kunkel
+
+The xb64 software library is covered under
+the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ xb64-devel@lists.sourceforge.net
+ xb64-users@lists.sourceforge.net
+
+*/
+
+#include <xbase.h>
+using namespace xb;
+
+
+struct sFldMap{
+ xbUInt32 iRecPos;
+ xbInt16 iFldNo;
+ char cFldType;
+ sFldMap *next;
+};
+
+void PrintHelp();
+void PrintHelp(){
+ std::cout << "Usage: xb_execsql [-h] [-?] [--help] [-v] [--version] -i infilename.txt -d delimeter -t table.DBF -q --quiet" << std::endl << std::endl;
+ std::cout << "This program imports data from a text file into a specified DBF file/table." << std::endl << std::endl;
+}
+void PrintVersion();
+void PrintVersion(){
+ std::cout << "Xbase64 Version: " << xbase_VERSION_MAJOR << "." << xbase_VERSION_MINOR << "." << xbase_VERSION_PATCH << std::endl;
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ xbXBase x;
+ xbSql sql( &x );
+ xbFile f( sql.GetXbasePtr() );
+ xbInt16 iRc = XB_NO_ERROR;
+ xbString sFileName = "";
+ xbString sTableName = "";
+ xbString sSqlLine = "";
+ xbString sParm = "";
+ xbString sMsg;
+ xbString sLine;
+ xbString sFld;
+ xbBool bQuiet = xbFalse;
+ char cDelimiter = ',';
+ char cType = ' ';
+ sFldMap *fmFldList = 0;
+ sFldMap *fmTemp = 0;
+ xbInt16 iFldNo = 0;
+ xbUInt32 ulRecCtr = 0;
+ xbBool bRecUpdated;
+ x.EnableMsgLogging();
+
+
+ if (argc < 2 || x.GetCmdLineOpt( argc, argv, "-h", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "-?", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--help", sParm )){
+ PrintHelp();
+ return 1;
+ }
+
+ if ( x.GetCmdLineOpt( argc, argv, "-v", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--version", sParm )){
+ PrintVersion();
+ return 1;
+ }
+
+ if ( x.GetCmdLineOpt( argc, argv, "-q", sParm ) ||
+ x.GetCmdLineOpt( argc, argv, "--quiet", sParm )){
+ bQuiet = xbTrue;
+ }
+
+ if ( x.GetCmdLineOpt( argc, argv, "-d", sParm )){
+ if( sParm.Len() > 0 ){
+ cDelimiter = sParm[1];
+ }
+ }
+
+ if( !x.GetCmdLineOpt( argc, argv, "-i", sFileName ) || sFileName == "" ){
+ PrintHelp();
+ return 1;
+ }
+
+ if( !x.GetCmdLineOpt( argc, argv, "-t", sTableName ) || sTableName == "" ){
+ PrintHelp();
+ return 1;
+ }
+
+ xbDbf *MyFile = NULL;
+ if(( iRc = x.OpenHighestVersion( sTableName.Str(), "", &MyFile )) != XB_NO_ERROR ){
+ std::cout << "Could not open table/file RC = " << iRc << " file = " << sTableName.Str() << std::endl;
+ x.DisplayError( iRc );
+ return 1;
+ }
+
+ if(( iRc = f.xbFopen( "r", sFileName, XB_SINGLE_USER )) != XB_NO_ERROR ){
+ sMsg.Sprintf( "Error opening [%s]\n", sFileName.Str() );
+ std::cout << sMsg.Str();
+ x.DisplayError( iRc );
+ return 1;
+ }
+
+
+ if(( iRc = f.xbFgets( 1024, sLine )) != XB_NO_ERROR ){
+ sMsg.Sprintf( "Error reading [%s]\n", sFileName.Str() );
+ std::cout << sMsg.Str();
+ x.DisplayError( iRc );
+ return 1;
+ }
+
+
+ // determine how many fields in a record
+ xbUInt32 lFldCnt = sLine.CountChar( cDelimiter, 1 );
+ // std::cout << "in rec = [" << sLine.Str() << "]\n";
+ // std::cout << "fld cnt = [" << lFldCnt << "]\n";
+
+ // do the mapping between field names in source data and field numbers in target table
+ for( xbUInt32 l = 0; l < (lFldCnt + 1); l++ ){
+
+ // get the field
+ sFld.ExtractElement( sLine.Str(), cDelimiter, l+1, 1 );
+ sFld.ZapTrailingChar( 0x0a ); // eliminate CRLF
+ sFld.ZapTrailingChar( 0x0d ); // eliminate CRLF
+
+
+ // do the lookup
+ // std::cout << "processing field [" << l << "] [" << sFld.Str() << "]\n";
+ // if found, create an entry in the field list structure
+ // else if not quiet, display a message
+
+ //iRc = MyFile->GetFieldNo( sFld, &iFldNo );
+
+ if(( iRc = MyFile->GetFieldNo( sFld, iFldNo )) == XB_NO_ERROR ){
+ MyFile->GetFieldType( iFldNo, cType );
+ fmTemp = (sFldMap *) calloc( 1, sizeof( sFldMap ));
+ if( !fmTemp ){
+ std::cout << "Memory allocation error\n";
+ exit(1);
+ } else {
+ fmTemp->iRecPos = l;
+ fmTemp->iFldNo = iFldNo;
+ fmTemp->cFldType = cType;
+ fmTemp->next = fmFldList;
+ fmFldList = fmTemp;
+
+ }
+ } else {
+ if( !bQuiet ){
+ std::cout << "Field [" << sFld.Str() << "] not found in target table" << std::endl;
+ }
+ }
+ }
+
+
+ while( f.xbFgets( 1024, sLine ) == XB_NO_ERROR ){
+ bRecUpdated = xbFalse;
+ // std::cout << sLine.Str() << "\n";
+
+ if(( iRc = MyFile->BlankRecord()) != XB_NO_ERROR ){
+ sMsg.Sprintf( "MyFile->BlankRecord() error [%d]\n", iRc );
+ std::cout << sMsg.Str();
+ x.DisplayError( iRc );
+ } else {
+
+ fmTemp = fmFldList;
+ while( fmTemp ){
+
+ // std::cout << "*** RecPos = " << fmTemp->iRecPos << " FldNo = " << fmTemp->iFldNo << " Type = " << fmTemp->cFldType << "\n";
+
+ sFld.ExtractElement( sLine.Str(), cDelimiter, fmTemp->iRecPos+1, 1 );
+ sFld.ZapTrailingChar( 0x0a ); // eliminate CRLF
+ sFld.ZapTrailingChar( 0x0d ); // eliminate CRLF
+
+ // remove any matching leading and trailing quotes
+ if( sFld[1] == '\'' && sFld[sFld.Len()] == '\'' ){
+ sFld.ZapTrailingChar( '\'' );
+ sFld.ZapLeadingChar ( '\'' );
+ //std::cout << "DataNq = " << sFld.Str() << "\n";
+ } else if( sFld[1] == '"' && sFld[sFld.Len()] == '"' ){
+ sFld.ZapTrailingChar( '"' );
+ sFld.ZapLeadingChar ( '"' );
+ }
+
+ // std::cout << "Data = " << sFld.Str() << "\n";
+ if( sFld.Len() > 0 ){
+ bRecUpdated = xbTrue;
+ if( fmTemp->cFldType == 'C' || fmTemp->cFldType == 'L' || fmTemp->cFldType == 'D' || fmTemp->cFldType == 'N' || fmTemp->cFldType == 'F' ){
+ iRc = MyFile->PutField( fmTemp->iFldNo, sFld );
+ } else if( fmTemp->cFldType == 'M' ){
+ iRc = MyFile->UpdateMemoField( fmTemp->iFldNo, sFld );
+ } else {
+ std::cout << "Field type [" << fmTemp->cFldType << "] not built yet" << std::endl;
+ }
+
+ if( iRc != XB_NO_ERROR && !bQuiet ){
+ std::cout << "Error [" << iRc << "] on field [" << fmTemp->iFldNo << "] on record [" << ulRecCtr << "]" << std::endl;
+ }
+ }
+ fmTemp = fmTemp->next;
+ }
+
+ if( bRecUpdated ){
+ iRc = MyFile->AppendRecord();
+ if( iRc != XB_NO_ERROR ){
+ if( !bQuiet ){
+ std::cout << "Error [" << iRc << "] on appending record [" << ulRecCtr << "]" << std::endl;
+ }
+ MyFile->Abort();
+ } else {
+ iRc = MyFile->Commit();
+ if( iRc != XB_NO_ERROR ){
+ if( !bQuiet ){
+ std::cout << "Error [" << iRc << "] on appending record [" << ulRecCtr << "]" << std::endl;
+ }
+ MyFile->Abort();
+ }
+ }
+ }
+
+ }
+
+ ulRecCtr++;
+
+ }
+
+
+
+
+
+ f.xbFclose();
+ return 0;
+}
+