ConsoleUI.cc Source File

Back to the index.

ConsoleUI.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2019 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <signal.h>
29 #include <unistd.h>
30 #include <iostream>
31 
32 #include "misc.h"
33 #include "ConsoleUI.h"
34 #include "GXemul.h"
35 
36 
38  : UI(gxemul)
39  , m_consoleIsInitialized(false)
40 {
41 }
42 
43 
45 {
46  // Restore the terminal mode:
47  if (m_consoleIsInitialized)
48  tcsetattr(STDIN_FILENO, TCSANOW, &m_oldTermios);
49 }
50 
51 
52 // Note: Use of global GXemul pointer!
53 static GXemul* g_GXemul;
54 static struct termios g_curTermios;
55 
56 static void ReshowCurrentCommandBuffer()
57 {
58  if (g_GXemul->GetRunState() == GXemul::Paused) {
59  // Reshow the prompt and the current command line:
61  std::cout.flush();
62  }
63 }
64 
65 /**
66  * \brief CTRL-C handler which sets the run state to Paused.
67  */
68 extern "C" void ConsoleUI_SIGINT_Handler(int n)
69 {
70  if (g_GXemul->IsInterrupting())
71  std::cout << "^C (already attempting to interrupt, please wait)\n";
72  else
73  std::cout << "^C\n";
74 
75  g_GXemul->Interrupt();
76 
78  ReshowCurrentCommandBuffer();
79 
80  signal(SIGINT, ConsoleUI_SIGINT_Handler);
81 }
82 
83 /**
84  * \brief Restore terminal settings after a CTRL-Z.
85  *
86  * If the user presses CTRL-Z (to stop the emulator process) and then
87  * continues, the termios settings might have been invalidated. This
88  * function restores them.
89  */
90 extern "C" void ConsoleUI_SIGCONT_Handler(int n)
91 {
92  tcsetattr(STDIN_FILENO, TCSANOW, &g_curTermios);
93  ReshowCurrentCommandBuffer();
94  signal(SIGCONT, ConsoleUI_SIGCONT_Handler);
95 }
96 
97 
99 {
100  if (m_consoleIsInitialized)
101  return;
102 
103  tcgetattr(STDIN_FILENO, &m_oldTermios);
104  m_currentTermios = m_oldTermios;
105 
106  // Set the terminal mode:
107  m_currentTermios.c_lflag &= ~ICANON;
108  m_currentTermios.c_cc[VTIME] = 0;
109  m_currentTermios.c_cc[VMIN] = 1;
110  m_currentTermios.c_lflag &= ~ECHO;
111 
112  tcsetattr(STDIN_FILENO, TCSANOW, &m_currentTermios);
113 
114  // Signal handlers for CTRL-C and CTRL-Z.
115  // Note: Using a global GXemul instance pointer!
116  g_GXemul = m_gxemul;
117  g_curTermios = m_currentTermios;
118  signal(SIGINT, ConsoleUI_SIGINT_Handler);
119  signal(SIGCONT, ConsoleUI_SIGCONT_Handler);
120 
121  m_consoleIsInitialized = true;
122 }
123 
124 
126 {
127  // Empty.
128 }
129 
130 
132 {
133  std::cout << GXemul::Version() << "\n";
134 }
135 
136 
137 static vector<string> SplitIntoRows(const string &msg, bool addEmptyLines)
138 {
139  // This is slow and hackish, but works.
140  vector<string> result;
141  string line;
142 
143  for (size_t i=0, n=msg.length(); i<n; i++) {
144  stringchar ch = msg[i];
145  if (ch == '\n') {
146  if (line.length() > 0 || addEmptyLines)
147  result.push_back(line);
148  line = "";
149  } else {
150  line += ch;
151  }
152  }
153 
154  if (line.length() > 0)
155  result.push_back(line);
156 
157  return result;
158 }
159 
160 
161 void ConsoleUI::ShowDebugMessage(const string& msg)
162 {
163  vector<string> lines = SplitIntoRows(msg, true);
164 
165  for (size_t i=0; i<lines.size(); ++i) {
167  if (isatty(fileno(stdout)))
168  std::cout << "\e[1m" << m_indentationMsg << lines[i] << "\e[0m\n";
169  else
170  std::cout << "[ " << m_indentationMsg << lines[i] << " ]\n";
171  } else {
172  std::cout << m_indentationMsg << lines[i] << "\n";
173  }
174 
175  // Replace indentation string with spaces after first
176  // line of output:
177  for (size_t j=m_indentationMsg.length(); j>0; --j)
178  m_indentationMsg[j-1] = ' ';
179  }
180 
181  std::cout.flush();
182 }
183 
184 
185 void ConsoleUI::ShowDebugMessage(Component* component, const string& msg)
186 {
187  if (m_gxemul->GetQuietMode())
188  return;
189 
190  stringstream ss;
191  string componentName = component->GenerateShortestPossiblePath();
192 
193  vector<string> lines = SplitIntoRows(msg, false);
194 
195  // cpu0: blahlonger
196  // blahshort
197  size_t i;
198  string spaces = "";
199  for (i=0; i<componentName.length() + 2; i++)
200  spaces += " ";
201 
202  ss << componentName << ": " << lines[0] << "\n";
203 
204  for (i=1; i<lines.size(); ++i)
205  ss << spaces << lines[i] << "\n";
206 
207  ShowDebugMessage(ss.str());
208 }
209 
210 
211 void ConsoleUI::ShowCommandMessage(const string& command)
212 {
213  // Not for ConsoleUI; commands entered by the user are
214  // displayed anyway (echoing characters while the command
215  // was entered).
216 }
217 
218 
219 void ConsoleUI::FatalError(const string& msg)
220 {
221  std::cerr << msg;
222  std::cerr.flush();
223 }
224 
225 
226 void ConsoleUI::RedisplayInputLine(const string& inputline,
227  size_t cursorPosition)
228 {
229  std::cout << "\rGXemul> " << inputline << " \rGXemul> ";
230 
231  for (size_t pos = 0; pos < cursorPosition; pos++)
232  std::cout << (string() + inputline[pos]);
233 
234  std::cout.flush();
235 }
236 
237 
238 /**
239  * \brief Read a key from stdin, blocking.
240  *
241  * @return The key read from stdin.
242  */
243 static stringchar ReadKey()
244 {
245  return std::cin.get();
246 }
247 
248 
249 void ConsoleUI::ReadAndExecuteCommand()
250 {
251  // Initial dummy addkey, to show the input line with the prompt, etc.:
253 
254  while (!m_gxemul->GetCommandInterpreter().AddKey(ReadKey()))
255  ;
256 }
257 
258 
260 {
261  std::cout << "\n";
262  std::cout.flush();
263 }
264 
265 
267 {
268 }
269 
270 
272 {
273  GXemul::RunState oldRunState = m_gxemul->GetRunState();
274 
275  while (m_gxemul->GetRunState() != GXemul::Quitting) {
276  GXemul::RunState runState = m_gxemul->GetRunState();
277 
278  switch (runState) {
279 
281  case GXemul::Running:
282  // Switching from Paused state to running? Then
283  // we need to:
284  // 1) flush old cached state
285  // 2) perform pre-run checks.
286  if (oldRunState == GXemul::Paused) {
288 
290  FatalError("Pre-run check failed.\n");
292  runState = m_gxemul->GetRunState();
293  break;
294  }
295  }
296 
297  m_gxemul->Execute();
298  break;
299 
300  case GXemul::Quitting:
301  break;
302 
303  case GXemul::Paused:
304  // When issuing interactive commands, "anything" can
305  // happen to the component tree, and thus any cached
306  // state quickly becomes untrustworthy. Let's flush it.
308 
309  ReadAndExecuteCommand();
310  break;
311  }
312 
313  oldRunState = runState;
314  }
315 
316  return 0;
317 }
318 
Component::PreRunCheck
bool PreRunCheck(GXemul *gxemul)
Checks the state of this component and all its children, before starting execution.
Definition: Component.cc:298
ConsoleUI::InputLineDone
virtual void InputLineDone()
Executed by the CommandInterpreter when a line has been completed (with a newline).
Definition: ConsoleUI.cc:259
ConsoleUI.h
GXemul::Running
@ Running
Definition: GXemul.h:61
ConsoleUI::ShowCommandMessage
virtual void ShowCommandMessage(const string &command)
Does nothing for the ConsoleUI.
Definition: ConsoleUI.cc:211
stringchar
char stringchar
Definition: misc.h:59
GXemul::IsInterrupting
bool IsInterrupting() const
Returns whether or not the current emulation is being interrupted.
Definition: GXemul.h:178
UI::m_gxemul
GXemul * m_gxemul
Definition: UI.h:208
GXemul
The main emulator class.
Definition: GXemul.h:55
CommandInterpreter::AddKey
bool AddKey(stringchar key)
Adds a character (keypress) to the current command buffer.
Definition: CommandInterpreter.cc:381
ConsoleUI::MainLoop
virtual int MainLoop()
Runs the text console main loop.
Definition: ConsoleUI.cc:271
GXemul::GetCommandInterpreter
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
Definition: GXemul.cc:623
GXemul::Quitting
@ Quitting
Definition: GXemul.h:62
ConsoleUI::Initialize
virtual void Initialize()
Initializes the terminal for blocking, non-echo I/O.
Definition: ConsoleUI.cc:98
ConsoleUI::ConsoleUI
ConsoleUI(GXemul *gxemul)
Constructs a text console UI instance.
Definition: ConsoleUI.cc:37
GXemul::GetRootComponent
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:659
UI
Base class for a User Interface.
Definition: UI.h:42
GXemul::SetRunState
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:733
misc.h
ConsoleUI_SIGCONT_Handler
void ConsoleUI_SIGCONT_Handler(int n)
Restore terminal settings after a CTRL-Z.
Definition: ConsoleUI.cc:90
ConsoleUI::FatalError
virtual void FatalError(const string &msg)
Shows a fatal error message, by printing it to stderr.
Definition: ConsoleUI.cc:219
GXemul::Execute
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:886
ConsoleUI::~ConsoleUI
virtual ~ConsoleUI()
Definition: ConsoleUI.cc:44
ConsoleUI_SIGINT_Handler
void ConsoleUI_SIGINT_Handler(int n)
CTRL-C handler which sets the run state to Paused.
Definition: ConsoleUI.cc:68
ConsoleUI::ShowStartupBanner
virtual void ShowStartupBanner()
Prints the text console startup banner.
Definition: ConsoleUI.cc:131
Component::GenerateShortestPossiblePath
string GenerateShortestPossiblePath() const
Generates a short string representation of the path to the Component.
Definition: Component.cc:721
GXemul::GetRunState
RunState GetRunState() const
Gets the current RunState.
Definition: GXemul.cc:741
GXemul::Paused
@ Paused
Definition: GXemul.h:59
Component
A Component is a node in the configuration tree that makes up an emulation setup.
Definition: Component.h:64
GXemul::SingleStepping
@ SingleStepping
Definition: GXemul.h:60
ConsoleUI::Shutdown
virtual void Shutdown()
Shuts down the UI.
Definition: ConsoleUI.cc:266
ConsoleUI::ShowDebugMessage
virtual void ShowDebugMessage(const string &msg)
Shows a debug message, by printing it to stdout.
Definition: ConsoleUI.cc:161
ConsoleUI::RedisplayInputLine
virtual void RedisplayInputLine(const string &inputline, size_t cursorPosition)
Redisplays the interactive command input line.
Definition: ConsoleUI.cc:226
UI::m_indentationMsg
string m_indentationMsg
Definition: UI.h:209
CommandInterpreter::ReshowCurrentCommandBuffer
void ReshowCurrentCommandBuffer()
Re-displays the current command buffer.
Definition: CommandInterpreter.cc:638
ConsoleUI::UpdateUI
virtual void UpdateUI()
Updates UI items. Not used for ConsoleUI.
Definition: ConsoleUI.cc:125
Component::FlushCachedState
void FlushCachedState()
Resets the cached state of this component and all its children.
Definition: Component.cc:317
GXemul::RunState
RunState
Definition: GXemul.h:58
GXemul::Version
static string Version()
Returns the GXemul version string.
Definition: GXemul.cc:501
GXemul::GetQuietMode
bool GetQuietMode() const
Gets the current quiet mode setting.
Definition: GXemul.cc:780
GXemul::Interrupt
void Interrupt()
Interrupts emulation.
Definition: GXemul.cc:720
CommandInterpreter::ClearCurrentCommandBuffer
void ClearCurrentCommandBuffer()
Clears the current command buffer.
Definition: CommandInterpreter.cc:655
GXemul.h

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18