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