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