/** \brief Check whether the token at a given position is a function token. \param a_Tok [out] If a value token is found it will be placed here. \throw ParserException if Syntaxflags do not allow a function at a_iPos \return true if a function token has been found false otherwise. \pre [assert] m_pParser!=0 */ bool ParserTokenReader::IsFunTok(token_type &a_Tok) { string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; funmap_type::const_iterator item = m_pFunDef->find(strTok); if (item==m_pFunDef->end()) return false; // Check if the next sign is an opening bracket const char_type *szFormula = m_strFormula.c_str(); if (szFormula[iEnd]!='(') return false; a_Tok.Set(item->second, strTok); m_iPos = (int)iEnd; if (m_iSynFlags & noFUN) Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); m_iSynFlags = noANY ^ noBO; return true; }
/** \brief Check if a string position contains a binary operator. */ bool TokenReader::IsOprt(ptr_tok_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_nPos); if (iEnd == m_nPos) return false; oprt_bin_maptype::reverse_iterator item; try { // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. for (item = m_pOprtDef->rbegin(); item != m_pOprtDef->rend(); ++item) { if (sTok.find(item->first) != 0) continue; // operator found, check if we expect one... if (m_nSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can use the same characters in their identifiers. if (IsInfixOpTok(a_Tok)) return true; // nope, it's no infix operator and we dont expect // an operator throw ecUNEXPECTED_OPERATOR; } else { a_Tok = ptr_tok_type(item->second->Clone()); m_nPos += (int)a_Tok->GetIdent().length(); m_nSynFlags = noBC | noIO | noIC | noOPT | noCOMMA | noEND | noNEWLINE | noPFX | noIF | noELSE; return true; } } return false; } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos; // - (int)item->first.length(); err.Ident = item->first; err.Expr = m_sExpr; throw ParserError(err); } }
/** \brief Check if a string position contains a unary post value operator. */ bool TokenReader::IsPostOpTok(ptr_tok_type &a_Tok) { if (m_nSynFlags & noPFX) { // <ibg 2014-05-30/> Only look for postfix operators if they are allowed at the given position. // This will prevent conflicts with variable names such as: // "sin(n)" where n is the postfix for "nano" return false; // </ibg> } // Tricky problem with equations like "3m+5": // m is a postfix operator, + is a valid sign for postfix operators and // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. // // This is a special case so this routine slightly differs from the other // token readers. // Test if there could be a postfix operator string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_nPos); if (iEnd == m_nPos) return false; try { // iteraterate over all postfix operator strings oprt_pfx_maptype::const_iterator item; for (item = m_pPostOprtDef->begin(); item != m_pPostOprtDef->end(); ++item) { if (sTok.find(item->first) != 0) continue; a_Tok = ptr_tok_type(item->second->Clone()); m_nPos += (int)item->first.length(); if (m_nSynFlags & noPFX) throw ecUNEXPECTED_OPERATOR; m_nSynFlags = noVAL | noVAR | noFUN | noBO | noPFX /*| noIO*/ | noIF; return true; } return false; } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos - (int)a_Tok->GetIdent().length(); err.Ident = a_Tok->GetIdent(); err.Expr = m_sExpr; throw ParserError(err); } }
/** \brief Check wheter a token at a given position is a variable token. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a variable token has been found. */ bool TokenReader::IsVarOrConstTok(ptr_tok_type &a_Tok) { if (!m_pVarDef->size() && !m_pConstDef->size() && !m_pFunDef->size()) return false; string_type sTok; int iEnd; try { iEnd = ExtractToken(m_pParser->ValidNameChars(), sTok, m_nPos); if (iEnd == m_nPos || (sTok.size() > 0 && sTok[0] >= _T('0') && sTok[0] <= _T('9'))) return false; // Check for variables var_maptype::const_iterator item = m_pVarDef->find(sTok); if (item != m_pVarDef->end()) { if (m_nSynFlags & noVAR) throw ecUNEXPECTED_VAR; m_nPos = iEnd; m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX; a_Tok = ptr_tok_type(item->second->Clone()); a_Tok->SetIdent(sTok); m_UsedVar[item->first] = item->second; // Add variable to used-var-list return true; } // Check for constants item = m_pConstDef->find(sTok); if (item != m_pConstDef->end()) { if (m_nSynFlags & noVAL) throw ecUNEXPECTED_VAL; m_nPos = iEnd; m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX | noIO; a_Tok = ptr_tok_type(item->second->Clone()); a_Tok->SetIdent(sTok); return true; } } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos; err.Ident = sTok; err.Expr = m_sExpr; throw ParserError(err); } return false; }
/** \brief Check whether the token at a given position is a value token. Value tokens are either values or constants. \param a_Tok [out] If a value token is found it will be placed here. \return true if a value token has been found. */ bool ParserTokenReader::IsValTok(token_type &a_Tok) { assert(m_pConstDef); assert(m_pParser); string_type strTok; value_type fVal(0); int iEnd(0); // 2.) Check for user defined constant // Read everything that could be a constant name iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) { valmap_type::const_iterator item = m_pConstDef->find(strTok); if (item!=m_pConstDef->end()) { m_iPos = iEnd; a_Tok.SetVal(item->second, strTok); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } // 3.call the value recognition functions provided by the user // Call user defined value recognition functions std::list<identfun_type>::const_iterator item = m_vIdentFun.begin(); for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) { int iStart = m_iPos; if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) { strTok.assign(m_strFormula.c_str(), iStart, m_iPos); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); a_Tok.SetVal(fVal, strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } return false; }
/** \brief Read the next token from the string. */ ParserTokenReader::token_type ParserTokenReader::ReadNextToken() { assert(m_pParser); std::stack<int> FunArgs; const char_type *szFormula = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) ++m_iPos; if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if // undefined variables occur. // (The GetUsedVar function must suppress the error for // undefined variables in order to collect all variable // names including the undefined ones.) if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return SaveBeforeReturn(tok); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached }
/** \brief Check if a string position contains a unary post value operator. */ bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) { // <ibg 20110629> Do not check for postfix operators if they are not allowed at // the current expression index. // // This will fix the bug reported here: // // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 // if (m_iSynFlags & noPOSTOP) return false; // </ibg> // Tricky problem with equations like "3m+5": // m is a postfix operator, + is a valid sign for postfix operators and // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. // // This is a special case so this routine slightly differs from the other // token readers. // Test if there could be a postfix operator string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; // iteraterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); for ( ; it!=m_pPostOprtDef->rend(); ++it) { if (sTok.find(it->first)!=0) continue; a_Tok.Set(it->second, sTok); m_iPos += (int)it->first.length(); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; return true; } return false; }
/** \brief Check wheter a token at a given position is an undefined variable. \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. \return true if a variable token has been found. \throw nothrow */ bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) { string_type strTok; int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); if ( iEnd==m_iPos ) return false; if (m_iSynFlags & noVAR) { // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the // token identifier. // related bug report: // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); } // If a factory is available implicitely create new variables if (m_pFactory) { value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); a_Tok.SetVar(fVar, strTok ); // Do not use m_pParser->DefineVar( strTok, fVar ); // in order to define the new variable, it will clear the // m_UsedVar array which will kill previousely defined variables // from the list // This is safe because the new variable can never override an existing one // because they are checked first! (*m_pVarDef)[strTok] = fVar; m_UsedVar[strTok] = fVar; // Add variable to used-var-list } else { a_Tok.SetVar((value_type*)&m_fZero, strTok); m_UsedVar[strTok] = 0; // Add variable to used-var-list } m_iPos = iEnd; // Call the variable factory in order to let it define a new parser variable m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; return true; }
/** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; funmap_type::const_iterator item = m_pInfixOprtDef->find(sTok); if (item==m_pInfixOprtDef->end()) return false; a_Tok.Set(item->second, sTok); m_iPos = (int)iEnd; if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; }
/** \brief Check Expression for the presence of a binary operator token. Userdefined binary operator "++" gives inconsistent parsing result for the equations "a++b" and "a ++ b" if alphabetic characters are allowed in operator tokens. To avoid this this function checks specifically for operator tokens. */ int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, int a_iPos) const { int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidInfixOprtChars(), a_iPos); if (iEnd==(int)string_type::npos) iEnd = (int)m_strFormula.length(); // Assign token string if there was something found if (a_iPos!=iEnd) { a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return iEnd; } else { // There is still the chance of having to deal with an operator consisting exclusively // of alphabetic characters. return ExtractToken(MUP_CHARS, a_sTok, a_iPos); } }
/** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool TokenReader::IsInfixOpTok(ptr_tok_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_nPos); if (iEnd == m_nPos) return false; try { // iteraterate over all infix operator strings oprt_ifx_maptype::const_iterator item = m_pInfixOprtDef->begin(); for (item = m_pInfixOprtDef->begin(); item != m_pInfixOprtDef->end(); ++item) { if (sTok.find(item->first) != 0) continue; a_Tok = ptr_tok_type(item->second->Clone()); m_nPos += (int)item->first.length(); if (m_nSynFlags & noIFX) throw ecUNEXPECTED_OPERATOR; m_nSynFlags = noPFX | noIFX | noOPT | noBC | noIC | noIO | noEND | noCOMMA | noNEWLINE | noIF | noELSE; return true; } return false; } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos; err.Ident = a_Tok->GetIdent(); err.Expr = m_sExpr; throw ParserError(err); } }
/** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; // iteraterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); for ( ; it!=m_pInfixOprtDef->rend(); ++it) { if (sTok.find(it->first)!=0) continue; a_Tok.Set(it->second, it->first); m_iPos += (int)it->first.length(); if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; } return false; /* a_Tok.Set(item->second, sTok); m_iPos = (int)iEnd; if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; */ }
/** \brief Check expression for function tokens. */ bool TokenReader::IsFunTok(ptr_tok_type &a_Tok) { if (m_pFunDef->size() == 0) return false; string_type sTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), sTok, m_nPos); if (iEnd == m_nPos) return false; try { fun_maptype::iterator item = m_pFunDef->find(sTok); if (item == m_pFunDef->end()) return false; m_nPos = (int)iEnd; a_Tok = ptr_tok_type(item->second->Clone()); a_Tok->Compile(_T("xxx")); if (m_nSynFlags & noFUN) throw ecUNEXPECTED_FUN; m_nSynFlags = sfALLOW_NONE ^ noBO; return true; } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos - (int)a_Tok->GetIdent().length(); err.Ident = a_Tok->GetIdent(); err.Expr = m_sExpr; throw ParserError(err); } }
/** \brief Read the next token from the string. */ ptr_tok_type TokenReader::ReadNextToken() { assert(m_pParser); SkipCommentsAndWhitespaces(); int token_pos = m_nPos; ptr_tok_type pTok; // Check for end of expression if (IsEOF(pTok)) return Store(pTok, token_pos); if (IsNewline(pTok)) return Store(pTok, token_pos); if (!(m_nSynFlags & noOPT) && IsOprt(pTok)) return Store(pTok, token_pos); // Check for user defined binary operator if (!(m_nSynFlags & noIFX) && IsInfixOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators if (IsValTok(pTok)) return Store(pTok, token_pos); // Check for values / constant tokens if (IsBuiltIn(pTok)) return Store(pTok, token_pos); // Check built in operators / tokens if (IsVarOrConstTok(pTok)) return Store(pTok, token_pos); // Check for variable tokens if (IsFunTok(pTok)) return Store(pTok, token_pos); if (!(m_nSynFlags & noPFX) && IsPostOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators // 2.) We have found no token, maybe there is a token that we don't expect here. // Again call the Identifier functions but this time only those we don't expect // to find. if ((m_nSynFlags & noOPT) && IsOprt(pTok)) return Store(pTok, token_pos); // Check for user defined binary operator if ((m_nSynFlags & noIFX) && IsInfixOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators if ((m_nSynFlags & noPFX) && IsPostOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators // </ibg> // Now we are in trouble because there is something completely unknown.... // Check the string for an undefined variable token. This is done // only if a flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if undefined variables // occur. The GetExprVar function must supress the error for undefined // variables in order to collect all variable names including the // undefined ones. if ((m_pParser->m_bIsQueryingExprVar || m_pParser->m_bAutoCreateVar) && IsUndefVarTok(pTok)) return Store(pTok, token_pos); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type sTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), sTok, m_nPos); ErrorContext err; err.Errc = ecUNASSIGNABLE_TOKEN; err.Expr = m_sExpr; err.Pos = m_nPos; if (iEnd != m_nPos) err.Ident = sTok; else err.Ident = m_sExpr.substr(m_nPos); throw ParserError(err); }
/**************************************************************************** * * ROUTINE : UnpackAndExpandAcToken * * INPUTS : INT8 * ExpandedBlock * Pointer to block structure into which the token * should be expanded. * * UINT32 * CoeffIndex * Where we are in the current block. * * OUTPUTS : * * RETURNS : The number of bits decoded * * FUNCTION : Unpacks and expands a AC DCT token. * * SPECIAL NOTES : * * * ERRORS : None. * ****************************************************************************/ void UnpackAndExpandAcToken( PB_INSTANCE *pbi, Q_LIST_ENTRY * ExpandedBlock, UINT8 * CoeffIndex ) { INT32 ExtraBits; UINT32 Token; #ifdef DEBUG ExtraBits = 0; #endif // Extract a token. Token = ExtractToken(&pbi->br, pbi->HuffRoot_VP3x[pbi->ACHuffChoice]); /* Now.. if we are using the DCT optimised coding system, extract any * assosciated additional bits token. */ if ( ExtraBitLengths_VP31[Token] > 0 ) { /* Extract the appropriate number of extra bits. */ ExtraBits = bitread(&pbi->br,ExtraBitLengths_VP31[Token]); //0; } // Take token dependant action if ( Token >= DCT_SHORT_ZRL_TOKEN ) { // "Value", "zero run" and "zero run value" tokens ExpandToken( pbi, ExpandedBlock, CoeffIndex, Token, ExtraBits ); if ( *CoeffIndex >= BLOCK_SIZE ) pbi->BlocksToDecode --; } else if ( Token == DCT_EOB_TOKEN ) { *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; } else { // Special action and EOB tokens switch ( Token ) { case DCT_EOB_PAIR_TOKEN: pbi->EOB_Run = 1; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; case DCT_EOB_TRIPLE_TOKEN: pbi->EOB_Run = 2; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; case DCT_REPEAT_RUN_TOKEN: pbi->EOB_Run = ExtraBits + 3; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; case DCT_REPEAT_RUN2_TOKEN: pbi->EOB_Run = ExtraBits + 7; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; case DCT_REPEAT_RUN3_TOKEN: pbi->EOB_Run = ExtraBits + 15; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; case DCT_REPEAT_RUN4_TOKEN: pbi->EOB_Run = ExtraBits - 1; *CoeffIndex = BLOCK_SIZE; pbi->BlocksToDecode --; break; } } }
int NaturalStringCompare( const QString & lhs, const QString & rhs, Qt::CaseSensitivity caseSensitive ) { int ii = 0; int jj = 0; QString lhsBufferQStr; QString rhsBufferQStr; int retVal = 0; // all status values are created on the stack outside the loop to make as fast as possible bool lhsNumber = false; bool rhsNumber = false; double lhsValue = 0.0; double rhsValue = 0.0; bool ok1; bool ok2; while ( retVal == 0 && ii < lhs.length() && jj < rhs.length() ) { ExtractToken( lhsBufferQStr, lhs, ii, lhsNumber ); ExtractToken( rhsBufferQStr, rhs, jj, rhsNumber ); if ( !lhsNumber && !rhsNumber ) { // both strings curr val is a simple strcmp retVal = lhsBufferQStr.compare( rhsBufferQStr, caseSensitive ); int maxLen = qMin( lhsBufferQStr.length(), rhsBufferQStr.length() ); QString tmpRight = rhsBufferQStr.left( maxLen ); QString tmpLeft = lhsBufferQStr.left( maxLen ); if ( tmpLeft.compare( tmpRight, caseSensitive ) == 0 ) { retVal = lhsBufferQStr.length() - rhsBufferQStr.length(); if ( retVal ) { QChar nextChar; if ( ii < lhs.length() ) // more on the lhs nextChar = lhs[ ii ]; else if ( jj < rhs.length() ) // more on the rhs nextChar = rhs[ jj ]; bool nextIsNum = ( nextChar == '-' || nextChar == '+' || nextChar.isDigit() ); if ( nextIsNum ) retVal = -1*retVal; } } } else if ( lhsNumber && rhsNumber ) { // both numbers, convert and compare lhsValue = lhsBufferQStr.toDouble( &ok1 ); rhsValue = rhsBufferQStr.toDouble( &ok2 ); if ( !ok1 || !ok2 ) retVal = lhsBufferQStr.compare( rhsBufferQStr, caseSensitive ); else if ( lhsValue > rhsValue ) retVal = 1; else if ( lhsValue < rhsValue ) retVal = -1; } else { // completely arebitrary that a number comes before a string retVal = lhsNumber ? -1 : 1; } } if ( retVal != 0 ) return retVal; if ( ii < lhs.length() ) return -1; else if ( jj < rhs.length() ) return 1; else return 0; }
/** Find out operating system name and version This method caches system information in m_osName, m_osVersion and m_osAlias. It requires m_unameInfo to be set prior to call. */ void SCXOSTypeInfo::Init() // private { m_osVersion = L""; m_osName = L"Unknown"; assert(m_unameIsValid); #if defined(hpux) || defined(sun) if (m_unameIsValid) { m_osName = StrFromUTF8(m_unameInfo.sysname); m_osVersion = StrFromUTF8(m_unameInfo.release); } #if defined(hpux) m_osAlias = L"HPUX"; m_osManufacturer = L"Hewlett-Packard Company"; #elif defined(sun) m_osAlias = L"Solaris"; m_osManufacturer = L"Oracle Corporation"; #endif #elif defined(aix) if (m_unameIsValid) { m_osName = StrFromUTF8(m_unameInfo.sysname); // To get "5.3" we must read "5" and "3" from different fields. string ver(m_unameInfo.version); ver.append("."); ver.append(m_unameInfo.release); m_osVersion = StrFromUTF8(ver); } m_osAlias = L"AIX"; m_osManufacturer = L"International Business Machines Corporation"; #elif defined(linux) vector<wstring> lines; SCXStream::NLFs nlfs; #if defined(PF_DISTRO_SUSE) static const string relFileName = "/etc/SuSE-release"; wifstream relfile(relFileName.c_str()); wstring version(L""); wstring patchlevel(L""); SCXStream::ReadAllLines(relfile, lines, nlfs); if (!lines.empty()) { m_osName = ExtractOSName(lines[0]); } // Set the Linux Caption (get first line of the /etc/SuSE-release file) m_linuxDistroCaption = lines[0]; if (0 == m_linuxDistroCaption.length()) { // Fallback - should not normally happen m_linuxDistroCaption = L"SuSE"; } // File contains one or more lines looking like this: // SUSE Linux Enterprise Server 10 (i586) // VERSION = 10 // PATCHLEVEL = 1 for (size_t i = 0; i<lines.size(); i++) { if (StrIsPrefix(StrTrim(lines[i]), L"VERSION", true)) { wstring::size_type n = lines[i].find_first_of(L"="); if (n != wstring::npos) { version = StrTrim(lines[i].substr(n+1)); } } else if (StrIsPrefix(StrTrim(lines[i]), L"PATCHLEVEL", true)) { wstring::size_type n = lines[i].find_first_of(L"="); if (n != wstring::npos) { patchlevel = StrTrim(lines[i].substr(n+1)); } } } if (version.length() > 0) { m_osVersion = version; if (patchlevel.length() > 0) { m_osVersion = version.append(L".").append(patchlevel); } } if (std::wstring::npos != m_osName.find(L"Desktop")) { m_osAlias = L"SLED"; } else { // Assume server. m_osAlias = L"SLES"; } m_osManufacturer = L"SUSE GmbH"; #elif defined(PF_DISTRO_REDHAT) static const string relFileName = "/etc/redhat-release"; wifstream relfile(relFileName.c_str()); SCXStream::ReadAllLines(relfile, lines, nlfs); if (!lines.empty()) { m_osName = ExtractOSName(lines[0]); } // Set the Linux Caption (get first line of the /etc/redhat-release file) m_linuxDistroCaption = lines[0]; if (0 == m_linuxDistroCaption.length()) { // Fallback - should not normally happen m_linuxDistroCaption = L"Red Hat"; } // File should contain one line that looks like this: // Red Hat Enterprise Linux Server release 5.1 (Tikanga) if (lines.size() > 0) { wstring::size_type n = lines[0].find_first_of(L"0123456789"); if (n != wstring::npos) { wstring::size_type n2 = lines[0].substr(n).find_first_of(L" \t\n\t"); m_osVersion = StrTrim(lines[0].substr(n,n2)); } } if ((std::wstring::npos != m_osName.find(L"Client")) // RHED5 || (std::wstring::npos != m_osName.find(L"Desktop"))) // RHED4 { m_osAlias = L"RHED"; } else { // Assume server. m_osAlias = L"RHEL"; } m_osManufacturer = L"Red Hat, Inc."; #elif defined(PF_DISTRO_ULINUX) // The release file is created at agent start time by init.d startup script // This is done to insure that we can write to the appropriate directory at // the time (since, at agent run-time, we may not have root privileges). // // If we CAN create the file here (if we're running as root), then we'll // do so here. But in the normal case, this shouldn't be necessary. Only // in "weird" cases (i.e. starting omiserver by hand, for example). // Create the release file by running GetLinuxOS.sh script // (if we have root privileges) try { if ( !SCXFile::Exists(m_deps->getReleasePath()) && SCXFile::Exists(m_deps->getScriptPath()) && m_deps->isReleasePathWritable() ) { std::istringstream in; std::ostringstream out; std::ostringstream err; int ret = SCXCoreLib::SCXProcess::Run(m_deps->getScriptPath().c_str(), in, out, err, 10000); if ( ret || out.str().length() || err.str().length() ) { wostringstream sout; sout << L"Unexpected errors running script: " << m_deps->getScriptPath().c_str() << L", return code: " << ret << L", stdout: " << StrFromUTF8(out.str()) << L", stderr: " << StrFromUTF8(err.str()); SCX_LOGERROR(m_log, sout.str() ); } } } catch(SCXCoreLib::SCXInterruptedProcessException &e) { wstring msg; msg = L"Timeout running script \"" + m_deps->getScriptPath() + L"\", " + e.Where() + L'.'; SCX_LOGERROR(m_log, msg ); }; // Look in release file for O/S information string sFile = StrToUTF8(m_deps->getReleasePath()); wifstream fin(sFile.c_str()); SCXStream::ReadAllLines(fin, lines, nlfs); if (!lines.empty()) { ExtractToken(L"OSName", lines, m_osName); ExtractToken(L"OSVersion", lines, m_osVersion); ExtractToken(L"OSFullName", lines, m_linuxDistroCaption); ExtractToken(L"OSAlias", lines, m_osAlias); ExtractToken(L"OSManufacturer", lines, m_osManufacturer); } else { m_osAlias = L"Universal"; } // Behavior for m_osCompatName (method GetOSName) should be as follows: // PostInstall scripts will first look for SCX-RELEASE file (only on universal kits) // If found, add "ORIGINAL_KIT_TYPE=Universal" to scxconfig.conf file, // else add "ORIGINAL_KIT_TYPE=!Universal" to scxconfig.conf file. // After that is set up, the SCX-RELEASE file is created. // // A RHEL system should of OSAlias of "RHEL, SLES system should have "SuSE" (in scx-release) // // We need to mimic return values for RHEL and SLES on universal kits that did not // have a universal kit installed previously, but only for RHEL and SLES kits. In // all other cases, continue to return "Linux Distribution". wstring configFilename(m_deps->getConfigPath()); SCXConfigFile configFile(configFilename); try { configFile.LoadConfig(); } catch(SCXFilePathNotFoundException &e) { // Something's whacky with postinstall, so we can't follow algorithm static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eError, SCXCoreLib::eTrace); wstring logMessage(L"Unable to load configuration file " + configFilename); SCX_LOG(m_log, suppressor.GetSeverity(logMessage), logMessage); m_osCompatName = L"Unknown Linux Distribution"; } if ( m_osCompatName.empty() ) { wstring kitType; if ( configFile.GetValue(L"ORIGINAL_KIT_TYPE", kitType) ) { if ( L"!Universal" == kitType ) { if ( L"RHEL" == m_osAlias ) { m_osCompatName = L"Red Hat Distribution"; } else if ( L"SLES" == m_osAlias ) { m_osCompatName = L"SuSE Distribution"; } } } if ( m_osCompatName.empty() ) { m_osCompatName = L"Linux Distribution"; } } #else #error "Linux Platform not supported"; #endif #elif defined(macos) m_osAlias = L"MacOS"; m_osManufacturer = L"Apple Inc."; if (m_unameIsValid) { // MacOS is called "Darwin" in uname info, so we hard-code here m_osName = L"Mac OS"; // This value we could read dynamically from the xml file // /System/Library/CoreServices/SystemVersion.plist, but that // file may be named differently based on client/server, and // reading the plist file would require framework stuff. // // Rather than using the plist, we'll use Gestalt, which is an // API designed to figure out versions of anything and everything. // Note that use of Gestalt requires the use of framework stuff // as well, so the Makefiles for MacOS are modified for that. SInt32 major, minor, bugfix; if (0 != Gestalt(gestaltSystemVersionMajor, &major) || 0 != Gestalt(gestaltSystemVersionMinor, &minor) || 0 != Gestalt(gestaltSystemVersionBugFix, &bugfix)) { throw SCXCoreLib::SCXErrnoException(L"Gestalt", errno, SCXSRCLOCATION); } wostringstream sout; sout << major << L"." << minor << L"." << bugfix; m_osVersion = sout.str(); } #else #error "Platform not supported" #endif }