1 //===-- MICmnStreamStdin.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 // Third Party Headers
11 #ifdef _MSC_VER
12 #include <windows.h>
13 #endif
14 #include <string.h>
15
16 // In-house headers:
17 #include "MICmnLog.h"
18 #include "MICmnResources.h"
19 #include "MICmnStreamStdin.h"
20 #include "MICmnStreamStdout.h"
21 #include "MIDriver.h"
22 #include "MIUtilSingletonHelper.h"
23
24 //++
25 //------------------------------------------------------------------------------------
26 // Details: CMICmnStreamStdin constructor.
27 // Type: Method.
28 // Args: None.
29 // Return: None.
30 // Throws: None.
31 //--
CMICmnStreamStdin()32 CMICmnStreamStdin::CMICmnStreamStdin()
33 : m_strPromptCurrent("(gdb)"), m_bShowPrompt(true), m_pCmdBuffer(nullptr) {}
34
35 //++
36 //------------------------------------------------------------------------------------
37 // Details: CMICmnStreamStdin destructor.
38 // Type: Overridable.
39 // Args: None.
40 // Return: None.
41 // Throws: None.
42 //--
~CMICmnStreamStdin()43 CMICmnStreamStdin::~CMICmnStreamStdin() { Shutdown(); }
44
45 //++
46 //------------------------------------------------------------------------------------
47 // Details: Initialize resources for *this Stdin stream.
48 // Type: Method.
49 // Args: None.
50 // Return: MIstatus::success - Functional succeeded.
51 // MIstatus::failure - Functional failed.
52 // Throws: None.
53 //--
Initialize()54 bool CMICmnStreamStdin::Initialize() {
55 m_clientUsageRefCnt++;
56
57 if (m_bInitialized)
58 return MIstatus::success;
59
60 bool bOk = MIstatus::success;
61 CMIUtilString errMsg;
62
63 // Note initialisation order is important here as some resources depend on
64 // previous
65 MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
66 MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
67
68 if (bOk) {
69 m_pCmdBuffer = new char[m_constBufferSize];
70 } else {
71 CMIUtilString strInitError(CMIUtilString::Format(
72 MIRSRC(IDS_MI_INIT_ERR_STREAMSTDIN), errMsg.c_str()));
73 SetErrorDescription(strInitError);
74
75 return MIstatus::failure;
76 }
77 m_bInitialized = bOk;
78
79 return MIstatus::success;
80 }
81
82 //++
83 //------------------------------------------------------------------------------------
84 // Details: Release resources for *this Stdin stream.
85 // Type: Method.
86 // Args: None.
87 // Return: MIstatus::success - Functional succeeded.
88 // MIstatus::failure - Functional failed.
89 // Throws: None.
90 //--
Shutdown()91 bool CMICmnStreamStdin::Shutdown() {
92 if (--m_clientUsageRefCnt > 0)
93 return MIstatus::success;
94
95 if (!m_bInitialized)
96 return MIstatus::success;
97
98 m_bInitialized = false;
99
100 ClrErrorDescription();
101
102 if (m_pCmdBuffer != nullptr) {
103 delete[] m_pCmdBuffer;
104 m_pCmdBuffer = nullptr;
105 }
106
107 bool bOk = MIstatus::success;
108 CMIUtilString errMsg;
109
110 MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg);
111 MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg);
112
113 if (!bOk) {
114 SetErrorDescriptionn(MIRSRC(IDE_MI_SHTDWN_ERR_STREAMSTDIN), errMsg.c_str());
115 }
116
117 return MIstatus::success;
118 }
119
120 //++
121 //------------------------------------------------------------------------------------
122 // Details: Validate and set the text that forms the prompt on the command line.
123 // Type: Method.
124 // Args: vNewPrompt - (R) Text description.
125 // Return: MIstatus::success - Functional succeeded.
126 // MIstatus::failure - Functional failed.
127 // Throws: None.
128 //--
SetPrompt(const CMIUtilString & vNewPrompt)129 bool CMICmnStreamStdin::SetPrompt(const CMIUtilString &vNewPrompt) {
130 if (vNewPrompt.empty()) {
131 const CMIUtilString msg(CMIUtilString::Format(
132 MIRSRC(IDS_STDIN_ERR_INVALID_PROMPT), vNewPrompt.c_str()));
133 CMICmnStreamStdout::Instance().Write(msg);
134 return MIstatus::failure;
135 }
136
137 m_strPromptCurrent = vNewPrompt;
138
139 return MIstatus::success;
140 }
141
142 //++
143 //------------------------------------------------------------------------------------
144 // Details: Retrieve the command line prompt text currently being used.
145 // Type: Method.
146 // Args: None.
147 // Return: const CMIUtilString & - Functional failed.
148 // Throws: None.
149 //--
GetPrompt() const150 const CMIUtilString &CMICmnStreamStdin::GetPrompt() const {
151 return m_strPromptCurrent;
152 }
153
154 //++
155 //------------------------------------------------------------------------------------
156 // Details: Set whether to display optional command line prompt. The prompt is
157 // output to
158 // stdout. Disable it when this may interfere with the client reading
159 // stdout as
160 // input and it tries to interpret the prompt text to.
161 // Type: Method.
162 // Args: vbYes - (R) True = Yes prompt is shown/output to the user
163 // (stdout), false = no prompt.
164 // Return: MIstatus::success - Functional succeeded.
165 // MIstatus::failure - Functional failed.
166 // Throws: None.
167 //--
SetEnablePrompt(const bool vbYes)168 void CMICmnStreamStdin::SetEnablePrompt(const bool vbYes) {
169 m_bShowPrompt = vbYes;
170 }
171
172 //++
173 //------------------------------------------------------------------------------------
174 // Details: Get whether to display optional command line prompt. The prompt is
175 // output to
176 // stdout. Disable it when this may interfere with the client reading
177 // stdout as
178 // input and it tries to interpret the prompt text to.
179 // Type: Method.
180 // Args: None.
181 // Return: bool - True = Yes prompt is shown/output to the user (stdout), false
182 // = no prompt.
183 // Throws: None.
184 //--
GetEnablePrompt() const185 bool CMICmnStreamStdin::GetEnablePrompt() const { return m_bShowPrompt; }
186
187 //++
188 //------------------------------------------------------------------------------------
189 // Details: Wait on new line of data from stdin stream (completed by '\n' or
190 // '\r').
191 // Type: Method.
192 // Args: vwErrMsg - (W) Empty string ok or error description.
193 // Return: char * - text buffer pointer or NULL on failure.
194 // Throws: None.
195 //--
ReadLine(CMIUtilString & vwErrMsg)196 const char *CMICmnStreamStdin::ReadLine(CMIUtilString &vwErrMsg) {
197 vwErrMsg.clear();
198
199 // Read user input
200 const char *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
201 if (pText == nullptr) {
202 #ifdef _MSC_VER
203 // Was Ctrl-C hit?
204 // On Windows, Ctrl-C gives an ERROR_OPERATION_ABORTED as error on the
205 // command-line.
206 // The end-of-file indicator is also set, so without this check we will exit
207 // next if statement.
208 if (::GetLastError() == ERROR_OPERATION_ABORTED)
209 return nullptr;
210 #endif
211 if (::feof(stdin)) {
212 const bool bForceExit = true;
213 CMIDriver::Instance().SetExitApplicationFlag(bForceExit);
214 } else if (::ferror(stdin) != 0)
215 vwErrMsg = ::strerror(errno);
216 return nullptr;
217 }
218
219 // Strip off new line characters
220 for (char *pI = m_pCmdBuffer; *pI != '\0'; pI++) {
221 if ((*pI == '\n') || (*pI == '\r')) {
222 *pI = '\0';
223 break;
224 }
225 }
226
227 return pText;
228 }
229