amath  1.8.5
Simple command line calculator
console_windows.cpp
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * Project homepage:
26  * https://amath.innolan.net
27  *
28  */
29 
30 #include "amath.h"
31 
32 #if defined(WINDOWS)
33 #include "amathc.h"
34 #include "console.h"
35 #include "console_windows.h"
36 #include "lib/charval.h"
37 #include "lib/aengine.h"
38 #include "main/evaluator.h"
39 #include "loc/text.h"
40 #include <windows.h>
41 
42 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
43 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
44 #endif
45 #ifndef DISABLE_NEWLINE_AUTO_RETURN
46 #define DISABLE_NEWLINE_AUTO_RETURN 0x0008
47 #endif
48 #ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
49 #define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
50 #endif
51 
52 #define IN_DEFAULT
53  ENABLE_PROCESSED_INPUT
54 
55 #define IN_ANSI
56  ENABLE_PROCESSED_INPUT |
57  ENABLE_VIRTUAL_TERMINAL_INPUT
58 
59 #define OUT_DEFAULT
60  ENABLE_PROCESSED_OUTPUT |
61  ENABLE_WRAP_AT_EOL_OUTPUT
62 
63 #define OUT_ANSI1
64  ENABLE_PROCESSED_OUTPUT |
65  ENABLE_WRAP_AT_EOL_OUTPUT |
66  ENABLE_VIRTUAL_TERMINAL_PROCESSING |
67  DISABLE_NEWLINE_AUTO_RETURN
68 
69 #define OUT_ANSI2
70  ENABLE_PROCESSED_OUTPUT |
71  ENABLE_WRAP_AT_EOL_OUTPUT |
72  ENABLE_VIRTUAL_TERMINAL_PROCESSING
73 
74 #define OUT_WHITE
75  FOREGROUND_INTENSITY |
76  FOREGROUND_RED |
77  FOREGROUND_GREEN |
78  FOREGROUND_BLUE
79 
80 WindowsConsole::WindowsConsole(const char* prompt, CharValidator* validator) :
81  ConsoleBase(prompt), line(nullptr), exit(false)
82 {
83  proc = new AnsiConoleEngine(prompt, validator);
84 }
85 
86 WindowsConsole::~WindowsConsole()
87 {
88 }
89 
90 void WindowsConsole::Clear()
91 {
92  if (ansiMode)
93  {
94  ConsoleBase::Clear();
95  }
96  else
97  {
98  HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
99  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
100  if (in == INVALID_HANDLE_VALUE || out == INVALID_HANDLE_VALUE)
101  {
102  return;
103  }
104 
105  system("cls");
106  SetConsoleMode(in, IN_DEFAULT);
107  SetConsoleMode(out, OUT_DEFAULT);
108  }
109 }
110 
111 void WindowsConsole::StartMessage()
112 {
113  if (ansiMode)
114  {
115  ConsoleBase::StartMessage();
116  }
117  else
118  {
119  CONSOLE_SCREEN_BUFFER_INFO old;
120  WORD oldColor;
121 
122  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
123  if (out == INVALID_HANDLE_VALUE)
124  {
125  ConsoleBase::StartMessage();
126  return;
127  }
128 
129  if (!GetConsoleScreenBufferInfo(out, &old))
130  {
131  ConsoleBase::StartMessage();
132  return;
133  }
134 
135  oldColor = old.wAttributes;
136 
137  if (!SetConsoleTextAttribute(out, OUT_WHITE))
138  {
139  ConsoleBase::StartMessage();
140  return;
141  }
142 
143  WriteString(INTROMSG);
144  ResetConsole();
145 
146  SetConsoleTextAttribute(out, oldColor);
147  }
148 }
149 
150 void WindowsConsole::ShowVersion()
151 {
152  if (ansiMode)
153  {
154  ConsoleBase::ShowVersion();
155  }
156  else
157  {
158  CONSOLE_SCREEN_BUFFER_INFO old;
159  WORD oldColor;
160 
161  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
162  if (out == INVALID_HANDLE_VALUE)
163  {
164  ConsoleBase::ShowVersion();
165  return;
166  }
167 
168  if (!GetConsoleScreenBufferInfo(out, &old))
169  {
170  ConsoleBase::ShowVersion();
171  return;
172  }
173 
174  oldColor = old.wAttributes;
175 
176  if (!SetConsoleTextAttribute(out, OUT_WHITE))
177  {
178  ConsoleBase::ShowVersion();
179  return;
180  }
181 
182  WriteString(GetVersionText());
183  ResetConsole();
184 
185  SetConsoleTextAttribute(out, oldColor);
186 
187  WriteString(NEWLINE);
188  WriteString(GetCompilerText());
189  WriteString(NEWLINE);
190  ResetConsole();
191  }
192 }
193 
194 bool WindowsConsole::Open()
195 {
196  HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
197  if (in == INVALID_HANDLE_VALUE)
198  {
199  return false;
200  }
201 
202  if (!GetConsoleMode(in, &oldInMode))
203  {
204  return false;
205  }
206 
207  if (!SetConsoleMode(in, IN_DEFAULT))
208  {
209  return false;
210  }
211 
212  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
213  if (out == INVALID_HANDLE_VALUE)
214  {
215  return false;
216  }
217 
218  if (!GetConsoleMode(out, &oldOutMode))
219  {
220  return false;
221  }
222 
223  if (!SetConsoleMode(out, OUT_DEFAULT))
224  {
225  return false;
226  }
227 
228  return true;
229 }
230 
231 void WindowsConsole::Close()
232 {
233  HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
234  if (in == INVALID_HANDLE_VALUE)
235  {
236  return;
237  }
238  SetConsoleMode(in, oldInMode);
239 
240  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
241  if (out == INVALID_HANDLE_VALUE)
242  {
243  return;
244  }
245  SetConsoleMode(in, oldOutMode);
246 }
247 
248 bool WindowsConsole::SetAnsiMode(bool value)
249 {
250  HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
251  if (in == INVALID_HANDLE_VALUE)
252  {
253  ConsoleBase::SetAnsiMode(false);
254  return false;
255  }
256 
257  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
258  if (out == INVALID_HANDLE_VALUE)
259  {
260  ConsoleBase::SetAnsiMode(false);
261  return false;
262  }
263 
264  // Disable virtual terminal
265  if (!value)
266  {
267  SetConsoleMode(in, IN_DEFAULT);
268  SetConsoleMode(out, OUT_DEFAULT);
269  ConsoleBase::SetAnsiMode(false);
270  proc->Disable();
271  return true;
272  }
273 
274  bool success = true;
275 
276  // Enable virtual terminal
277  if (!SetConsoleMode(out, OUT_ANSI1))
278  {
279  if (!SetConsoleMode(out, OUT_ANSI2))
280  {
281  success = false;
282  }
283  }
284 
285  if (!SetConsoleMode(in, IN_ANSI))
286  {
287  success = false;
288  }
289 
290  if (!success)
291  {
292  SetConsoleMode(in, IN_DEFAULT);
293  SetConsoleMode(out, OUT_DEFAULT);
294  proc->Disable();
295  }
296 
297  ConsoleBase::SetAnsiMode(success);
298  proc->Enable();
299  return success;
300 }
301 
302 void WindowsConsole::Start()
303 {
304  exit = false;
305  StartMessage();
306 
307  while (!exit)
308  {
309  Prompt();
310  ReadLine();
311  Evaluator* evaluator = new Evaluator(line);
312  evaluator->Evaluate();
313  const char* res = evaluator->GetResult();
314  Write(res, StrLen(res));
315  ResetConsole();
316  delete evaluator;
317  }
318 }
319 
320 void WindowsConsole::Exit()
321 {
322  exit = true;
323 }
324 
325 void WindowsConsole::SetPrompt(const char* string)
326 {
327  ConsoleBase::SetPrompt(string);
328  proc->SetPrompt(string);
329 }
330 
331 void WindowsConsole::ReadLine()
332 {
333  DWORD count;
334  HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
335  if (in == INVALID_HANDLE_VALUE)
336  {
337  return;
338  }
339 
340  char inchar;
341  proc->StartInput();
342  while (!proc->InputDone())
343  {
344  ReadConsole(in, &inchar, 1, &count, nullptr);
345  const char* out = proc->ProcessChar(inchar);
346  WriteString(out);
347  }
348 
349  line = proc->GetLine();
350 }
351 
352 void WindowsConsole::WriteString(const char* string)
353 {
354  Write(string, StrLen(string));
355 }
356 
357 void WindowsConsole::Write(const char* string, unsigned int length)
358 {
359  DWORD count;
360  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
361  if (out == INVALID_HANDLE_VALUE)
362  {
363  return;
364  }
365 
366  WriteConsoleA(out, string, length, &count, nullptr);
367 }
368 
369 #endif