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