|  | //===-- MICmnStreamStdin.cpp ------------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | // Third Party Headers | 
|  | #ifdef _MSC_VER | 
|  | #include <windows.h> | 
|  | #endif | 
|  | #include <string.h> // For std::strerror() | 
|  |  | 
|  | // In-house headers: | 
|  | #include "MICmnLog.h" | 
|  | #include "MICmnResources.h" | 
|  | #include "MICmnStreamStdin.h" | 
|  | #include "MICmnStreamStdout.h" | 
|  | #include "MIDriver.h" | 
|  | #include "MIUtilSingletonHelper.h" | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: CMICmnStreamStdin constructor. | 
|  | // Type:    Method. | 
|  | // Args:    None. | 
|  | // Return:  None. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | CMICmnStreamStdin::CMICmnStreamStdin() | 
|  | : m_strPromptCurrent("(gdb)"), m_bShowPrompt(true), m_pCmdBuffer(nullptr) {} | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: CMICmnStreamStdin destructor. | 
|  | // Type:    Overridable. | 
|  | // Args:    None. | 
|  | // Return:  None. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | CMICmnStreamStdin::~CMICmnStreamStdin() { Shutdown(); } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Initialize resources for *this Stdin stream. | 
|  | // Type:    Method. | 
|  | // Args:    None. | 
|  | // Return:  MIstatus::success - Functional succeeded. | 
|  | //          MIstatus::failure - Functional failed. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | bool CMICmnStreamStdin::Initialize() { | 
|  | m_clientUsageRefCnt++; | 
|  |  | 
|  | if (m_bInitialized) | 
|  | return MIstatus::success; | 
|  |  | 
|  | bool bOk = MIstatus::success; | 
|  | CMIUtilString errMsg; | 
|  |  | 
|  | // Note initialisation order is important here as some resources depend on | 
|  | // previous | 
|  | MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); | 
|  | MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); | 
|  |  | 
|  | if (bOk) { | 
|  | m_pCmdBuffer = new char[m_constBufferSize]; | 
|  | } else { | 
|  | CMIUtilString strInitError(CMIUtilString::Format( | 
|  | MIRSRC(IDS_MI_INIT_ERR_STREAMSTDIN), errMsg.c_str())); | 
|  | SetErrorDescription(strInitError); | 
|  |  | 
|  | return MIstatus::failure; | 
|  | } | 
|  | m_bInitialized = bOk; | 
|  |  | 
|  | return MIstatus::success; | 
|  | } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Release resources for *this Stdin stream. | 
|  | // Type:    Method. | 
|  | // Args:    None. | 
|  | // Return:  MIstatus::success - Functional succeeded. | 
|  | //          MIstatus::failure - Functional failed. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | bool CMICmnStreamStdin::Shutdown() { | 
|  | if (--m_clientUsageRefCnt > 0) | 
|  | return MIstatus::success; | 
|  |  | 
|  | if (!m_bInitialized) | 
|  | return MIstatus::success; | 
|  |  | 
|  | m_bInitialized = false; | 
|  |  | 
|  | ClrErrorDescription(); | 
|  |  | 
|  | if (m_pCmdBuffer != nullptr) { | 
|  | delete[] m_pCmdBuffer; | 
|  | m_pCmdBuffer = nullptr; | 
|  | } | 
|  |  | 
|  | bool bOk = MIstatus::success; | 
|  | CMIUtilString errMsg; | 
|  |  | 
|  | MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); | 
|  | MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); | 
|  |  | 
|  | if (!bOk) { | 
|  | SetErrorDescriptionn(MIRSRC(IDE_MI_SHTDWN_ERR_STREAMSTDIN), errMsg.c_str()); | 
|  | } | 
|  |  | 
|  | return MIstatus::success; | 
|  | } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Validate and set the text that forms the prompt on the command line. | 
|  | // Type:    Method. | 
|  | // Args:    vNewPrompt  - (R) Text description. | 
|  | // Return:  MIstatus::success - Functional succeeded. | 
|  | //          MIstatus::failure - Functional failed. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | bool CMICmnStreamStdin::SetPrompt(const CMIUtilString &vNewPrompt) { | 
|  | if (vNewPrompt.empty()) { | 
|  | const CMIUtilString msg(CMIUtilString::Format( | 
|  | MIRSRC(IDS_STDIN_ERR_INVALID_PROMPT), vNewPrompt.c_str())); | 
|  | CMICmnStreamStdout::Instance().Write(msg); | 
|  | return MIstatus::failure; | 
|  | } | 
|  |  | 
|  | m_strPromptCurrent = vNewPrompt; | 
|  |  | 
|  | return MIstatus::success; | 
|  | } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Retrieve the command line prompt text currently being used. | 
|  | // Type:    Method. | 
|  | // Args:    None. | 
|  | // Return:  const CMIUtilString & - Functional failed. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | const CMIUtilString &CMICmnStreamStdin::GetPrompt() const { | 
|  | return m_strPromptCurrent; | 
|  | } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Set whether to display optional command line prompt. The prompt is | 
|  | // output to | 
|  | //          stdout. Disable it when this may interfere with the client reading | 
|  | //          stdout as | 
|  | //          input and it tries to interpret the prompt text to. | 
|  | // Type:    Method. | 
|  | // Args:    vbYes   - (R) True = Yes prompt is shown/output to the user | 
|  | // (stdout), false = no prompt. | 
|  | // Return:  MIstatus::success - Functional succeeded. | 
|  | //          MIstatus::failure - Functional failed. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | void CMICmnStreamStdin::SetEnablePrompt(const bool vbYes) { | 
|  | m_bShowPrompt = vbYes; | 
|  | } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Get whether to display optional command line prompt. The prompt is | 
|  | // output to | 
|  | //          stdout. Disable it when this may interfere with the client reading | 
|  | //          stdout as | 
|  | //          input and it tries to interpret the prompt text to. | 
|  | // Type:    Method. | 
|  | // Args:    None. | 
|  | // Return:  bool - True = Yes prompt is shown/output to the user (stdout), false | 
|  | // = no prompt. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | bool CMICmnStreamStdin::GetEnablePrompt() const { return m_bShowPrompt; } | 
|  |  | 
|  | //++ | 
|  | //------------------------------------------------------------------------------------ | 
|  | // Details: Wait on new line of data from stdin stream (completed by '\n' or | 
|  | // '\r'). | 
|  | // Type:    Method. | 
|  | // Args:    vwErrMsg    - (W) Empty string ok or error description. | 
|  | // Return:  char * - text buffer pointer or NULL on failure. | 
|  | // Throws:  None. | 
|  | //-- | 
|  | const char *CMICmnStreamStdin::ReadLine(CMIUtilString &vwErrMsg) { | 
|  | vwErrMsg.clear(); | 
|  |  | 
|  | // Read user input | 
|  | const char *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin); | 
|  | if (pText == nullptr) { | 
|  | #ifdef _MSC_VER | 
|  | // Was Ctrl-C hit? | 
|  | // On Windows, Ctrl-C gives an ERROR_OPERATION_ABORTED as error on the | 
|  | // command-line. | 
|  | // The end-of-file indicator is also set, so without this check we will exit | 
|  | // next if statement. | 
|  | if (::GetLastError() == ERROR_OPERATION_ABORTED) | 
|  | return nullptr; | 
|  | #endif | 
|  | if (::feof(stdin)) { | 
|  | const bool bForceExit = true; | 
|  | CMIDriver::Instance().SetExitApplicationFlag(bForceExit); | 
|  | } else if (::ferror(stdin) != 0) | 
|  | vwErrMsg = ::strerror(errno); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Strip off new line characters | 
|  | for (char *pI = m_pCmdBuffer; *pI != '\0'; pI++) { | 
|  | if ((*pI == '\n') || (*pI == '\r')) { | 
|  | *pI = '\0'; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return pText; | 
|  | } |