| //===-- 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; |
| } |