//===-- MICmnStreamStdout.cpp -----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // In-house headers: #include "MICmnStreamStdout.h" #include "MICmnLog.h" #include "MICmnResources.h" #include "MIDriver.h" //++ // Details: CMICmnStreamStdout constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmnStreamStdout::CMICmnStreamStdout() {} //++ // Details: CMICmnStreamStdout destructor. // Type: Overridable. // Args: None. // Return: None. // Throws: None. //-- CMICmnStreamStdout::~CMICmnStreamStdout() { Shutdown(); } //++ // Details: Initialize resources for *this Stdout stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::Initialize() { m_clientUsageRefCnt++; if (m_bInitialized) return MIstatus::success; bool bOk = MIstatus::success; #ifdef _MSC_VER // Debugging / I/O issues with client. // This is only required on Windows if you do not use ::flush(stdout). MI uses // ::flush(stdout) // It trys to ensure the process attached to the stdout steam gets ALL the data. //::setbuf( stdout, NULL ); #endif // _MSC_VER m_bInitialized = bOk; return MIstatus::success; } //++ // Details: Release resources for *this Stdout stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::Shutdown() { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; ClrErrorDescription(); m_bInitialized = false; return MIstatus::success; } //++ // Details: Write an MI format type response to stdout. The text data does not // need to // include a carriage line return as this is added to the text. The // function also // then passes the text data into the CMICmnLog logger. // Type: Method. // Args: vText - (R) MI formatted text. // vbSendToLog - (R) True = Yes send to the Log file too, false = do // not. (Dflt = true) // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::WriteMIResponse(const CMIUtilString &vText, const bool vbSendToLog /* = true */) { return WritePriv(vText, vText, vbSendToLog); } //++ // Details: Write text data to stdout. The text data does not need to // include a carriage line return as this is added to the text. The // function also // then passes the text data into the CMICmnLog logger. // Type: Method. // Args: vText - (R) Text data. // vbSendToLog - (R) True = Yes send to the Log file too, false = do // not. (Dflt = true) // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::Write(const CMIUtilString &vText, const bool vbSendToLog /* = true */) { if (vText.length() == 0) return MIstatus::failure; const CMIUtilString strPrefixed(CMIUtilString::Format( "%s: %s", CMIDriver::Instance().GetAppNameShort().c_str(), vText.c_str())); return WritePriv(strPrefixed, vText, vbSendToLog); } //++ // Details: Write text data to stdout. The text data does not need to // include a carriage line return as this is added to the text. The // function also // then passes the text data into the CMICmnLog logger. // Type: Method. // Args: vText - (R) Text data prefixed with MI app's short name. // vTxtForLogFile - (R) Text data. // vbSendToLog - (R) True = Yes send to the Log file too, false = // do not. (Dflt = true) // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::WritePriv(const CMIUtilString &vText, const CMIUtilString &vTxtForLogFile, const bool vbSendToLog /* = true */) { if (vText.length() == 0) return MIstatus::failure; bool bOk = MIstatus::success; { // Grab the stdout thread lock while we print CMIUtilThreadLock _lock(m_mutex); // Send this text to stdout const MIint status = ::fputs(vText.c_str(), stdout); if (status == EOF) // Don't call the CMICmnBase::SetErrorDescription() because it will cause // a stack overflow: // CMICmnBase::SetErrorDescription -> CMICmnStreamStdout::Write -> // CMICmnStreamStdout::WritePriv -> CMICmnBase::SetErrorDescription bOk = MIstatus::failure; else { ::fprintf(stdout, "\n"); ::fflush(stdout); } // Send this text to the log if (bOk && vbSendToLog) bOk &= m_pLog->WriteLog(vTxtForLogFile); } return bOk; } //++ // Details: Lock the availability of the stream stdout. Other users of *this // stream will // be stalled until it is available (Unlock()). // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::Lock() { m_mutex.Lock(); return MIstatus::success; } //++ // Details: Release a previously locked stdout. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdout::Unlock() { m_mutex.Unlock(); return MIstatus::success; } //++ // Details: Take a text data and send to the stdout stream. Also output to the // MI Log // file. // Type: Static method. // Args: vrTxt - (R) Text. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) { const bool bSendToLog = true; return CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt, bSendToLog); } //++ // Details: Write prompt to stdout if it's enabled. // Type: Static method. // Args: None. // Return: MIstatus::success - Function succeeded. // MIstatus::failure - Function failed. // Throws: None. //-- bool CMICmnStreamStdout::WritePrompt() { const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); if (rStdinMan.GetEnablePrompt()) return TextToStdout(rStdinMan.GetPrompt()); return MIstatus::success; }