| //===-- 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 "MICmnStreamStdin.h" |
| #include "MICmnStreamStdout.h" |
| #include "MICmnResources.h" |
| #include "MICmnLog.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; |
| } |