//===-- MIDriver.cpp --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //++ // File: MIDriver.cpp // // Overview: CMIDriver implementation. // // Environment: Compilers: Visual C++ 12. // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 // Libraries: See MIReadmetxt. // // Copyright: None. //-- // Third party headers: #include // va_list, va_start, var_end #include // In-house headers: #include "Driver.h" #include "MIDriver.h" #include "MICmnResources.h" #include "MICmnLog.h" #include "MICmdMgr.h" #include "MICmnLLDBDebugger.h" #include "MICmnMIResultRecord.h" #include "MICmnMIValueConst.h" #include "MICmnThreadMgrStd.h" #include "MIUtilDebug.h" #include "MIUtilSingletonHelper.h" #include "MICmnStreamStdout.h" #include "MICmnStreamStderr.h" // Instantiations: #if _DEBUG const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION_DEBUG ); #else const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION ); // Matches version in resources file #endif // _DEBUG const CMIUtilString CMIDriver::ms_constAppNameShort( MIRSRC( IDS_MI_APPNAME_SHORT ) ); const CMIUtilString CMIDriver::ms_constAppNameLong( MIRSRC( IDS_MI_APPNAME_LONG ) ); //++ ------------------------------------------------------------------------------------ // Details: CMIDriver constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMIDriver::CMIDriver( void ) : m_bFallThruToOtherDriverEnabled( false ) , m_bDriverIsExiting( false ) , m_handleMainThread( 0 ) , m_rStdin( CMICmnStreamStdin::Instance() ) , m_rLldbDebugger( CMICmnLLDBDebugger::Instance() ) , m_rStdOut( CMICmnStreamStdout::Instance() ) { } //++ ------------------------------------------------------------------------------------ // Details: CMIDriver destructor. // Type: Overridden. // Args: None. // Return: None. // Throws: None. //-- CMIDriver::~CMIDriver( void ) { } //++ ------------------------------------------------------------------------------------ // Details: Set whether *this driver (the parent) is enabled to pass a command to its // fall through (child) driver to interpret the command and do work instead // (if *this driver decides it can't hanled the command). // Type: Method. // Args: vbYes - (R) True = yes fall through, false = do not pass on command. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::SetEnableFallThru( const bool vbYes ) { m_bFallThruToOtherDriverEnabled = vbYes; return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Get whether *this driver (the parent) is enabled to pass a command to its // fall through (child) driver to interpret the command and do work instead // (if *this driver decides it can't hanled the command). // Type: Method. // Args: None. // Return: bool - True = yes fall through, false = do not pass on command. // Throws: None. //-- bool CMIDriver::GetEnableFallThru( void ) const { return m_bFallThruToOtherDriverEnabled; } //++ ------------------------------------------------------------------------------------ // Details: Retrieve MI's application name of itself. // Type: Method. // Args: None. // Return: CMIUtilString & - Text description. // Throws: None. //-- const CMIUtilString & CMIDriver::GetAppNameShort( void ) const { return ms_constAppNameShort; } //++ ------------------------------------------------------------------------------------ // Details: Retrieve MI's application name of itself. // Type: Method. // Args: None. // Return: CMIUtilString & - Text description. // Throws: None. //-- const CMIUtilString & CMIDriver::GetAppNameLong( void ) const { return ms_constAppNameLong; } //++ ------------------------------------------------------------------------------------ // Details: Retrieve MI's version description of itself. // Type: Method. // Args: None. // Return: CMIUtilString & - Text description. // Throws: None. //-- const CMIUtilString & CMIDriver::GetVersionDescription( void ) const { return ms_constMIVersion; } //++ ------------------------------------------------------------------------------------ // Details: Initialize setup *this driver ready for use. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::Initialize( void ) { m_clientUsageRefCnt++; ClrErrorDescription(); if( m_bInitialized ) return MIstatus::success; bool bOk = MIstatus::success; CMIUtilString errMsg; // Initialize all of the modules we depend on MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); MI::ModuleInit< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg ); MI::ModuleInit< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg ); MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); MI::ModuleInit< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg ); MI::ModuleInit< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg ); MI::ModuleInit< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg ); bOk &= m_rLldbDebugger.SetDriver( *this ); MI::ModuleInit< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg ); #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER CMIDriverMgr & rDrvMgr = CMIDriverMgr::Instance(); bOk = bOk && rDrvMgr.RegisterDriver( *g_driver, "LLDB driver" ); // Will be pass thru driver if( bOk ) { bOk = SetEnableFallThru( false ); // This is intentional at this time - yet to be fully implemented bOk = bOk && SetDriverToFallThruTo( *g_driver ); CMIUtilString strOtherDrvErrMsg; if( bOk && GetEnableFallThru() && !g_driver->MISetup( strOtherDrvErrMsg ) ) { bOk = false; errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_FALLTHRUDRIVER ), strOtherDrvErrMsg.c_str() ); } } #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER m_bExitApp = false; m_bInitialized = bOk; if( !bOk ) { const CMIUtilString msg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVER ), errMsg.c_str() ); SetErrorDescription( msg ); return MIstatus::failure; } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Unbind detach or release resources used by *this driver. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::Shutdown( void ) { if( --m_clientUsageRefCnt > 0 ) return MIstatus::success; if( !m_bInitialized ) return MIstatus::success; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Shutdown all of the modules we depend on MI::ModuleShutdown< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg ); MI::ModuleShutdown< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg ); MI::ModuleShutdown< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg ); MI::ModuleShutdown< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg ); MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); MI::ModuleShutdown< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg ); MI::ModuleShutdown< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg ); MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); if( !bOk ) { SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Work function. Client (the driver's user) is able to append their own message // in to the MI's Log trace file. // Type: Method. // Args: vMessage - (R) Client's text message. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::WriteMessageToLog( const CMIUtilString & vMessage ) { CMIUtilString msg; msg = CMIUtilString::Format( MIRSRC( IDS_MI_CLIENT_MSG ), vMessage.c_str() ); return m_pLog->Write( msg, CMICmnLog::eLogVerbosity_ClientMsg ); } //++ ------------------------------------------------------------------------------------ // Details: CDriverMgr calls *this driver initialize setup ready for use. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoInitialize( void ) { return CMIDriver::Instance().Initialize(); } //++ ------------------------------------------------------------------------------------ // Details: CDriverMgr calls *this driver to unbind detach or release resources used by // *this driver. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoShutdown( void ) { return CMIDriver::Instance().Shutdown(); } //++ ------------------------------------------------------------------------------------ // Details: Retrieve the name for *this driver. // Type: Overridden. // Args: None. // Return: CMIUtilString & - Driver name. // Throws: None. //-- const CMIUtilString & CMIDriver::GetName( void ) const { const CMIUtilString & rName = GetAppNameLong(); const CMIUtilString & rVsn = GetVersionDescription(); static CMIUtilString strName = CMIUtilString::Format( "%s %s", rName.c_str(), rVsn.c_str() ); return strName; } //++ ------------------------------------------------------------------------------------ // Details: Retrieve *this driver's last error condition. // Type: Overridden. // Args: None. // Return: CMIUtilString - Text description. // Throws: None. //-- CMIUtilString CMIDriver::GetError( void ) const { return GetErrorDescription(); } //++ ------------------------------------------------------------------------------------ // Details: Call *this driver to resize the console window. // Type: Overridden. // Args: vTermWidth - (R) New window column size. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- void CMIDriver::DoResizeWindow( const uint32_t vTermWidth ) { GetTheDebugger().SetTerminalWidth( vTermWidth ); } //++ ------------------------------------------------------------------------------------ // Details: Call *this driver to return it's debugger. // Type: Overridden. // Args: None. // Return: lldb::SBDebugger & - LLDB debugger object reference. // Throws: None. //-- lldb::SBDebugger & CMIDriver::GetTheDebugger( void ) { return m_rLldbDebugger.GetTheDebugger(); } //++ ------------------------------------------------------------------------------------ // Details: Specify another driver *this driver can call should this driver not be able // to handle the client data input. DoFallThruToAnotherDriver() makes the call. // Type: Overridden. // Args: vrOtherDriver - (R) Reference to another driver object. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver ) { m_pDriverFallThru = const_cast< CMIDriverBase * >( &vrOtherDriver ); return m_pDriverFallThru->SetDriverParent( *this ); } //++ ------------------------------------------------------------------------------------ // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this driver's // implementation called from here to match the existing function name of the // original LLDb driver class (the extra indirection is not necessarily required). // Check the arguments that were passed to this program to make sure they are // valid and to get their argument values (if any). // Type: Overridden. // Args: argc - (R) An integer that contains the count of arguments that follow in // argv. The argc parameter is always greater than or equal to 1. // argv - (R) An array of null-terminated strings representing command-line // arguments entered by the user of the program. By convention, // argv[0] is the command with which the program is invoked. // vpStdOut - (R) Pointer to a standard output stream. // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s), // version information only. // False = Continue to work, start debugger i.e. Command // interpreter. // Return: lldb::SBError - LLDB current error status. // Throws: None. //-- lldb::SBError CMIDriver::DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting ) { return ParseArgs( argc, argv, vpStdOut, vwbExiting ); } //++ ------------------------------------------------------------------------------------ // Details: Check the arguments that were passed to this program to make sure they are // valid and to get their argument values (if any). // Type: Overridden. // Args: argc - (R) An integer that contains the count of arguments that follow in // argv. The argc parameter is always greater than or equal to 1. // argv - (R) An array of null-terminated strings representing command-line // arguments entered by the user of the program. By convention, // argv[0] is the command with which the program is invoked. // vpStdOut - (R) Pointer to a standard output stream. // vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s), // version information only. // False = Continue to work, start debugger i.e. Command // interpreter. // Return: lldb::SBError - LLDB current error status. // Throws: None. //-- lldb::SBError CMIDriver::ParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting ) { lldb::SBError errStatus; // Do nothing - no options to handle for *this driver return errStatus; } //++ ------------------------------------------------------------------------------------ // Details: A client can ask if *this driver is GDB/MI compatible. // Type: Overridden. // Args: None. // Return: True - GBD/MI compatible LLDB front end. // False - Not GBD/MI compatible LLDB front end. // Throws: None. //-- bool CMIDriver::GetDriverIsGDBMICompatibleDriver( void ) const { return true; } //++ ------------------------------------------------------------------------------------ // Details: Callback function for monitoring stream stdin object. Part of the visitor // pattern. // This function is called by the CMICmnStreamStdin::CThreadStdin // "stdin monitor" thread (ID). // Type: Overridden. // Args: vStdInBuffer - (R) Copy of the current stdin line data. // vrbYesExit - (W) True = yes exit stdin monitoring, false = continue monitor. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::ReadLine( const CMIUtilString & vStdInBuffer, bool & vrbYesExit ) { // For debugging. Update prompt show stdin is working //printf( "%s\n", vStdInBuffer.c_str() ); //fflush( stdout ); // Special case look for the quit command here so stop monitoring stdin stream // So we do not go back to fgetc() and wait and hang thread on exit if( vStdInBuffer == "quit" ) vrbYesExit = true; // 1. Put new line in the queue container by stdin monitor thread // 2. Then *this driver ReadStdinLineQueuer() should when ready read the quence { CMIUtilThreadLock lock( m_threadMutex ); m_queueStdinLine.push( vStdInBuffer ); // Check to see if the *this driver is shutting down (exit application) if( !vrbYesExit ) vrbYesExit = m_bDriverIsExiting; } return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Start worker threads for the driver. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::StartWorkerThreads( void ) { bool bOk = MIstatus::success; // Grab the thread manager CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance(); // Start the stdin thread bOk &= m_rStdin.SetVisitor( *this ); if( bOk && !rThreadMgr.ThreadStart< CMICmnStreamStdin >( m_rStdin )) { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); SetErrorDescriptionn( errMsg ); return MIstatus::failure; } // Start the event polling thread if( bOk && !rThreadMgr.ThreadStart< CMICmnLLDBDebugger >( m_rLldbDebugger ) ) { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); SetErrorDescriptionn( errMsg ); return MIstatus::failure; } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Stop worker threads for the driver. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::StopWorkerThreads( void ) { CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance(); return rThreadMgr.ThreadAllTerminate(); } //++ ------------------------------------------------------------------------------------ // Details: Call this function puts *this driver to work. // This function is used by the application's main thread. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoMainLoop( void ) { if( !StartWorkerThreads() ) return MIstatus::failure; // App is not quitting currently m_bExitApp = false; // While the app is active while( !m_bExitApp ) { // Poll stdin queue and dispatch if( !ReadStdinLineQueue() ) { // Something went wrong break; } } // Signal that the application is shutting down DoAppQuit(); // Close and wait for the workers to stop StopWorkerThreads(); // Ensure that a new line is sent as the last act of the dying driver m_rStdOut.WriteMIResponse( "\n", false ); return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: *this driver sits and waits for input to the stdin line queue shared by *this // driver and the stdin monitor thread, it queues, *this reads, interprets and // reacts. // This function is used by the application's main thread. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::ReadStdinLineQueue( void ) { // True when queue contains input bool bHaveInput = false; // Stores the current input line CMIUtilString lineText; { // Lock while we access the queue CMIUtilThreadLock lock( m_threadMutex ); if( !m_queueStdinLine.empty() ) { lineText = m_queueStdinLine.front(); m_queueStdinLine.pop(); bHaveInput = !lineText.empty(); } } // Process while we have input if( bHaveInput ) { if( lineText == "quit" ) { // We want to be exiting when receiving a quit command m_bExitApp = true; return MIstatus::success; } // Process the command bool bCmdYesValid = false; bool bOk = InterpretCommand( lineText, bCmdYesValid ); if( bOk && !bCmdYesValid ) bOk = InterpretCommandFallThruDriver( lineText, bCmdYesValid ); // Draw prompt if desired if( bOk && m_rStdin.GetEnablePrompt() ) m_rStdOut.WriteMIResponse( m_rStdin.GetPrompt() ); // Input has been processed bHaveInput = false; } else { // Give resources back to the OS const std::chrono::milliseconds time( 1 ); std::this_thread::sleep_for( time ); } return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Set things in motion, set state etc that brings *this driver (and the // application) to a tidy shutdown. // This function is used by the application's main thread. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoAppQuit( void ) { bool bYesQuit = true; // Shutdown stuff, ready app for exit { CMIUtilThreadLock lock( m_threadMutex ); m_bDriverIsExiting = true; } return bYesQuit; } //++ ------------------------------------------------------------------------------------ // Details: *this driver passes text commands to a fall through driver is it does not // understand them (the LLDB driver). // This function is used by the application's main thread. // Type: Method. // Args: vTextLine - (R) Text data representing a possible command. // vwbCmdYesValid - (W) True = Command valid, false = command not handled. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::InterpretCommandFallThruDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid ) { MIunused( vTextLine ); MIunused( vwbCmdYesValid ); // ToDo: Implement when less urgent work to be done //bool bOk = MIstatus::success; //bool bCmdNotUnderstood = true; //if( bCmdNotUnderstood && GetEnableFallThru() ) //{ // CMIUtilString errMsg; // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg ); // if( !bOk ) // { // errMsg = errMsg.StripCREndOfLine(); // errMsg = errMsg.StripCRAll(); // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo(); // const MIchar * pName = pOtherDriver->GetDriverName().c_str(); // const MIchar * pId = pOtherDriver->GetDriverId().c_str(); // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() ) ); // m_pLog->WriteMsg( msg ); // } //} // //vwbCmdYesValid = bOk; //CMIUtilString strNot; //if( vwbCmdYesValid) // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ); //const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) ); //m_pLog->WriteLog( msg ); return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Retrieve the name for *this driver. // Type: Overridden. // Args: None. // Return: CMIUtilString & - Driver name. // Throws: None. //-- const CMIUtilString & CMIDriver::GetDriverName( void ) const { return GetName(); } //++ ------------------------------------------------------------------------------------ // Details: Get the unique ID for *this driver. // Type: Overridden. // Args: None. // Return: CMIUtilString & - Text description. // Throws: None. //-- const CMIUtilString & CMIDriver::GetDriverId( void ) const { return GetId(); } //++ ------------------------------------------------------------------------------------ // Details: This function allows *this driver to call on another driver to perform work // should this driver not be able to handle the client data input. // SetDriverToFallThruTo() specifies the fall through to driver. // Check the error message if the function returns a failure. // Type: Overridden. // Args: vCmd - (R) Command instruction to interpret. // vwErrMsg - (W) Error description on command failing. // Return: MIstatus::success - Command succeeded. // MIstatus::failure - Command failed. // Throws: None. //-- bool CMIDriver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg ) { bool bOk = MIstatus::success; CMIDriverBase * pOtherDriver = GetDriverToFallThruTo(); if( pOtherDriver == nullptr ) return bOk; return pOtherDriver->DoFallThruToAnotherDriver( vCmd, vwErrMsg ); } //++ ------------------------------------------------------------------------------------ // Details: *this driver provides a file stream to other drivers on which *this driver // write's out to and they read as expected input. *this driver is passing // through commands to the (child) pass through assigned driver. // Type: Overrdidden. // Args: None. // Return: FILE * - Pointer to stream. // Throws: None. //-- FILE * CMIDriver::GetStdin( void ) const { // Note this fn is called on CMIDriverMgr register driver so stream has to be // available before *this driver has been initialized! Flaw? // This very likely to change later to a stream that the pass thru driver // will read and we write to give it 'input' return stdin; } //++ ------------------------------------------------------------------------------------ // Details: *this driver provides a file stream to other pass through assigned drivers // so they know what to write to. // Type: Overidden. // Args: None. // Return: FILE * - Pointer to stream. // Throws: None. //-- FILE * CMIDriver::GetStdout( void ) const { // Note this fn is called on CMIDriverMgr register driver so stream has to be // available before *this driver has been initialized! Flaw? // Do not want to pass through driver to write to stdout return NULL; } //++ ------------------------------------------------------------------------------------ // Details: *this driver provides a error file stream to other pass through assigned drivers // so they know what to write to. // Type: Overidden. // Args: None. // Return: FILE * - Pointer to stream. // Throws: None. //-- FILE * CMIDriver::GetStderr( void ) const { // Note this fn is called on CMIDriverMgr register driver so stream has to be // available before *this driver has been initialized! Flaw? // This very likely to change later to a stream that the pass thru driver // will write to and *this driver reads from to pass on the the CMICmnLog object return stderr; } //++ ------------------------------------------------------------------------------------ // Details: Set a unique ID for *this driver. It cannot be empty. // Type: Overridden. // Args: vId - (R) Text description. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::SetId( const CMIUtilString & vId ) { if( vId.empty() ) { SetErrorDescriptionn( MIRSRC( IDS_DRIVER_ERR_ID_INVALID ), GetName().c_str(), vId.c_str() ); return MIstatus::failure; } m_strDriverId = vId; return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Get the unique ID for *this driver. // Type: Overridden. // Args: None. // Return: CMIUtilString & - Text description. // Throws: None. //-- const CMIUtilString & CMIDriver::GetId( void ) const { return m_strDriverId; } //++ ------------------------------------------------------------------------------------ // Details: Interpret the text data and match against current commands to see if there // is a match. If a match then the command is issued and actioned on. If a // command cannot be found to match then vwbCmdYesValid is set to false and // nothing else is done here. // This function is used by the application's main thread. // Type: Method. // Args: vTextLine - (R) Text data representing a possible command. // vwbCmdYesValid - (W) True = Command invalid, false = command acted on. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::InterpretCommand( const CMIUtilString & vTextLine, bool & vwbCmdYesValid ) { vwbCmdYesValid = false; bool bCmdNotInCmdFactor = false; SMICmdData cmdData; CMICmdMgr & rCmdMgr = CMICmdMgr::Instance(); if( !rCmdMgr.CmdInterpret( vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData ) ) return MIstatus::failure; if( vwbCmdYesValid ) { // For debugging only //m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() ); return ExecuteCommand( cmdData ); } // Write to the Log that a 'command' was not valid. // Report back to the MI client via MI result record. CMIUtilString strNotInCmdFactory; if( bCmdNotInCmdFactor ) strNotInCmdFactory = CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_NOT_IN_FACTORY ), cmdData.strMiCmd.c_str() ); const CMIUtilString strNot( CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ) ); const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str() ) ); const CMICmnMIValueConst vconst = CMICmnMIValueConst( msg ); const CMICmnMIValueResult valueResult( "msg", vconst ); const CMICmnMIResultRecord miResultRecord( cmdData.nMiCmdNumber, CMICmnMIResultRecord::eResultClass_Error, valueResult ); m_rStdOut.WriteMIResponse( miResultRecord.GetString() ); // Proceed to wait for or execute next command return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Having previously had the potential command validated and found valid now // get the command executed. // This function is used by the application's main thread. // Type: Method. // Args: vCmdData - (RW) Command meta data. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::ExecuteCommand( const SMICmdData & vCmdData ) { CMICmdMgr & rCmdMgr = CMICmdMgr::Instance(); return rCmdMgr.CmdExecute( vCmdData ); } //++ ------------------------------------------------------------------------------------ // Details: Set the exit application flag. The application checks this flag after every // stdin line is read so the exit may not be instantious. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- void CMIDriver::SetExitApplicationFlag( void ) { CMIUtilThreadLock lock( m_threadMutex ); m_bExitApp = true; }