//===-- 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 #endif #include // 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(IDS_MI_INIT_ERR_LOG, bOk, errMsg); MI::ModuleInit(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(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown(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; }