//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : CmdParser.cpp Data : 01.09.14 Versione : 1.5i1 // Contenuto : Implementazione della classe CmdParser. // // // // Modifiche : 19.01.13 DS Creazione modulo. // 10.05.14 DS Modif. per DirReplace. // 01.09.14 DS Il distruttore cancella gli esecutori installati. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CmdParser.h" #include "DllMain.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGnFileUtils.h" #include "/EgtDev/Include/EGnFileCompare.h" #include "/EgtDev/Include/EGnCmdExecutor.h" #include "/EgtDev/Include/EgtILogger.h" #include using namespace std ; //---------------------------------------------------------------------------- ICmdParser* CreateCmdParser( void) { return static_cast ( new CmdParser) ; } //---------------------------------------------------------------------------- CmdParser::CmdParser( void) { m_nLev = 0 ; // assegno chiavi a funzioni di esecuzione m_ExecMgr.Init( 16) ; m_ExecMgr.Insert( "ASSERT", &CmdParser::ExecuteAssert) ; m_ExecMgr.Insert( "COUNTER", &CmdParser::ExecuteCounter) ; m_ExecMgr.Insert( "DIR", &CmdParser::ExecuteDir) ; m_ExecMgr.Insert( "DIRREPLACE", &CmdParser::ExecuteDirReplace) ; m_ExecMgr.Insert( "EXEC", &CmdParser::ExecuteExec) ; m_ExecMgr.Insert( "FILE", &CmdParser::ExecuteFile) ; m_ExecMgr.Insert( "OUTLOG", &CmdParser::ExecuteOutLog) ; m_ExecMgr.Insert( "PAUSE", &CmdParser::ExecutePause) ; m_ExecMgr.Insert( "RESET", &CmdParser::ExecuteReset) ; m_ExecMgr.Insert( "RUN", &CmdParser::ExecuteRun) ; m_ExecMgr.Insert( "SET", &CmdParser::ExecuteSet) ; } //---------------------------------------------------------------------------- CmdParser::~CmdParser( void) { // pulisco lista esecutori PCmdExecList::iterator IterCEL ; for ( IterCEL = m_CmdExecList.begin() ; IterCEL != m_CmdExecList.end() ; ++ IterCEL) { if ( (*IterCEL) != nullptr) delete (*IterCEL) ; } m_CmdExecList.clear() ; } //---------------------------------------------------------------------------- bool CmdParser::SetExecutor( ICmdExecutor* pCmdExec) { // pulisco lista esecutori PCmdExecList::iterator IterCEL ; for ( IterCEL = m_CmdExecList.begin() ; IterCEL != m_CmdExecList.end() ; ++ IterCEL) { if ( (*IterCEL) != nullptr) delete (*IterCEL) ; } m_CmdExecList.clear() ; // verifico la validità dell'esecutore if ( pCmdExec == nullptr) return false ; // salvo il riferimento all'esecutore e mi registro try { m_CmdExecList.push_back( pCmdExec) ; } catch(...) { return false ; } pCmdExec->SetCmdParser( this) ; return true ; } //---------------------------------------------------------------------------- bool CmdParser::AddExecutor( ICmdExecutor* pCmdExec) { // verifico la validità dell'esecutore if ( pCmdExec == nullptr) return false ; // salvo il riferimento all'esecutore e mi registro try { m_CmdExecList.push_back( pCmdExec) ; } catch(...) { return false ; } pCmdExec->SetCmdParser( this) ; return true ; } //---------------------------------------------------------------------------- bool CmdParser::Init( void) { // reimposto le variabili ResetAllVariables() ; // imposto il livello di esecuzione iniziale m_nLev = 0 ; return true ; } //---------------------------------------------------------------------------- bool CmdParser::Run( const string& sCmdFile, bool bIsolated) { // se richiesta esecuzione isolata, faccio una copia dello stato delle variabili NameMap CurrNameMap ; if ( bIsolated) CurrNameMap = m_NameMap ; // log di inizio file string sOut = GetInitSpaces() + "--- Start : " + sCmdFile + " ---" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) // inizializzo lo scanner CmdScanner TheScanner ; bool bOk = TheScanner.Init( sCmdFile) ; if ( ! bOk) { sOut = GetInitSpaces() + "Error opening command file" ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) } // interpretazione dei comandi del file m_nCurrLine = 0 ; m_nExec = DO ; m_nAssertNextError = 0 ; string sLine ; while ( bOk && m_nExec != STOP && TheScanner.GetLine( sLine)) { // assegno numero linea corrente m_nCurrLine = TheScanner.GetCurrLineNbr() ; // elimino gli spazi all'inizio e alla fine Trim( sLine) ; // separo comando e parametri string sCmd, sParams ; SplitFirst( sLine, "(", sCmd, sParams) ; ToUpper( sCmd) ; // elimino dai parametri tutto quanto dopo ultima parentesi chiusa string sDummy ; SplitLast( sParams, ")", sParams, sDummy) ; // se da saltare e non è comando che fa riprendere esecuzione, vado al prossimo if ( m_nExec == SKIP && sCmd != "EXEC.DO") continue ; // deve esserci un comando e deve essere eseguito correttamente if ( ! sCmd.empty() && ExecCommand( sCmd, sParams)) { if ( m_nAssertNextError == 1) { bOk = false ; sOut = GetInitSpaces() + "Expected error not found on line (" + ToString( m_nCurrLine) + ") : " + sLine ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) } } else { if ( m_nAssertNextError != 1) bOk = false ; sOut = GetInitSpaces() + "Error on line (" + ToString( m_nCurrLine) + ") : " + sLine ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) } // reset flag atteso errore su prossima istruzione if ( m_nAssertNextError > 0) -- m_nAssertNextError ; } // log di fine file if ( bOk) { sOut = GetInitSpaces() + "--- End ---" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) } else { sOut = GetInitSpaces() + "--- Stop : error ---" ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) } // se richiesta esecuzione isolata, ripristino lo stato originale delle variabili if ( bIsolated) m_NameMap = CurrNameMap ; return bOk ; } //---------------------------------------------------------------------------- bool CmdParser::ExecLine( const string& sCmdLine, bool bIsolated) { // se richiesta esecuzione isolata, faccio una copia dello stato delle variabili NameMap CurrNameMap ; if ( bIsolated) CurrNameMap = m_NameMap ; // elimino gli spazi all'inizio e alla fine string sLine = sCmdLine ; Trim( sLine) ; // separo comando e parametri string sCmd, sParams ; SplitFirst( sLine, "(", sCmd, sParams) ; ToUpper( sCmd) ; // elimino dai parametri tutto quanto dopo ultima parentesi chiusa string sDummy ; SplitLast( sParams, ")", sParams, sDummy) ; // deve esserci un comando e deve essere eseguito correttamente bool bOk = true ; if ( sCmd.empty() || ! ExecCommand( sCmd, sParams)) { bOk = false ; string sOut = GetInitSpaces() + "Error on line : " + sCmdLine ; LOG_ERROR( GetEGnLogger(), sOut.c_str()) } // se richiesta esecuzione isolata, ripristino lo stato originale delle variabili if ( bIsolated) m_NameMap = CurrNameMap ; return bOk ; } //---------------------------------------------------------------------------- bool CmdParser::AddVariable( const string& sName, int nVal) { return ( m_NameMap.insert( NameMap::value_type( sName, nVal)).second) ; } //---------------------------------------------------------------------------- bool CmdParser::SetVariable( const string& sName, int nVal) { NameMap::iterator Iter ; Iter = m_NameMap.find( sName) ; if ( Iter != m_NameMap.end()) { Iter->second = nVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::GetVariable( const string& sName, int& nVal) { NameMap::const_iterator Iter ; Iter = m_NameMap.find( sName) ; if ( Iter != m_NameMap.end()) { nVal = Iter->second ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::RemoveVariable( const string& sName) { return ( m_NameMap.erase( sName) > 0) ; } //---------------------------------------------------------------------------- bool CmdParser::ResetAllVariables( void) { // pulisco e imposto dimensioni mappa dei nomi di variabili m_NameMap.clear() ; m_NameMap.rehash( 100) ; // installo variabili standard PCmdExecList::iterator Iter ; for ( Iter = m_CmdExecList.begin() ; Iter != m_CmdExecList.end() ; ++ Iter) { if ( (*Iter) == nullptr || ! (*Iter)->AddStandardVariables()) return false ; } return true ; } //---------------------------------------------------------------------------- void CmdParser::ResetDirReplace( void) { m_DirReplace.clear() ; } //---------------------------------------------------------------------------- bool CmdParser::SetDirReplace( const string& sToken, const string& sReplace) { // se il token è già presente, ne aggiorno la stringa di replace for ( size_t i = 0 ; i < m_DirReplace.size() ; ++i) { if ( m_DirReplace[i].first == sToken) { m_DirReplace[i].second = sReplace ; return true ; } } // altrimenti lo aggiungo in coda try { m_DirReplace.push_back( make_pair( sToken, sReplace)) ; } catch (...) { return false ; } return true ; } //---------------------------------------------------------------------------- int CmdParser::DirReplace( string& sPath) { int nRep = 0 ; for ( size_t i = 0 ; i < m_DirReplace.size() ; ++i) nRep += ReplaceString( sPath, m_DirReplace[i].first, m_DirReplace[i].second) ; return nRep ; } //---------------------------------------------------------------------------- int CmdParser::DirInvReplace( string& sPath) { int nRep = 0 ; for ( size_t i = 0 ; i < m_DirReplace.size() ; ++i) nRep += ReplaceString( sPath, m_DirReplace[i].second, m_DirReplace[i].first) ; return nRep ; } //---------------------------------------------------------------------------- int CmdParser::GetIdParam( const string& sParam, bool bNewAllowed) { int nVal ; // se nome di identificatore numerico if ( sParam[0] == '$') { // se variabile già definita, ne restituisco il valore if ( GetVariable( sParam, nVal)) return nVal ; // se ammessa nuova definizione, provo ad inserirlo else if ( bNewAllowed && AddVariable( sParam, CMD_ID_NULL)) return CMD_ID_NULL ; // altrimenti errore else return CMD_ID_ERROR ; } // se identificatore numerico else if ( FromString( sParam, nVal)) return nVal ; // altrimenti errore else return CMD_ID_ERROR ; } //---------------------------------------------------------------------------- bool CmdParser::GetStringParam( const string& sParam, string& sString) { if ( sParam.empty()) return false ; sString = sParam ; if ( sString[0] == '(') sString.erase( 0, 1) ; if ( ! sString.empty() && sString.back() == ')') sString.pop_back() ; return true ; } //---------------------------------------------------------------------------- string CmdParser::GetInitSpaces( void) { string sIni ; for ( int i = 0 ; i < m_nLev ; ++ i) sIni += " " ; return sIni ; } //---------------------------------------------------------------------------- bool CmdParser::ExecCommand( const string& sCmd, const string& sParams) { // divido il comando e lo normalizzo string sCmd1, sCmd2 ; SplitFirst( sCmd, ".", sCmd1, sCmd2) ; Trim( sCmd1) ; Trim( sCmd2) ; // divido i parametri STRVECTOR vsParams ; Tokenize( sParams, ",", "(", ")", vsParams) ; STRVECTOR::iterator Iter ; for ( Iter = vsParams.begin() ; Iter != vsParams.end() ; ++ Iter) Trim( (*Iter)) ; // output di debug string sOut = GetInitSpaces() + sCmd1 ; if ( ! sCmd2.empty()) sOut += "." + sCmd2 ; sOut += "( " ; for ( Iter = vsParams.begin() ; Iter != vsParams.end() ; ++ Iter) { if ( Iter != vsParams.begin()) sOut += ", " ; sOut += *Iter ; } sOut += ")" ; LOG_DBG_INFO( GetEGnLogger(), sOut.c_str()) // eseguo il comando cercando nell'esecutore di comandi locale int nRes = m_ExecMgr.Execute( *this, sCmd1, sCmd2, vsParams) ; if ( nRes != ER_MISSING) return ( nRes == ER_OK) ; // eseguo il comando cercando negli esecutori di comandi installati PCmdExecList::iterator IterCEL ; for ( IterCEL = m_CmdExecList.begin() ; IterCEL != m_CmdExecList.end() ; ++ IterCEL) { if ( (*IterCEL) == nullptr) return false ; nRes = (*IterCEL)->Execute( sCmd1, sCmd2, vsParams) ; if ( nRes != ER_MISSING) return ( nRes == ER_OK) ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteAssert( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2 == "NEXTERROR") { // nessun parametro if ( vsParams.size() != 0) return false ; // imposto il flag di assert errore in prossima istruzione m_nAssertNextError = 2 ; // emetto log string sOut = GetInitSpaces() + "Assert error on next line (" + ToString( m_nCurrLine) + ")" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteCounter( const string& sCmd2, const STRVECTOR& vsParams) { // avvio il counter if ( sCmd2 == "START") { m_Counter.Start() ; return true ; } // fermo il counter ed emetto i risultati else if ( sCmd2 == "STOP") { m_Counter.Stop() ; string sOut = GetInitSpaces() + ( ( vsParams.size() >= 1) ? vsParams[0] : "ExecTime =") ; sOut += " " + ToString( m_Counter.GetTime(), 2) + " ms" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteDir( const string& sCmd2, const STRVECTOR& vsParams) { // analisi ed esecuzione dei comandi if ( sCmd2 == "EMPTY") { // 1 parametro : nome direttorio da svuotare if ( vsParams.size() != 1) return false ; // eventuale conversione di token nel nome direttorio string sDir = vsParams[0] ; DirReplace( sDir) ; // svuoto il direttorio EmptyDirectory( sDir) ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteDirReplace( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2 == "SET") { // 2 parametri : sToken, sReplace if ( vsParams.size() != 2) return false ; // eseguo return SetDirReplace( vsParams[0], vsParams[1]) ; } else if ( sCmd2 == "RESET") { // 0 parametri if ( vsParams.size() != 0) return false ; // eseguo ResetDirReplace() ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteExec( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2 == "SKIP") { // nessun parametro if ( vsParams.size() != 0) return false ; // imposto il flag di esecuzione m_nExec = SKIP ; // emetto log string sOut = GetInitSpaces() + "Skip on line (" + ToString( m_nCurrLine) + ")" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } else if ( sCmd2 == "DO") { // nessun parametro if ( vsParams.size() != 0) return false ; // imposto il flag di stop m_nExec = DO ; // emetto log string sOut = GetInitSpaces() + "Do on line (" + ToString( m_nCurrLine) + ")" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } else if ( sCmd2 == "STOP") { // nessun parametro if ( vsParams.size() != 0) return false ; // imposto il flag di stop m_nExec = STOP ; // emetto log string sOut = GetInitSpaces() + "Stop on line (" + ToString( m_nCurrLine) + ")" ; LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteFile( const string& sCmd2, const STRVECTOR& vsParams) { // cancellazione file if ( sCmd2 == "DEL") { // 1 parametro : file if ( vsParams.size() != 1) return false ; // eventuale conversione di token nel nome file string sFile = vsParams[0] ; DirReplace( sFile) ; // eseguo la cancellazione EraseFile( sFile) ; return true ; } // confronto tra file di testo else if ( sCmd2 == "CMP") { // 4 parametri : file1, file2, inizio commento, file diff if ( vsParams.size() != 4) return false ; // eventuale conversione di token nei nomi file string sFile1 = vsParams[0] ; DirReplace( sFile1) ; string sFile2 = vsParams[1] ; DirReplace( sFile2) ; string sFileDiff = vsParams[3] ; DirReplace( sFileDiff) ; // eseguo il confronto int nDiff ; TextFileCompare( sFile1, sFile2, vsParams[2], sFileDiff, nDiff) ; return true ; } // confronto tra file binari else if ( sCmd2 == "BINCMP") { // 3 parametri : file1, file2, file diff if ( vsParams.size() != 3) return false ; // eventuale conversione di token nei nomi file string sFile1 = vsParams[0] ; DirReplace( sFile1) ; string sFile2 = vsParams[1] ; DirReplace( sFile2) ; string sFileDiff = vsParams[2] ; DirReplace( sFileDiff) ; // eseguo il confronto int nDiff ; BinaryFileCompare( sFile1, sFile2, sFileDiff, nDiff) ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteOutLog( const string& sCmd2, const STRVECTOR& vsParams) { // 1 parametro : messaggio da mettere nel log if ( vsParams.size() != 1) return false ; // recupero messaggio string sMsg ; if ( ! GetStringParam( vsParams[0], sMsg)) return false ; string sOut = GetInitSpaces() + sMsg ; // emissione messaggio LOG_INFO( GetEGnLogger(), sOut.c_str()) return true ; } //---------------------------------------------------------------------------- bool CmdParser::ExecutePause( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2.empty()) { const int MIN_TIME = 0 ; const int MAX_TIME = 10000 ; // 1 parametro : durata della pausa in ms if ( vsParams.size() != 1) return false ; // tempo di attesa int nTime ; if ( ! FromString( vsParams[0], nTime)) return false ; if ( nTime < MIN_TIME) nTime = MIN_TIME ; else if ( nTime > MAX_TIME) nTime = MAX_TIME ; // eseguo Sleep( nTime) ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteReset( const string& sCmd2, const STRVECTOR& vsParams) { // ripristino dell'ambiente di esecuzione if ( sCmd2 == "ALL") { return ResetAllVariables() ; } // cancellazione di un identificativo else if ( sCmd2.empty()) { // 1 parametro ( Nome/i) if ( vsParams.size() != 1) return false ; // recupero lista nomi STRVECTOR vsNames ; if ( ! GetNamesParam( vsParams[0], vsNames)) return false ; // eseguo cancellazioni STRVECTOR::iterator Iter ; for ( Iter = vsNames.begin() ; Iter != vsNames.end() ; ++Iter) RemoveVariable( *Iter) ; return true ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteRun( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2.empty()) { // almeno 1 parametro : nome file di script da eseguire if ( vsParams.size() < 1) return false ; // eventuale conversione di token nel nome file string sFile = vsParams[0] ; DirReplace( sFile) ; // se esiste 2° parametro è flag di ignora errori bool bSkipErrors = false ; if ( vsParams.size() >= 2) FromString( vsParams[1], bSkipErrors) ; // controllo massimo numero di annidamenti if ( m_nLev >= 5) return false ; // esecuzione comando ++ m_nLev ; bool bOk = Run( sFile) ; -- m_nLev ; return ( bOk || bSkipErrors) ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::ExecuteSet( const string& sCmd2, const STRVECTOR& vsParams) { if ( sCmd2.empty()) { // 2 parametri ( Nome, Valore) if ( vsParams.size() != 2) return false ; // recupero il valore int nVal ; if ( ! FromString( vsParams[1], nVal)) return false ; // eseguo if ( SetVariable( vsParams[0], nVal)) return true ; else return AddVariable( vsParams[0], nVal) ; } return false ; } //---------------------------------------------------------------------------- bool CmdParser::GetNamesParam( const string& sParam, STRVECTOR& vsNames) { STRVECTOR::iterator Iter ; // divido in parti Tokenize( sParam, ",", vsNames) ; for ( Iter = vsNames.begin() ; Iter != vsNames.end() ; ++Iter) Trim( (*Iter), " \t\r\n()") ; return true ; }