/* xbxbase.cpp XBase64 Software Library Copyright (c) 1997,2003,2014,2022 Gary A Kunkel The xb64 software library is covered under the terms of the GPL Version 3, 2007 license. Email Contact: XDB-devel@lists.sourceforge.net XDB-users@lists.sourceforge.net */ #include "xbase.h" namespace xb{ /*************************************************************************/ //! @brief Class Constructor. xbXBase::xbXBase() { SetEndianType(); #ifdef XB_LOGGING_SUPPORT xLog = new xbLog(); #endif } /*************************************************************************/ //! @brief Class Deconstructor. xbXBase::~xbXBase(){ CloseAllTables(); #ifdef XB_LOGGING_SUPPORT delete xLog; #endif } /*************************************************************************/ //! @brief Close all tables / files. /*! This closes everything. \returns Return Codes */ xbInt16 xbXBase::CloseAllTables(){ xbInt16 iRc = 0; xbInt16 iErrorStop = 0; xbInt16 iOpenTableCnt = GetOpenTableCount(); try{ xbDbf *d; for( xbInt16 i = 0; i < iOpenTableCnt; i++ ){ d = (xbDbf *) GetDbfPtr( 1 ); if( d ){ if(( iRc = d->Close()) != XB_NO_ERROR ){ iErrorStop = 100; throw iRc; } } else { iRc = XB_INVALID_OBJECT; iErrorStop = 110; throw iRc; } } } catch (xbInt16 iRc ){ xbString sMsg; sMsg.Sprintf( "xbxbase::CloseAllTables() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc ); WriteLogMessage( sMsg.Str() ); WriteLogMessage( GetErrorMessage( iRc )); } return iRc; } /*************************************************************************/ #ifdef XB_LOGGING_SUPPORT //! @brief Get fully qualified log file name. /*! \returns Returns the fully qualified log file name. */ const xbString & xbXBase::GetLogFqFileName() const { return xLog->GetFqFileName(); } //! @brief Get the log file name. /*! \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(); } //! @brief Get the log directory. /*! \returns xbTrue - Logging enabled.
xbFalse - Logging disables. */ xbBool xbXBase::GetLogStatus() const { return xLog->LogGetStatus(); } //! @brief Set the log file name. /*! \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. /*! \param lSize - Log File Size. \return void */ void xbXBase::SetLogSize( size_t lSize ) { xLog->LogSetLogSize( lSize ); } //! @brief Write message to logfile. /*! \param sLogMessage - Message to write. \param iOpt 0 = stdout
1 = Syslog
2 = Both
\returns Return Codes */ xbInt16 xbXBase::WriteLogMessage( const xbString & sLogMessage, xbInt16 iOpt ){ return xLog->LogWrite( sLogMessage, iOpt ); } //! @brief Write message to logfile. /*! \param lCnt - Number of bytes to write. \param p - Pointer to bytes to write to log file. \returns Return Codes */ xbInt16 xbXBase::WriteLogBytes( xbUInt32 lCnt, const char *p ){ return xLog->LogWriteBytes( lCnt, p ); } //! @brief Enable message logging. void xbXBase::EnableMsgLogging() { xLog->LogSetStatus( xbTrue ); } //! @brief Disable message logging. void xbXBase::DisableMsgLogging() { xLog->LogSetStatus( xbFalse ); } //! @brief Flush log file updates to disk. xbInt16 xbXBase::FlushLog() { return xLog->xbFflush(); } #else // if logging not compiled in, these stubs are called with no effect 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; } xbInt16 xbXBase::WriteLogMessage( const xbString & sLogMessage, xbInt16 ){ return XB_NO_ERROR; } xbInt16 xbXBase::WriteLogBytes( xbUInt32 lCnt, const char *p ){ return XB_NO_ERROR; } void xbXBase::EnableMsgLogging() { return; } void xbXBase::DisableMsgLogging() { return; } xbInt16 xbXBase::FlushLog() { return XB_NO_ERROR; } void xbXBase::SetLogSize( size_t lSize ) { return; } #endif // XB_LOGGING_SUPPORT /*************************************************************************/ #ifdef XB_FUNCTION_SUPPORT //! @brief Get information regarding expression functions. /*! \param sExpLine An expression beginning with function name. \param cReturnType Output - return type of function. \param iCalc Used to calculate the function return value is
1 = use value specified in lReturnLenVal
2 = use length of operand specified in col 4
3 = use valued of numeric operand specified in col 4
4 = length of parm 1 * numeric value parm
5 = larger length of parm 2 or length of parm 3
6 = if two or more parms, use numeric value from second parm, otherwise use col4 value \param lReturnLenVal Used in combination with iReturnLenCalc. \returns Return Codes */ xbInt16 xbXBase::GetFunctionInfo( const xbString &sExpLine, char &cReturnType, xbInt16 &iCalc, xbInt32 &lReturnLenVal ) const{ xbUInt32 iLen; const char *s; if( sExpLine.Len() == 0 ) return XB_INVALID_FUNCTION; s = sExpLine; iLen = 0; while( *s && *s != '(' && *s != ' ' ) { s++; iLen++; } xbString sFunction( sExpLine, iLen ); cReturnType = 0x00; char cFunc1 = sFunction[1]; if( cFunc1 < 'L' ){ // std::cout << "less than L\n"; if( cFunc1 < 'D' ){ // std::cout << "less than D\n"; if( sFunction == "ABS" ){ // { "ABS", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "ALLTRIM" ){ // { "ALLTRIM", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "ASC" ){ // { "ASC", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "AT" ){ // { "AT", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "CDOW" ){ // { "CDOW", 'C', 1, 9 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 9; } else if( sFunction == "CHR" ){ // { "CHR", 'C', 1, 1 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 1; } else if( sFunction == "CMONTH" ){ // { "CMONTH", 'C', 1, 9 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 9; } else if( sFunction == "CTOD" ){ // { "CTOD", 'D', 1, 8 }, cReturnType = 'D'; iCalc = 1; lReturnLenVal = 8; } } else { // std::cout << ">= D\n"; if( sFunction == "DATE" ){ // { "DATE", 'D', 1, 8 }, cReturnType = 'D'; iCalc = 1; lReturnLenVal = 8; } else if( sFunction == "DAY" ){ // { "DAY", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "DEL" ){ // { "DEL", 'C', 1, 1 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 1; } else if( sFunction == "DELETED" ){ // { "DELETED", 'L', 1, 1 }, cReturnType = 'L'; iCalc = 1; lReturnLenVal = 1; } else if( sFunction == "DESCEND" ){ // { "DESCEND", '1', 2, 1 }, cReturnType = '1'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "DOW" ){ // { "DOW", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "DTOC" ){ // { "DTOC", 'C', 1, 8 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 8; } else if( sFunction == "DTOS" ){ // { "DTOS", 'C', 1, 8 }, cReturnType = 'C'; iCalc = 1; lReturnLenVal = 8; } else if( sFunction == "EXP" ){ // { "EXP", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "IIF" ){ // { "IIF", 'C', 5, 0 }, cReturnType = 'C'; iCalc = 5; lReturnLenVal = 0; } else if( sFunction == "INT" ){ // { "INT", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "ISALPHA" ){ // { "ISALPHA", 'L', 1, 1 }, cReturnType = 'L'; iCalc = 1; lReturnLenVal = 1; } else if( sFunction == "ISLOWER" ){ // { "ISLOWER", 'L', 1, 1 }, cReturnType = 'L'; iCalc = 1; lReturnLenVal = 1; } else if( sFunction == "ISUPPER" ){ // { "ISUPPER", 'L', 1, 1 }, cReturnType = 'L'; iCalc = 1; lReturnLenVal = 1; } } } else { // std::cout << ">= L\n"; if( cFunc1 < 'R' ) { // std::cout << " < R\n"; if( sFunction == "LEFT" ){ // { "LEFT", 'C', 3, 2 }, cReturnType = 'C'; iCalc = 3; lReturnLenVal = 2; } else if( sFunction == "LEN" ){ // { "LEN", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 3; } else if( sFunction == "LOG" ){ // { "LOG", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "LOWER" ){ // { "LOWER", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "LTRIM" ){ // { "LTRIM", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "MAX" ){ // { "MAX", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "MIN" ){ // { "MIN", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "MONTH" ){ // { "MONTH", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } } else if( cFunc1 == 'R' ){ // std::cout << "==R\n"; if( sFunction == "RECNO" ){ // { "RECNO", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "RECCOUNT" ){ // { "RECCOUNT", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "REPLICATE" ){ // { "REPLICATE", 'C', 4, 0 }, cReturnType = 'C'; iCalc = 4; lReturnLenVal = 0; } else if( sFunction == "RIGHT" ){ // { "RIGHT", 'C', 3, 2 }, cReturnType = 'C'; iCalc = 3; lReturnLenVal = 2; } else if( sFunction == "RTRIM" ){ // { "RTRIM", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } } else if( cFunc1 == 'S' ){ // std::cout << "==S\n"; if( sFunction == "SPACE" ){ // { "SPACE", 'C', 3, 1 }, cReturnType = 'C'; iCalc = 3; lReturnLenVal = 1; } else if( sFunction == "SQRT" ){ // { "SQRT", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } else if( sFunction == "STOD" ){ // { "STOD", 'D', 1, 8 }, cReturnType = 'D'; iCalc = 1; lReturnLenVal = 8; } else if( sFunction == "STR" ){ // { "STR", 'C', 6, 10 }, cReturnType = 'C'; iCalc = 6; lReturnLenVal = 10; } else if( sFunction == "STRZERO" ){ // { "STRZERO", 'C', 3, 2 }, cReturnType = 'C'; iCalc = 3; lReturnLenVal = 2; } else if( sFunction == "SUBSTR" ){ // { "SUBSTR", 'C', 3, 3 }, cReturnType = 'C'; iCalc = 3; lReturnLenVal = 3; } } else { // std::cout << ">S\n"; if( sFunction == "TRIM" ){ // { "TRIM", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "UPPER" ){ // { "UPPER", 'C', 2, 1 }, cReturnType = 'C'; iCalc = 2; lReturnLenVal = 1; } else if( sFunction == "VAL" ){ // { "VAL", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 3; } else if( sFunction == "YEAR" ){ // { "YEAR", 'N', 1, 4 }, cReturnType = 'N'; iCalc = 1; lReturnLenVal = 4; } } } if( cReturnType == 0x00 ) return XB_INVALID_FUNCTION; else return XB_NO_ERROR; } #endif /*************************************************************************/ //! @brief Cross platform sleep function. /*! \param lMillisecs Milliseconds to sleep. */ void xbXBase::xbSleep( xbInt32 lMillisecs ){ #ifdef WIN32 Sleep( lMillisecs ); #else usleep( (xbInt64) lMillisecs * 1000 ); #endif } /***********************************************************************/ //! @brief Cross memcmp function. /*! \param s1 Left operand to compare. \param s2 Right operand to compare. \param n Number of bytes to compare. \returns 1 s1 > s2
0 s1 == s2
-1 s1 < s2 */ xbInt16 xbXBase::xbMemcmp( const unsigned char *s1, const unsigned char *s2, size_t n ){ // The standard memcmp function was found not to behave the same across all platforms for( size_t i = 0; i < n; i++ ){ if( s1[i] > s2[i] ) return 1; else if( s1[i] < s2[i] ) return -1; } return 0; } /***********************************************************************/ //! @brief Open highest qualified class available for dbf file. /*! This routine opens the highest available version of the dbf file. Defaults to XB_READ_WRITE and XB_MULTI_USER mode. \returns param dbf - Output pointer to dbf file opened or null if error */ xbDbf* xbXBase::Open( const xbString &sTableName, xbInt16 &iRc ){ return Open( sTableName, "", XB_READ_WRITE, XB_MULTI_USER, 0, iRc ); } /***********************************************************************/ //! @brief Open highest qualified class available for dbf file. /*! This routine can open various versions of the dbf file dependent on the iVersion field \param sTableName - Table name to open. \param sAlias - Optional alias name. \param iOpenMode - XB_READ_WRITE or XB_READ \param iShareMode - XB_SINGLE_USER or XB_MULTI_USER \param iRequestVersion 0 - Highest available 4 - Version four dbf 3 - Version three dbf \param iRc - Return code from open request \returns param dbf - Output pointer to dbf file opened or null if error */ xbDbf* xbXBase::Open( const xbString &sTableName, const xbString &sAlias, xbInt16 iOpenMode, xbInt16 iShareMode, xbInt16 iRequestVersion, xbInt16 &iRc ){ xbInt16 iErrorStop = 0; xbDbf * pDbf = 0; iRc = 0; xbString sFqFileName; try{ if( sTableName.Len() == 0 ){ iErrorStop = 100; iRc = XB_FILE_NOT_FOUND; throw iRc; } xbFile *f = new xbFile(this); f->SetFileName( sTableName ); if(( iRc = f->FileExists( f->GetFqFileName())) != xbTrue ){ iErrorStop = 110; iRc = XB_FILE_NOT_FOUND; throw iRc; } unsigned char cFileTypeByte; if(( iRc = f->GetXbaseFileTypeByte( f->GetFqFileName(), cFileTypeByte )) != XB_NO_ERROR ){ iErrorStop = 120; throw iRc; } xbInt16 iTblVsn = f->DetermineXbaseTableVersion( cFileTypeByte ); f->xbFclose(); sFqFileName.Set( f->GetFqFileName() ); delete f; if( iTblVsn == 4 && ( iRequestVersion == 0 || iRequestVersion == 4 )){ #ifdef XB_DBF4_SUPPORT pDbf = new xbDbf4( this ); iRc = pDbf->Open( sFqFileName, sAlias, iOpenMode, iShareMode ); #else // std::cout << "Dbase IV file support not build into library. See XB_DBF4_SUPPORT" << std::endl; iErrorStop = 130; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; #endif } else if( iTblVsn == 3 && ( iRequestVersion == 0 || iRequestVersion == 3 )){ #ifdef XB_DBF3_SUPPORT pDbf = new xbDbf3( this ); iRc = pDbf->Open( sFqFileName, sAlias, iOpenMode, iShareMode ); #else //std::cout << "Dbase III file support not build into library. See XB_DBF3_SUPPORT" << std::endl; iErrorStop = 140; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; #endif } else { iErrorStop = 150; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; } if( iRc != XB_NO_ERROR ){ iErrorStop = 160; throw iRc; } } catch (xbInt16 iRc ){ xbString sMsg; sMsg.Sprintf( "xbxbase::Open() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc ); WriteLogMessage( sMsg.Str() ); WriteLogMessage( GetErrorMessage( iRc )); } return pDbf; } xbInt16 xbXBase::OpenHighestVersion( const xbString &sTableName, const xbString &sAlias, xbDbf **dbf ) { xbInt16 iRc = 0; xbInt16 iErrorStop = 0; try{ xbFile f(this); if( sTableName.Len() == 0 ){ iErrorStop = 100; iRc = XB_FILE_NOT_FOUND; throw iRc; } f.SetFileName( sTableName ); if(( iRc = f.FileExists( f.GetFqFileName() )) != xbTrue ){ iErrorStop = 110; iRc = XB_FILE_NOT_FOUND; throw iRc; } unsigned char cFileTypeByte; if(( iRc = f.GetXbaseFileTypeByte( f.GetFqFileName(), cFileTypeByte )) != XB_NO_ERROR ){ iErrorStop = 120; return iRc; } if( f.DetermineXbaseTableVersion( cFileTypeByte ) == 4 ){ #ifdef XB_DBF4_SUPPORT xbDbf *pwDbf = new xbDbf4( this ); pwDbf->Open( f.GetFqFileName(), sAlias ); *dbf = pwDbf; pwDbf = 0; #else // std::cout << "Dbase IV file support not build into library. See XB_DBF4_SUPPORT" << std::endl; iErrorStop = 130; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; #endif } else if( f.DetermineXbaseTableVersion( cFileTypeByte ) == 3 ){ #ifdef XB_DBF3_SUPPORT *dbf = new xbDbf3( this ); #else //std::cout << "Dbase III file support not build into library. See XB_DBF3_SUPPORT" << std::endl; iErrorStop = 140; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; #endif } else { iErrorStop = 150; iRc = XB_FILE_TYPE_NOT_SUPPORTED; throw iRc; } } catch (xbInt16 iRc ){ xbString sMsg; sMsg.Sprintf( "xbxbase::OpenHighestVersion() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc ); WriteLogMessage( sMsg.Str() ); WriteLogMessage( GetErrorMessage( iRc )); } return iRc; } /***********************************************************************/ } /* namespace */