ConsoleUI.cc Source File

Back to the index.

ConsoleUI.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2010 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  std::cout << "[ " << m_indentationMsg << lines[i] << " ]\n";
168  else
169  std::cout << m_indentationMsg << lines[i] << "\n";
170 
171  // Replace indentation string with spaces after first
172  // line of output:
173  for (size_t j=m_indentationMsg.length(); j>0; --j)
174  m_indentationMsg[j-1] = ' ';
175  }
176 
177  std::cout.flush();
178 }
179 
180 
181 void ConsoleUI::ShowDebugMessage(Component* component, const string& msg)
182 {
183  if (m_gxemul->GetQuietMode())
184  return;
185 
186  stringstream ss;
187  string componentName = component->GenerateShortestPossiblePath();
188 
189  vector<string> lines = SplitIntoRows(msg, false);
190 
191  // cpu0: blahlonger
192  // blahshort
193  size_t i;
194  string spaces = "";
195  for (i=0; i<componentName.length() + 2; i++)
196  spaces += " ";
197 
198  ss << componentName << ": " << lines[0] << "\n";
199 
200  for (i=1; i<lines.size(); ++i)
201  ss << spaces << lines[i] << "\n";
202 
203  ShowDebugMessage(ss.str());
204 }
205 
206 
207 void ConsoleUI::ShowCommandMessage(const string& command)
208 {
209  // Not for ConsoleUI; commands entered by the user are
210  // displayed anyway (echoing characters while the command
211  // was entered).
212 }
213 
214 
215 void ConsoleUI::FatalError(const string& msg)
216 {
217  std::cerr << msg;
218  std::cerr.flush();
219 }
220 
221 
222 void ConsoleUI::RedisplayInputLine(const string& inputline,
223  size_t cursorPosition)
224 {
225  std::cout << "\rGXemul> " << inputline << " \rGXemul> ";
226 
227  for (size_t pos = 0; pos < cursorPosition; pos++)
228  std::cout << (string() + inputline[pos]);
229 
230  std::cout.flush();
231 }
232 
233 
234 /**
235  * \brief Read a key from stdin, blocking.
236  *
237  * @return The key read from stdin.
238  */
239 static stringchar ReadKey()
240 {
241  return std::cin.get();
242 }
243 
244 
245 void ConsoleUI::ReadAndExecuteCommand()
246 {
247  // Initial dummy addkey, to show the input line with the prompt, etc.:
249 
250  while (!m_gxemul->GetCommandInterpreter().AddKey(ReadKey()))
251  ;
252 }
253 
254 
256 {
257  std::cout << "\n";
258  std::cout.flush();
259 }
260 
261 
263 {
264 }
265 
266 
268 {
269  GXemul::RunState oldRunState = m_gxemul->GetRunState();
270 
271  while (m_gxemul->GetRunState() != GXemul::Quitting) {
272  GXemul::RunState runState = m_gxemul->GetRunState();
273 
274  switch (runState) {
275 
277  case GXemul::Running:
278  // Switching from Paused state to running? Then
279  // we need to:
280  // 1) flush old cached state
281  // 2) perform pre-run checks.
282  if (oldRunState == GXemul::Paused) {
284 
286  FatalError("Pre-run check failed.\n");
288  runState = m_gxemul->GetRunState();
289  break;
290  }
291  }
292 
293  m_gxemul->Execute();
294  break;
295 
296  case GXemul::Quitting:
297  break;
298 
299  case GXemul::Paused:
300  // When issuing interactive commands, "anything" can
301  // happen to the component tree, and thus any cached
302  // state quickly becomes untrustworthy. Let's flush it.
304 
305  ReadAndExecuteCommand();
306  break;
307  }
308 
309  oldRunState = runState;
310  }
311 
312  return 0;
313 }
314 
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:741
void ClearCurrentCommandBuffer()
Clears the current command buffer.
RunState GetRunState() const
Gets the current RunState.
Definition: GXemul.cc:749
virtual void ShowDebugMessage(const string &msg)
Shows a debug message, by printing it to stdout.
Definition: ConsoleUI.cc:161
bool GetQuietMode() const
Gets the current quiet mode setting.
Definition: GXemul.cc:788
void Interrupt()
Interrupts emulation.
Definition: GXemul.cc:728
char stringchar
Definition: misc.h:59
virtual void ShowStartupBanner()
Prints the text console startup banner.
Definition: ConsoleUI.cc:131
string GenerateShortestPossiblePath() const
Generates a short string representation of the path to the Component.
Definition: Component.cc:721
virtual void InputLineDone()
Executed by the CommandInterpreter when a line has been completed (with a newline).
Definition: ConsoleUI.cc:255
void ConsoleUI_SIGINT_Handler(int n)
CTRL-C handler which sets the run state to Paused.
Definition: ConsoleUI.cc:68
static string Version()
Returns the GXemul version string.
Definition: GXemul.cc:509
The main emulator class.
Definition: GXemul.h:54
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
Definition: GXemul.cc:631
virtual void Shutdown()
Shuts down the UI.
Definition: ConsoleUI.cc:262
virtual void Initialize()
Initializes the terminal for blocking, non-echo I/O.
Definition: ConsoleUI.cc:98
RunState
Definition: GXemul.h:57
GXemul * m_gxemul
Definition: UI.h:208
virtual void ShowCommandMessage(const string &command)
Does nothing for the ConsoleUI.
Definition: ConsoleUI.cc:207
A Component is a node in the configuration tree that makes up an emulation setup. ...
Definition: Component.h:62
bool PreRunCheck(GXemul *gxemul)
Checks the state of this component and all its children, before starting execution.
Definition: Component.cc:298
void ConsoleUI_SIGCONT_Handler(int n)
Restore terminal settings after a CTRL-Z.
Definition: ConsoleUI.cc:90
void FlushCachedState()
Resets the cached state of this component and all its children.
Definition: Component.cc:317
bool AddKey(stringchar key)
Adds a character (keypress) to the current command buffer.
bool IsInterrupting() const
Returns whether or not the current emulation is being interrupted.
Definition: GXemul.h:178
void ReshowCurrentCommandBuffer()
Re-displays the current command buffer.
virtual void UpdateUI()
Updates UI items. Not used for ConsoleUI.
Definition: ConsoleUI.cc:125
virtual ~ConsoleUI()
Definition: ConsoleUI.cc:44
ConsoleUI(GXemul *gxemul)
Constructs a text console UI instance.
Definition: ConsoleUI.cc:37
virtual void RedisplayInputLine(const string &inputline, size_t cursorPosition)
Redisplays the interactive command input line.
Definition: ConsoleUI.cc:222
virtual void FatalError(const string &msg)
Shows a fatal error message, by printing it to stderr.
Definition: ConsoleUI.cc:215
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:667
Base class for a User Interface.
Definition: UI.h:40
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:894
string m_indentationMsg
Definition: UI.h:209
virtual int MainLoop()
Runs the text console main loop.
Definition: ConsoleUI.cc:267

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13