1 //===-- MICmnStreamStdout.cpp -----------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // In-house headers:
11 #include "MICmnStreamStdout.h"
12 #include "MICmnLog.h"
13 #include "MICmnResources.h"
14 #include "MIDriver.h"
15
16 //++
17 //------------------------------------------------------------------------------------
18 // Details: CMICmnStreamStdout constructor.
19 // Type: Method.
20 // Args: None.
21 // Return: None.
22 // Throws: None.
23 //--
CMICmnStreamStdout()24 CMICmnStreamStdout::CMICmnStreamStdout() {}
25
26 //++
27 //------------------------------------------------------------------------------------
28 // Details: CMICmnStreamStdout destructor.
29 // Type: Overridable.
30 // Args: None.
31 // Return: None.
32 // Throws: None.
33 //--
~CMICmnStreamStdout()34 CMICmnStreamStdout::~CMICmnStreamStdout() { Shutdown(); }
35
36 //++
37 //------------------------------------------------------------------------------------
38 // Details: Initialize resources for *this Stdout stream.
39 // Type: Method.
40 // Args: None.
41 // Return: MIstatus::success - Functional succeeded.
42 // MIstatus::failure - Functional failed.
43 // Throws: None.
44 //--
Initialize()45 bool CMICmnStreamStdout::Initialize() {
46 m_clientUsageRefCnt++;
47
48 if (m_bInitialized)
49 return MIstatus::success;
50
51 bool bOk = MIstatus::success;
52
53 #ifdef _MSC_VER
54 // Debugging / I/O issues with client.
55 // This is only required on Windows if you do not use ::flush(stdout). MI uses
56 // ::flush(stdout)
57 // It trys to ensure the process attached to the stdout steam gets ALL the data.
58 //::setbuf( stdout, NULL );
59 #endif // _MSC_VER
60
61 m_bInitialized = bOk;
62
63 return MIstatus::success;
64 }
65
66 //++
67 //------------------------------------------------------------------------------------
68 // Details: Release resources for *this Stdout stream.
69 // Type: Method.
70 // Args: None.
71 // Return: MIstatus::success - Functional succeeded.
72 // MIstatus::failure - Functional failed.
73 // Throws: None.
74 //--
Shutdown()75 bool CMICmnStreamStdout::Shutdown() {
76 if (--m_clientUsageRefCnt > 0)
77 return MIstatus::success;
78
79 if (!m_bInitialized)
80 return MIstatus::success;
81
82 ClrErrorDescription();
83
84 m_bInitialized = false;
85
86 return MIstatus::success;
87 }
88
89 //++
90 //------------------------------------------------------------------------------------
91 // Details: Write an MI format type response to stdout. The text data does not
92 // need to
93 // include a carriage line return as this is added to the text. The
94 // function also
95 // then passes the text data into the CMICmnLog logger.
96 // Type: Method.
97 // Args: vText - (R) MI formatted text.
98 // vbSendToLog - (R) True = Yes send to the Log file too, false = do
99 // not. (Dflt = true)
100 // Return: MIstatus::success - Functional succeeded.
101 // MIstatus::failure - Functional failed.
102 // Throws: None.
103 //--
WriteMIResponse(const CMIUtilString & vText,const bool vbSendToLog)104 bool CMICmnStreamStdout::WriteMIResponse(const CMIUtilString &vText,
105 const bool vbSendToLog /* = true */) {
106 return WritePriv(vText, vText, vbSendToLog);
107 }
108
109 //++
110 //------------------------------------------------------------------------------------
111 // Details: Write text data to stdout. The text data does not need to
112 // include a carriage line return as this is added to the text. The
113 // function also
114 // then passes the text data into the CMICmnLog logger.
115 // Type: Method.
116 // Args: vText - (R) Text data.
117 // vbSendToLog - (R) True = Yes send to the Log file too, false = do
118 // not. (Dflt = true)
119 // Return: MIstatus::success - Functional succeeded.
120 // MIstatus::failure - Functional failed.
121 // Throws: None.
122 //--
Write(const CMIUtilString & vText,const bool vbSendToLog)123 bool CMICmnStreamStdout::Write(const CMIUtilString &vText,
124 const bool vbSendToLog /* = true */) {
125 if (vText.length() == 0)
126 return MIstatus::failure;
127
128 const CMIUtilString strPrefixed(CMIUtilString::Format(
129 "%s: %s", CMIDriver::Instance().GetAppNameShort().c_str(),
130 vText.c_str()));
131
132 return WritePriv(strPrefixed, vText, vbSendToLog);
133 }
134
135 //++
136 //------------------------------------------------------------------------------------
137 // Details: Write text data to stdout. The text data does not need to
138 // include a carriage line return as this is added to the text. The
139 // function also
140 // then passes the text data into the CMICmnLog logger.
141 // Type: Method.
142 // Args: vText - (R) Text data prefixed with MI app's short name.
143 // vTxtForLogFile - (R) Text data.
144 // vbSendToLog - (R) True = Yes send to the Log file too, false =
145 // do not. (Dflt = true)
146 // Return: MIstatus::success - Functional succeeded.
147 // MIstatus::failure - Functional failed.
148 // Throws: None.
149 //--
WritePriv(const CMIUtilString & vText,const CMIUtilString & vTxtForLogFile,const bool vbSendToLog)150 bool CMICmnStreamStdout::WritePriv(const CMIUtilString &vText,
151 const CMIUtilString &vTxtForLogFile,
152 const bool vbSendToLog /* = true */) {
153 if (vText.length() == 0)
154 return MIstatus::failure;
155
156 bool bOk = MIstatus::success;
157 {
158 // Grab the stdout thread lock while we print
159 CMIUtilThreadLock _lock(m_mutex);
160
161 // Send this text to stdout
162 const MIint status = ::fputs(vText.c_str(), stdout);
163 if (status == EOF)
164 // Don't call the CMICmnBase::SetErrorDescription() because it will cause
165 // a stack overflow:
166 // CMICmnBase::SetErrorDescription -> CMICmnStreamStdout::Write ->
167 // CMICmnStreamStdout::WritePriv -> CMICmnBase::SetErrorDescription
168 bOk = MIstatus::failure;
169 else {
170 ::fprintf(stdout, "\n");
171 ::fflush(stdout);
172 }
173
174 // Send this text to the log
175 if (bOk && vbSendToLog)
176 bOk &= m_pLog->WriteLog(vTxtForLogFile);
177 }
178
179 return bOk;
180 }
181
182 //++
183 //------------------------------------------------------------------------------------
184 // Details: Lock the availability of the stream stdout. Other users of *this
185 // stream will
186 // be stalled until it is available (Unlock()).
187 // Type: Method.
188 // Args: None.
189 // Return: MIstatus::success - Functional succeeded.
190 // MIstatus::failure - Functional failed.
191 // Throws: None.
192 //--
Lock()193 bool CMICmnStreamStdout::Lock() {
194 m_mutex.Lock();
195 return MIstatus::success;
196 }
197
198 //++
199 //------------------------------------------------------------------------------------
200 // Details: Release a previously locked stdout.
201 // Type: Method.
202 // Args: None.
203 // Return: MIstatus::success - Functional succeeded.
204 // MIstatus::failure - Functional failed.
205 // Throws: None.
206 //--
Unlock()207 bool CMICmnStreamStdout::Unlock() {
208 m_mutex.Unlock();
209 return MIstatus::success;
210 }
211
212 //++
213 //------------------------------------------------------------------------------------
214 // Details: Take a text data and send to the stdout stream. Also output to the
215 // MI Log
216 // file.
217 // Type: Static method.
218 // Args: vrTxt - (R) Text.
219 // Return: MIstatus::success - Functionality succeeded.
220 // MIstatus::failure - Functionality failed.
221 // Throws: None.
222 //--
TextToStdout(const CMIUtilString & vrTxt)223 bool CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) {
224 const bool bSendToLog = true;
225 return CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt, bSendToLog);
226 }
227
228 //++
229 //------------------------------------------------------------------------------------
230 // Details: Write prompt to stdout if it's enabled.
231 // Type: Static method.
232 // Args: None.
233 // Return: MIstatus::success - Function succeeded.
234 // MIstatus::failure - Function failed.
235 // Throws: None.
236 //--
WritePrompt()237 bool CMICmnStreamStdout::WritePrompt() {
238 const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance();
239 if (rStdinMan.GetEnablePrompt())
240 return TextToStdout(rStdinMan.GetPrompt());
241 return MIstatus::success;
242 }
243