]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MICmnStreamStdinWindows.cpp
Add ELF Tool Chain's brandelf(1) to contrib
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / tools / lldb-mi / MICmnStreamStdinWindows.cpp
1 //===-- MICmnStreamStdinWindows.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 //++
11 // File:        MIUtilStreamStdin.cpp
12 //
13 // Overview:    CMICmnStreamStdinWindows implementation.
14 //
15 // Environment: Compilers:  Visual C++ 12.
16 //                          gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
17 //              Libraries:  See MIReadmetxt.
18 //
19 // Copyright:   None.
20 //--
21
22 // Third Party Headers:
23 #if defined(_MSC_VER)
24 #include <stdio.h>
25 #include <Windows.h>
26 #include <io.h>
27 #include <conio.h>
28 #endif // defined( _MSC_VER )
29 #include <string.h>
30
31 // In-house headers:
32 #include "MICmnStreamStdinWindows.h"
33 #include "MICmnLog.h"
34 #include "MICmnResources.h"
35 #include "MIUtilSystemWindows.h"
36 #include "MIUtilSingletonHelper.h"
37
38 //++ ------------------------------------------------------------------------------------
39 // Details: CMICmnStreamStdinWindows constructor.
40 // Type:    Method.
41 // Args:    None.
42 // Return:  None.
43 // Throws:  None.
44 //--
45 CMICmnStreamStdinWindows::CMICmnStreamStdinWindows(void)
46     : m_constBufferSize(1024)
47     , m_pStdin(nullptr)
48     , m_pCmdBuffer(nullptr)
49     , m_pStdinBuffer(nullptr)
50     , m_nBytesToBeRead(0)
51     , m_bRunningInConsoleWin(false)
52 {
53 }
54
55 //++ ------------------------------------------------------------------------------------
56 // Details: CMICmnStreamStdinWindows destructor.
57 // Type:    Overridable.
58 // Args:    None.
59 // Return:  None.
60 // Throws:  None.
61 //--
62 CMICmnStreamStdinWindows::~CMICmnStreamStdinWindows(void)
63 {
64     Shutdown();
65 }
66
67 //++ ------------------------------------------------------------------------------------
68 // Details: Initialize resources for *this Stdin stream.
69 // Type:    Method.
70 // Args:    None.
71 // Return:  MIstatus::success - Functional succeeded.
72 //          MIstatus::failure - Functional failed.
73 // Throws:  None.
74 //--
75 bool
76 CMICmnStreamStdinWindows::Initialize(void)
77 {
78     if (m_bInitialized)
79         return MIstatus::success;
80
81     bool bOk = MIstatus::success;
82     CMIUtilString errMsg;
83
84     // Note initialisation order is important here as some resources depend on previous
85     MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
86     MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
87
88     // Other resources required
89     if (bOk)
90     {
91         m_pCmdBuffer = new MIchar[m_constBufferSize];
92         m_pStdin = stdin;
93
94 #if MICONFIG_CREATE_OWN_STDIN_BUFFER
95         // Give stdinput a user defined buffer
96         m_pStdinBuffer = new char[1024];
97         ::setbuf(stdin, m_pStdinBuffer);
98 #endif // MICONFIG_CREATE_OWN_STDIN_BUFFER
99
100         // Clear error indicators for std input
101         ::clearerr(stdin);
102
103 #if defined(_MSC_VER)
104         m_bRunningInConsoleWin = ::_isatty(::fileno(stdin));
105 #endif // #if defined( _MSC_VER )
106     }
107
108     m_bInitialized = bOk;
109
110     if (!bOk)
111     {
112         CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_OS_STDIN_HANDLER), errMsg.c_str()));
113         SetErrorDescription(strInitError);
114         return MIstatus::failure;
115     }
116
117     return MIstatus::success;
118 }
119
120 //++ ------------------------------------------------------------------------------------
121 // Details: Release resources for *this Stdin stream.
122 // Type:    Method.
123 // Args:    None.
124 // Return:  MIstatus::success - Functional succeeded.
125 //          MIstatus::failure - Functional failed.
126 // Throws:  None.
127 //--
128 bool
129 CMICmnStreamStdinWindows::Shutdown(void)
130 {
131     if (!m_bInitialized)
132         return MIstatus::success;
133
134     m_bInitialized = false;
135
136     ClrErrorDescription();
137
138     bool bOk = MIstatus::success;
139     CMIUtilString errMsg;
140
141     // Tidy up
142     if (m_pCmdBuffer != nullptr)
143     {
144         delete[] m_pCmdBuffer;
145         m_pCmdBuffer = nullptr;
146     }
147     m_pStdin = nullptr;
148
149 #if MICONFIG_CREATE_OWN_STDIN_BUFFER
150     if (m_pStdinBuffer)
151         delete[] m_pStdinBuffer;
152     m_pStdinBuffer = nullptr;
153 #endif // MICONFIG_CREATE_OWN_STDIN_BUFFER
154
155     // Note shutdown order is important here
156     MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
157     MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
158
159     if (!bOk)
160     {
161         SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER), errMsg.c_str());
162     }
163
164     return MIstatus::success;
165 }
166
167 //++ ------------------------------------------------------------------------------------
168 // Details: Determine if stdin has any characters present in its buffer.
169 // Type:    Method.
170 // Args:    vwbAvail    - (W) True = There is chars available, false = nothing there.
171 // Return:  MIstatus::success - Functional succeeded.
172 //          MIstatus::failure - Functional failed.
173 // Throws:  None.
174 //--
175 bool
176 CMICmnStreamStdinWindows::InputAvailable(bool &vwbAvail)
177 {
178     return m_bRunningInConsoleWin ? InputAvailableConsoleWin(vwbAvail) : InputAvailableApplication(vwbAvail);
179 }
180
181 //++ ------------------------------------------------------------------------------------
182 // Details: Determine if stdin has any characters present in its buffer. If running in a
183 //          terminal use _kbhit().
184 // Type:    Method.
185 // Args:    vwbAvail    - (W) True = There is chars available, false = nothing there.
186 // Return:  MIstatus::success - Functional succeeded.
187 //          MIstatus::failure - Functional failed.
188 // Throws:  None.
189 //--
190 bool
191 CMICmnStreamStdinWindows::InputAvailableConsoleWin(bool &vwbAvail)
192 {
193 #if defined(_MSC_VER)
194     if (m_nBytesToBeRead == 0)
195     {
196         // Get a windows handle to std input stream
197         HANDLE handle = ::GetStdHandle(STD_INPUT_HANDLE);
198         DWORD nBytesWaiting = ::_kbhit();
199
200         // Save the number of bytes to be read so that we can check if input is available to be read
201         m_nBytesToBeRead = nBytesWaiting;
202
203         // Return state of whether bytes are waiting or not
204         vwbAvail = (nBytesWaiting > 0);
205     }
206 #endif // #if defined( _MSC_VER )
207
208     return MIstatus::success;
209 }
210
211 //++ ------------------------------------------------------------------------------------
212 // Details: Determine if stdin has any characters present in its buffer.
213 // Type:    Method.
214 // Args:    vwbAvail    - (W) True = There is chars available, false = nothing there.
215 // Return:  MIstatus::success - Functional succeeded.
216 //          MIstatus::failure - Functional failed.
217 // Throws:  None.
218 //--
219 bool
220 CMICmnStreamStdinWindows::InputAvailableApplication(bool &vwbAvail)
221 {
222 #if defined(_MSC_VER)
223     if (m_nBytesToBeRead == 0)
224     {
225         // Get a windows handle to std input stream
226         HANDLE handle = ::GetStdHandle(STD_INPUT_HANDLE);
227         DWORD nBytesWaiting = 0;
228
229         // Ask how many bytes are available
230         if (::PeekNamedPipe(handle, nullptr, 0, nullptr, &nBytesWaiting, nullptr) == FALSE)
231         {
232             // This can occur when the client i.e. Eclipse closes the stdin stream 'cause it deems its work is finished
233             // for that debug session. May be we should be handling SIGKILL somehow?
234             const CMIUtilString osErrMsg(CMIUtilSystemWindows().GetOSLastError().StripCRAll());
235             SetErrorDescription(CMIUtilString::Format(MIRSRC(IDS_STDIN_ERR_CHKING_BYTE_AVAILABLE), osErrMsg.c_str()));
236             return MIstatus::failure;
237         }
238
239         // Save the number of bytes to be read so that we can check if input is available to be read
240         m_nBytesToBeRead = nBytesWaiting;
241
242         // Return state of whether bytes are waiting or not
243         vwbAvail = (nBytesWaiting > 0);
244     }
245 #endif // #if defined( _MSC_VER )
246
247     return MIstatus::success;
248 }
249
250 //++ ------------------------------------------------------------------------------------
251 // Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
252 // Type:    Method.
253 // Args:    vwErrMsg    - (W) Empty string ok or error description.
254 // Return:  MIchar * - text buffer pointer or NULL on failure.
255 // Throws:  None.
256 //--
257 const MIchar *
258 CMICmnStreamStdinWindows::ReadLine(CMIUtilString &vwErrMsg)
259 {
260     vwErrMsg.clear();
261
262     // Read user input
263     const MIchar *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
264     if (pText == nullptr)
265     {
266         if (::ferror(m_pStdin) != 0)
267             vwErrMsg = ::strerror(errno);
268         return nullptr;
269     }
270
271     // Subtract the number of bytes read so that we can check if input is available to be read
272     m_nBytesToBeRead = m_nBytesToBeRead - ::strlen(pText);
273
274     // Strip off new line characters
275     for (MIchar *pI = m_pCmdBuffer; *pI != '\0'; pI++)
276     {
277         if ((*pI == '\n') || (*pI == '\r'))
278         {
279             *pI = '\0';
280             break;
281         }
282     }
283
284     return pText;
285 }