]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/lldb-mi/MIDriverMgr.cpp
Import LLDB as of upstream SVN r216948 (git 50f7fe44)
[FreeBSD/FreeBSD.git] / tools / lldb-mi / MIDriverMgr.cpp
1 //===-- MIDriverMgr.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 //++
11 // File:                MIDriverMgr.cpp
12 //
13 // Overview:    CMIDriverMgr implementation.
14 //
15 // Environment: Compilers:      Visual C++ 12.
16 //                                                      gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
17 //                              Libraries:      See MIReadmetxt. 
18 //
19 // Copyright:   None.
20 //--
21
22 // Third Party Headers:
23 #include <lldb/API/SBError.h>
24
25 // In-house headers:
26 #include "MIDriverMgr.h"
27 #include "MICmnResources.h"
28 #include "MICmnLog.h"
29 #include "MICmnLogMediumFile.h"
30 #include "MIDriver.h"
31 #include "MIUtilTermios.h"
32 #include "MICmnStreamStdout.h"
33 #include "MIUtilSingletonHelper.h"
34
35 //++ ------------------------------------------------------------------------------------
36 // Details:     CMIDriverMgr constructor.
37 // Type:        Method.
38 // Args:        None.
39 // Return:      None.
40 // Throws:      None.
41 //--
42 CMIDriverMgr::CMIDriverMgr( void )
43 :       m_pDriverCurrent( nullptr )
44 ,       m_bInMi2Mode( false )
45 {
46 }
47
48 //++ ------------------------------------------------------------------------------------
49 // Details:     CMIDriverMgr destructor.
50 // Type:        Overridden.
51 // Args:        None.
52 // Return:      None.
53 // Throws:      None.
54 //--
55 CMIDriverMgr::~CMIDriverMgr( void )
56 {
57         Shutdown();
58 }
59
60 //++ ------------------------------------------------------------------------------------
61 // Details:     Initialize *this manager.
62 // Type:        Method.
63 // Args:        None.
64 // Return:      MIstatus::success - Functional succeeded.
65 //                      MIstatus::failure - Functional failed.
66 // Throws:      None.
67 //--
68 bool CMIDriverMgr::Initialize( void )
69 {
70         m_clientUsageRefCnt++;
71
72         ClrErrorDescription();
73
74         if( m_bInitialized )
75                 return MIstatus::success;
76
77         bool bOk = MIstatus::success;
78         CMIUtilString errMsg;
79  
80         // Note initialisation order is important here as some resources depend on previous
81         MI::ModuleInit< CMICmnLog >      ( IDS_MI_INIT_ERR_LOG      , bOk, errMsg );
82         MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
83
84         if( bOk )
85         {
86                 MIUtilTermios::StdinTermiosSet();
87         }
88         
89         m_bInitialized = bOk;
90         
91         if( !bOk )
92         {
93                 CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVERMGR ), errMsg.c_str() ) );
94                 SetErrorDescription( strInitError );
95                 return MIstatus::failure;
96         }
97
98         return bOk;
99 }
100
101 //++ ------------------------------------------------------------------------------------
102 // Details:     Unbind detach or release resources used by this server in general common 
103 //                      functionality shared between versions of any server interfaces implemented.
104 // Type:        Method.
105 // Args:        vbAppExitOk     - (R) True = No problems, false = App exiting with problems (investigate!).     
106 // Return:      MIstatus::success - Functional succeeded.
107 //                      MIstatus::failure - Functional failed.
108 // Throws:      None.
109 //--
110 bool CMIDriverMgr::Shutdown( void )
111 {
112         // Do not want a ref counter because this function needs to be called how ever this 
113         // application stops running
114         //if( --m_clientUsageRefCnt > 0 )
115         //      return MIstatus::success;
116         
117         bool vbAppExitOk = true;
118
119         ClrErrorDescription();
120
121         if( !m_bInitialized )
122                 return MIstatus::success;
123
124         if( vbAppExitOk )       
125         {
126                 // The MI Driver's log updating may have been switched off switch back on to say all is ok. 
127                 CMICmnLog::Instance().SetEnabled( true );
128 #if _DEBUG
129                 CMICmnStreamStdout::Instance().Write( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Both stdout and Log
130 #else
131                 CMICmnLog::WriteLog( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Just to the Log
132 #endif // _DEBUG
133         }
134         else
135         {
136                 CMICmnLog & rAppLog = CMICmnLog::Instance();
137                 if( rAppLog.GetEnabled()  )
138                 {
139                         const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) );
140                         CMICmnStreamStdout::Instance().Write( msg );
141                 }
142                 else
143                 {
144                         // The MI Driver's log updating may have been switched off switch back on to say there has been problem. 
145                         rAppLog.SetEnabled( true );
146                         const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM_NO_LOG ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) );
147                         CMICmnStreamStdout::Instance().Write( msg );
148                 }
149         }
150         
151         m_bInitialized = false;
152
153         bool bOk = MIstatus::success;
154         CMIUtilString errMsg;
155
156         // Tidy up
157         UnregisterDriverAll();
158         MIUtilTermios::StdinTermiosReset();
159  
160         // Note shutdown order is important here 
161         MI::ModuleShutdown< CMICmnResources >( IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg );
162         MI::ModuleShutdown< CMICmnLog >      ( IDS_MI_SHTDWN_ERR_LOG      , bOk, errMsg );
163
164         if( !bOk )
165         {
166                 SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_DRIVERMGR ), errMsg.c_str() );
167         }
168
169         return bOk;
170 }
171 //++ ------------------------------------------------------------------------------------
172 // Details:     Unregister all the Driver registered with *this manager. The manager also
173 //                      deletes
174 // Type:        Method.
175 // Args:        None.
176 // Return:      MIstatus::success - Functional succeeded.
177 //                      MIstatus::failure - Functional failed.
178 // Throws:      None.
179 //--
180 bool CMIDriverMgr::UnregisterDriverAll( void )
181 {
182         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
183         while( it != m_mapDriverIdToDriver.end() )
184         {
185                 IDriver * pDriver = (*it).second;
186                 pDriver->DoShutdown();
187                 
188                 // Next
189                 ++it;
190         }
191
192         m_mapDriverIdToDriver.clear();
193         m_pDriverCurrent = NULL;
194
195         return MIstatus::success;
196 }
197
198 //++ ------------------------------------------------------------------------------------
199 // Details:     Register a driver with *this Driver Manager. Call SetUseThisDriverToDoWork()
200 //                      inform the manager which driver is the one to the work. The manager calls
201 //                      the driver's init function which must be successful in order to complete the
202 //                      registration.
203 // Type:        Method.
204 // Args:        vrDriver        - (R) The driver to register.
205 //                      vrDriverID      - (R) The driver's ID to lookup by.
206 // Return:      MIstatus::success - Functional succeeded.
207 //                      MIstatus::failure - Functional failed.
208 // Throws:      None.
209 //--
210 bool CMIDriverMgr::RegisterDriver( const IDriver & vrDriver, const CMIUtilString & vrDriverID )
211 {
212         if( HaveDriverAlready( vrDriver ) )
213                 return MIstatus::success;
214
215         IDriver * pDriver = const_cast< IDriver * >( &vrDriver );
216         if( !pDriver->SetId( vrDriverID ) )
217                 return MIstatus::failure;
218         if( !pDriver->DoInitialize() )
219         {
220                 SetErrorDescriptionn( MIRSRC( IDS_DRIVERMGR_DRIVER_ERR_INIT ), pDriver->GetName().c_str(), vrDriverID.c_str(), pDriver->GetError().c_str() );
221                 return MIstatus::failure;
222         }
223
224         MapPairDriverIdToDriver_t pr( vrDriverID, pDriver );
225         m_mapDriverIdToDriver.insert( pr );
226
227         return MIstatus::success;
228 }
229
230 //++ ------------------------------------------------------------------------------------
231 // Details:     Query the Driver Manager to see if *this manager has the driver already 
232 //                      registered.
233 // Type:        Method.
234 // Args:        vrDriver        - (R) The driver to query.
235 // Return:      True - registered.
236 //                      False - not registered.
237 // Throws:      None.
238 //--
239 bool CMIDriverMgr::HaveDriverAlready( const IDriver & vrDriver ) const
240 {
241         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
242         while( it != m_mapDriverIdToDriver.end() )
243         {
244                 const IDriver * pDrvr = (*it).second;
245                 if( pDrvr == &vrDriver )
246                         return true;
247
248                 // Next
249                 ++it;
250         }
251
252         return false;
253 }
254
255 //++ ------------------------------------------------------------------------------------
256 // Details:     Unregister a driver from the Driver Manager. Call the SetUseThisDriverToDoWork()
257 //                      function to define another driver to do work if the one being unregistered did
258 //                      the work previously.
259 // Type:        Method.
260 // Args:        vrDriver        - (R) The driver to unregister.
261 // Return:      MIstatus::success - Functional succeeded.
262 //                      MIstatus::failure - Functional failed.
263 // Throws:      None.
264 //--
265 bool CMIDriverMgr::UnregisterDriver( const IDriver & vrDriver )
266 {
267         const IDriver * pDrvr = nullptr;
268         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
269         while( it != m_mapDriverIdToDriver.end() )
270         {
271                 pDrvr = (*it).second;
272                 if( pDrvr == &vrDriver )
273                         break;
274
275                 // Next
276                 ++it;
277         }
278         m_mapDriverIdToDriver.erase( it );
279
280         if( m_pDriverCurrent == pDrvr )
281                 m_pDriverCurrent = nullptr;
282
283         return MIstatus::success;
284 }
285
286 //++ ------------------------------------------------------------------------------------
287 // Details:     Specify the driver to do work. The Driver Manager drives this driver. Any
288 //                      previous driver doing work is not called anymore (so be sure the previous
289 //                      driver is in a tidy state before stopping it working).
290 // Type:        Method.
291 // Args:        vrADriver       - (R) A lldb::SBBroadcaster/IDriver derived object.
292 // Return:      MIstatus::success - Functional succeeded.
293 //                      MIstatus::failure - Functional failed.
294 // Throws:      None.
295 //--
296 bool CMIDriverMgr::SetUseThisDriverToDoWork( const IDriver & vrADriver )
297 {
298         m_pDriverCurrent = const_cast< IDriver * >( &vrADriver );
299
300         const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_SAY_DRIVER_USING ), m_pDriverCurrent->GetName().c_str() ) );
301         m_pLog->Write( msg, CMICmnLog::eLogVerbosity_Log );
302
303         m_bInMi2Mode = m_pDriverCurrent->GetDriverIsGDBMICompatibleDriver();
304
305         return MIstatus::success;
306 }
307
308 //++ ------------------------------------------------------------------------------------
309 // Details:     Ask *this manager which driver is currently doing the work. 
310 // Type:        Method.
311 // Args:        None.
312 // Return:      IDriver * - Pointer to a driver, NULL if there is no current working driver.
313 // Throws:      None.
314 //--
315 CMIDriverMgr::IDriver * CMIDriverMgr::GetUseThisDriverToDoWork( void ) const
316 {
317         return m_pDriverCurrent;
318 }
319
320 //++ ------------------------------------------------------------------------------------
321 // Details:     Call this function puts *this driver to work.
322 // Type:        Method.
323 // Args:        None.
324 // Return:      MIstatus::success - Functional succeeded.
325 //                      MIstatus::failure - Functional failed.
326 // Throws:      None.
327 //--
328 bool CMIDriverMgr::DriverMainLoop( void )
329 {
330         if( m_pDriverCurrent != nullptr )
331         {
332                 if( !m_pDriverCurrent->DoMainLoop() )
333                 {
334                         const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_MAINLOOP ), m_pDriverCurrent->GetError().c_str() ) );
335                         CMICmnStreamStdout::Instance().Write( errMsg, true );
336                         return MIstatus::failure;
337                 }
338         }
339         else
340         {
341                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
342                 CMICmnStreamStdout::Instance().Write( errMsg, true );
343                 return MIstatus::failure;
344         }
345
346         return MIstatus::success;
347 }
348
349 //++ ------------------------------------------------------------------------------------
350 // Details:     Call *this driver to resize the console window.
351 // Type:        Method.
352 // Args:        vWindowSizeWsCol        - (R) New window column size.
353 // Return:      MIstatus::success - Functional succeeded.
354 //                      MIstatus::failure - Functional failed.
355 // Throws:      None.
356 //--
357 void CMIDriverMgr::DriverResizeWindow( const uint32_t vWindowSizeWsCol )
358 {
359         if( m_pDriverCurrent != nullptr )
360                 return m_pDriverCurrent->DoResizeWindow( vWindowSizeWsCol );
361         else
362         {
363                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
364                 CMICmnStreamStdout::Instance().Write( errMsg, true );
365         }
366 }
367
368 //++ ------------------------------------------------------------------------------------
369 // Details:     Get the current driver to validate executable command line arguments.
370 // Type:        Method.
371 // Args:        argc            - (R)   An integer that contains the count of arguments that follow in 
372 //                                                              argv. The argc parameter is always greater than or equal to 1.
373 //                      argv            - (R)   An array of null-terminated strings representing command-line 
374 //                                                              arguments entered by the user of the program. By convention, 
375 //                                                              argv[0] is the command with which the program is invoked.
376 //                      vpStdOut        - (R)   Point to a standard output stream. 
377 //                      vwbExiting      - (W)   True = *this want to exit, false = continue to work. 
378 // Return:      MIstatus::success - Functional succeeded.
379 //                      MIstatus::failure - Functional failed.
380 // Throws:      None.
381 //--
382 bool CMIDriverMgr::DriverParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
383 {
384         if( m_pDriverCurrent == nullptr )
385         {
386                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
387                 CMICmnStreamStdout::Instance().Write( errMsg, true );
388                 return MIstatus::failure;
389         }
390
391         const lldb::SBError error( m_pDriverCurrent->DoParseArgs( argc, argv, vpStdOut, vwbExiting ) );
392         bool bOk = !error.Fail();
393         if( !bOk )
394         {
395                 CMIUtilString errMsg;
396                 const MIchar * pErrorCstr = error.GetCString();
397                 if( pErrorCstr != nullptr )
398                         errMsg = CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_PARSE_ARGS ), m_pDriverCurrent->GetName().c_str(), pErrorCstr );
399                 else
400                         errMsg = CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN ), m_pDriverCurrent->GetName().c_str() );
401
402                 bOk = CMICmnStreamStdout::Instance().Write( errMsg, true );
403         }
404
405         return bOk;
406 }
407
408 //++ ------------------------------------------------------------------------------------
409 // Details:     Retrieve the current driver's last error condition.
410 // Type:        Method.
411 // Args:        None.
412 // Return:      CMIUtilString - Text description.
413 // Throws:      None.
414 //--
415 CMIUtilString CMIDriverMgr::DriverGetError( void ) const
416 {
417         if( m_pDriverCurrent != nullptr )
418                 return m_pDriverCurrent->GetError();
419         else
420         {
421                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
422                 CMICmnStreamStdout::Instance().Write( errMsg, true );
423         }
424
425         return CMIUtilString();
426 }
427
428 //++ ------------------------------------------------------------------------------------
429 // Details:     Retrieve the current driver's name.
430 // Type:        Method.
431 // Args:        None.
432 // Return:      CMIUtilString - Driver name.
433 //                                                       Empty string = no current working driver specified.
434 // Throws:      None.
435 //--
436 CMIUtilString CMIDriverMgr::DriverGetName( void ) const
437 {
438         if( m_pDriverCurrent != nullptr )
439                 return m_pDriverCurrent->GetName();
440         else
441         {
442                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
443                 CMICmnStreamStdout::Instance().Write( errMsg, true );
444         }
445
446         return CMIUtilString();
447 }
448
449 //++ ------------------------------------------------------------------------------------
450 // Details:     Retrieve the current driver's debugger object.
451 // Type:        Method.
452 // Args:        None.
453 // Return:      lldb::SBDebugger * - Ptr to driver's debugger object. 
454 //                                                         - NULL = no current working driver specified.
455 // Throws:      None.
456 //--
457 lldb::SBDebugger * CMIDriverMgr::DriverGetTheDebugger( void )
458 {
459         lldb::SBDebugger * pDebugger = nullptr;
460         if( m_pDriverCurrent != nullptr )
461                 pDebugger = &m_pDriverCurrent->GetTheDebugger();
462         else
463         {
464                 const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
465                 CMICmnStreamStdout::Instance().Write( errMsg, true );
466         }
467
468         return pDebugger;
469 }
470
471 //++ ------------------------------------------------------------------------------------
472 // Details:     Check the arguments given on the command line. The main purpose of this
473 //                      function is to check for the presence of the --interpreter option. Having 
474 //                      this option present tells *this manager to set the CMIDriver to do work. If 
475 //                      not use the LLDB driver. The following are options that are only handled by
476 //                      the CMIDriverMgr are: 
477 //                              --help or -h
478 //                              --interpreter
479 //                              --version
480 //                              --versionLong
481 //                              --noLog
482 //                              --executable 
483 //                      The above arguments are not handled by any driver object except for --executable.
484 //                      The options --interpreter and --executable in code act very similar. The
485 //                      --executable is necessary to differentiate whither the MI Driver is being using
486 //                      by a client i.e. Eclipse or from the command line. Eclipse issues the option
487 //                      --interpreter and also passes additional arguments which can be interpreted as an
488 //                      executable if called from the command line. Using --executable tells the MI 
489 //                      Driver is being called the command line and that the executable argument is indeed
490 //                      a specified executable an so actions commands to set up the executable for a 
491 //                      debug session. Using --interpreter on the commnd line does not action additional
492 //                      commands to initialise a debug session and so be able to launch the process.
493 // Type:        Method.
494 // Args:        argc            - (R)   An integer that contains the count of arguments that follow in 
495 //                                                              argv. The argc parameter is always greater than or equal to 1.
496 //                      argv            - (R)   An array of null-terminated strings representing command-line 
497 //                                                              arguments entered by the user of the program. By convention, 
498 //                                                              argv[0] is the command with which the program is invoked.
499 //                      vwbExiting      - (W)   True = *this want to exit, Reasons: help, invalid arg(s),
500 //                                                              version information only.
501 //                                                              False = Continue to work, start debugger i.e. Command 
502 //                                                              interpreter. 
503 // Return:      lldb::SBError - LLDB current error status.
504 // Throws:      None.
505 //--
506 bool CMIDriverMgr::ParseArgs( const int argc, const char * argv[], bool & vwbExiting )
507 {
508         bool bOk = MIstatus::success;
509
510         vwbExiting = false;
511
512         // Print MI application path to the Log file
513         const CMIUtilString appPath( CMIUtilString::Format( MIRSRC( IDS_MI_APP_FILEPATHNAME ), argv[ 0 ] ) );
514         bOk = m_pLog->Write( appPath, CMICmnLog::eLogVerbosity_Log );
515                 
516         // Print application arguments to the Log file
517         const bool bHaveArgs( argc >= 2 );
518         CMIUtilString strArgs( MIRSRC( IDS_MI_APP_ARGS ) );
519         if( !bHaveArgs )
520         {
521                 strArgs += MIRSRC( IDS_WORD_NONE );
522                 bOk = bOk && m_pLog->Write( strArgs, CMICmnLog::eLogVerbosity_Log );
523         }
524         else
525         {
526                 for( MIint i = 1; i < argc; i++ ) 
527                 { 
528                         strArgs += CMIUtilString::Format( "%d:'%s' ", i, argv[ i ] );
529                 }
530                 bOk = bOk && m_pLog->Write( strArgs, CMICmnLog::eLogVerbosity_Log );
531         }
532         
533         // Look for the command line options            
534         bool bHaveArgInterpret = false;
535         bool bHaveArgVersion = false;
536         bool bHaveArgVersionLong = false;
537         bool bHaveArgNoLog = false;
538         bool bHaveArgHelp = false;
539
540         // Hardcode the use of the MI driver
541 #if MICONFIG_DEFAULT_TO_MI_DRIVER
542         bHaveArgInterpret = true;
543 #endif // MICONFIG_DEFAULT_TO_MI_DRIVER
544
545         if( bHaveArgs )
546         {
547                 // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
548                 for( MIint i = 1; i < argc; i++ ) 
549                 { 
550                         // *** Add args to help in GetHelpOnCmdLineArgOptions() ***
551                         const CMIUtilString strArg( argv[ i ] );
552
553                         // Argument "--executable" is also check for in CMIDriver::ParseArgs()
554                         if( (0 == strArg.compare( "--interpreter" )) || // Given by the client such as Eclipse
555                                 (0 == strArg.compare( "--executable" )) )       // Used to specify that there is executable argument also on the command line 
556                         {                                                                                               // See fn description.
557                                    bHaveArgInterpret = true;
558                         }
559                         if( 0 == strArg.compare( "--version" ) ) 
560                         {
561                                    bHaveArgVersion = true;
562                         }
563                         if( 0 == strArg.compare( "--versionLong" ) ) 
564                         {
565                                    bHaveArgVersionLong = true;
566                         }
567                         if( 0 == strArg.compare( "--noLog" ) ) 
568                         {
569                                    bHaveArgNoLog = true;
570                         }
571                         if( (0 == strArg.compare( "--help" )) || (0 == strArg.compare( "-h" )) )
572                         {
573                                 bHaveArgHelp = true;
574                         }
575                 }
576         }
577
578         if( bHaveArgNoLog )
579         {
580                 CMICmnLog::Instance().SetEnabled( false );
581         }
582         
583         // Todo: Remove this output when MI is finished. It is temporary to persuade Ecllipse plugin to work.
584         //               Eclipse reads this literally and will not work unless it gets this exact version text.
585         // Handle --version option (ignore the --interpreter option if present)
586         if( bHaveArgVersion )
587         {
588                 vwbExiting = true;
589                 bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( MIRSRC( IDE_MI_VERSION_GDB ) );
590                 return bOk;
591         }
592
593         // Todo: Make this the --version when the the above --version version is removed
594         // Handle --versionlong option (ignore the --interpreter option if present)
595         if( bHaveArgVersionLong )
596         {
597                 vwbExiting = true;
598                 bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( GetAppVersion() );
599                 return bOk;
600         }
601
602         // Both '--help' and '--intepreter' means give help for MI only. Without 
603         // '--interpreter' help the LLDB driver is working and so help is for that.
604         if( bHaveArgHelp && bHaveArgInterpret )
605         {
606                 vwbExiting = true;
607                 bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( GetHelpOnCmdLineArgOptions() );
608                 return bOk;
609         }
610  
611         // This makes the assumption that there is at least one MI compatible
612         // driver registered and one LLDB driver registerd and the CMIDriver 
613         // is the first one found.
614         // ToDo: Implement a better solution that handle any order, any number
615         // of drivers. Or this 'feature' may be removed if deemed not required.
616         IDriver * pLldbDriver = GetFirstNonMIDriver();
617         IDriver * pMi2Driver = GetFirstMIDriver();
618         if( bHaveArgInterpret && (pMi2Driver != nullptr) )
619                 bOk = bOk && SetUseThisDriverToDoWork( *pMi2Driver );
620         else if( pLldbDriver != nullptr )
621                 bOk = bOk && SetUseThisDriverToDoWork( *pLldbDriver );
622         else
623         {
624                 if( bOk )
625                 {
626                         vwbExiting = true;
627                         const CMIUtilString msg( MIRSRC( IDS_DRIVER_ERR_NON_REGISTERED ) );
628                         bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( msg );
629                 }
630         }
631                                         
632         return bOk;
633 }
634         
635 //++ ------------------------------------------------------------------------------------
636 // Details:     Return formatted application version and name information.
637 // Type:        Method.
638 // Args:        None. 
639 // Return:      CMIUtilString - Text data.
640 // Throws:      None.
641 //--
642 CMIUtilString CMIDriverMgr::GetAppVersion( void ) const
643 {
644         const CMIUtilString strProj( MIRSRC( IDS_PROJNAME ) );
645         const CMIUtilString strVsn( CMIDriver::Instance().GetVersionDescription() );
646         const CMIUtilString strGdb( MIRSRC( IDE_MI_VERSION_GDB ) );
647         const CMIUtilString strVrsnInfo( CMIUtilString::Format( "%s\n%s\n%s", strProj.c_str(), strVsn.c_str(), strGdb.c_str() ) );
648
649         return strVrsnInfo;
650 }
651
652 //++ ------------------------------------------------------------------------------------
653 // Details:     Return formatted help information on all the MI command line options.
654 // Type:        Method.
655 // Args:        None. 
656 // Return:      CMIUtilString - Text data.
657 // Throws:      None.
658 //--
659 CMIUtilString CMIDriverMgr::GetHelpOnCmdLineArgOptions( void ) const
660 {
661         const CMIUtilString pHelp[] = 
662         {
663                 MIRSRC( IDE_MI_APP_DESCRIPTION ),
664                 MIRSRC( IDE_MI_APP_INFORMATION ),
665                 MIRSRC( IDE_MI_APP_ARG_USAGE ),
666                 MIRSRC( IDE_MI_APP_ARG_HELP ),
667                 MIRSRC( IDE_MI_APP_ARG_VERSION ),
668                 MIRSRC( IDE_MI_APP_ARG_VERSION_LONG ),
669                 MIRSRC( IDE_MI_APP_ARG_INTERPRETER ),
670                 MIRSRC( IDE_MI_APP_ARG_EXECUTEABLE ),
671                 CMIUtilString::Format( MIRSRC( IDE_MI_APP_ARG_NO_APP_LOG ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ),
672                 MIRSRC( IDE_MI_APP_ARG_EXECUTABLE ),
673                 MIRSRC( IDS_CMD_QUIT_HELP ),
674                 MIRSRC( IDE_MI_APP_ARG_EXAMPLE )
675         };
676         const MIuint nHelpItems = sizeof pHelp / sizeof pHelp[ 0 ];
677         CMIUtilString strHelp;
678         for( MIuint i = 0; i < nHelpItems; i++ )
679         {
680                 strHelp += pHelp[ i ];
681                 strHelp += "\n\n";
682         }
683
684         return strHelp;
685 }
686
687 //++ ------------------------------------------------------------------------------------
688 // Details:     Search the registered drivers and return the first driver which says it is
689 //                      GDB/MI compatible i.e. the CMIDriver class.
690 // Type:        Method.
691 // Args:        None. 
692 // Return:      IDriver * - Ptr to driver, NULL = no driver found.
693 // Throws:      None.
694 //--
695 CMIDriverMgr::IDriver * CMIDriverMgr::GetFirstMIDriver( void ) const
696 {
697         IDriver * pDriver = nullptr;
698         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
699         while( it != m_mapDriverIdToDriver.end() )
700         {
701                 const CMIUtilString & rDrvId = (*it).first; MIunused( rDrvId );
702                 IDriver * pDvr = (*it).second;
703                 if( pDvr->GetDriverIsGDBMICompatibleDriver() )
704                 {
705                         pDriver = pDvr;
706                         break;
707                 }
708
709                 // Next
710                 ++it;
711         }
712
713         return pDriver;
714 }
715
716 //++ ------------------------------------------------------------------------------------
717 // Details:     Search the registered drivers and return the first driver which says it is
718 //                      not GDB/MI compatible i.e. the LLDB Driver class.
719 // Type:        Method.
720 // Args:        None. 
721 // Return:      IDriver * - Ptr to driver, NULL = no driver found.
722 // Throws:      None.
723 //--
724 CMIDriverMgr::IDriver * CMIDriverMgr::GetFirstNonMIDriver( void ) const
725 {
726         IDriver * pDriver = nullptr;
727         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
728         while( it != m_mapDriverIdToDriver.end() )
729         {
730                 const CMIUtilString & rDrvId = (*it).first; MIunused( rDrvId );
731                 IDriver * pDvr = (*it).second;
732                 if( !pDvr->GetDriverIsGDBMICompatibleDriver() )
733                 {
734                         pDriver = pDvr;
735                         break;
736                 }
737
738                 // Next
739                 ++it;
740         }
741
742         return pDriver;
743 }
744
745 //++ ------------------------------------------------------------------------------------
746 // Details:     Search the registered drivers and return driver with the specified ID.
747 // Type:        Method.
748 // Args:        vrDriverId      - (R) ID of a driver. 
749 // Return:      IDriver * - Ptr to driver, NULL = no driver found.
750 // Throws:      None.
751 //--
752 CMIDriverMgr::IDriver * CMIDriverMgr::GetDriver( const CMIUtilString & vrDriverId ) const
753 {
754         MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.find( vrDriverId );
755         if( it == m_mapDriverIdToDriver.end() )
756                 return nullptr;
757
758         IDriver * pDriver = (*it).second;
759         
760         return pDriver;
761 }
762