Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
console.c
Go to the documentation of this file.
1 /* Xep128: Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
2  Copyright (C)2016 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3  http://xep128.lgb.hu/
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 
20 #include "xep128.h"
21 #include "console.h"
22 #include "emu_monitor.h"
23 
24 #include <SDL.h>
25 
26 #ifdef NO_CONSOLE
27 int console_is_open = 0;
28 void console_close_window ( void ) {
29 }
30 void console_close_window_on_exit ( void ) {
31 }
32 void console_open_window ( void ) {
33 }
34 void console_monitor_ready ( void ) {
35 }
36 #else
37 
38 
39 #ifdef _WIN32
40 #include <windows.h>
41 #include <stdio.h>
42 #include <io.h>
43 #include <fcntl.h>
44 #else
45 #ifndef XEMU_HAS_READLINE
46 #error "We need libreadline for this target/platform, but XEMU_HAS_READLINE is not defined. Maybe libreadline cannot be detected?"
47 #endif
48 #include <readline/readline.h>
49 #include <readline/history.h>
50 #endif
51 
52 #define USE_MONITOR 1
53 
55 static int ok_for_monitor = 0;
56 static volatile int monitor_running = 0;
57 static SDL_Thread *mont = NULL;
58 
59 
60 
61 
62 /* Monitor thread waits for console input and enqueues the request.
63  The thread is NOT executes the command itself! Even the answer
64  is printed by the main thread already!
65  Honestly, I was lazy, this may be also implemented in the main
66  main thread, with select() based scheme / async I/O on UNIX, but I have
67  no idea about Windows ... */
68 static int console_monitor_thread ( void *ptr )
69 {
70  printf("Welcome to " WINDOW_TITLE " monitor. Use \"help\" for help" NL);
71  while (monitor_running) {
72  char *p;
73 #ifdef _WIN32
74  char buffer[256];
75  printf(WINDOW_TITLE "> ");
76  p = fgets(buffer, sizeof buffer, stdin);
77 #else
78  p = readline(WINDOW_TITLE "> ");
79 #endif
80  if (p == NULL) {
81  SDL_Delay(10); // avoid flooding the CPU in case of I/O problem for fgets ...
82  } else {
83  // Queue the command!
84  while (monitor_queue_command(p) && monitor_running)
85  SDL_Delay(10); // avoid flooding the CPU in case of not processed-yet command in the "queue" buffer
86 #ifndef _WIN32
87  if (p[0])
88  add_history(p);
89  free(p);
90 #endif
91  // Wait for command completed
92  while (monitor_queue_used() && monitor_running)
93  SDL_Delay(10); // avoid flooding the CPU while waiting for command being processed and answered on the console
94  }
95  }
96  printf("MONITOR: thread is about to exit" NL);
97  return 0;
98 }
99 
100 
101 
102 static void monitor_start ( void )
103 {
104  if (!ok_for_monitor || !console_is_open || monitor_running || !USE_MONITOR)
105  return;
106  DEBUGPRINT("MONITOR: start" NL);
107  monitor_running = 1;
108  mont = SDL_CreateThread(console_monitor_thread, WINDOW_TITLE " monitor", NULL);
109  if (mont == NULL)
110  monitor_running = 0;
111 }
112 
113 
114 
115 static int monitor_stop ( void )
116 {
117  int ret;
118  if (!monitor_running)
119  return 0;
120  DEBUGPRINT("MONITOR: stop" NL);
121  monitor_running = 0;
122  if (mont != NULL) {
123  printf(NL NL "*** PRESS ENTER TO EXIT ***" NL);
124  // Though Info window here is overkill, I am still interested why it causes a segfault when I've tried ...
125  //INFO_WINDOW("Monitor runs on console. You must press ENTER there to continue");
126  SDL_WaitThread(mont, &ret);
127  mont = NULL;
128  DEBUGPRINT("MONITOR: thread joined, status code is %d" NL, ret);
129  }
130  return 1;
131 }
132 
133 
134 
135 void console_open_window ( void )
136 {
137 #ifdef _WIN32
138  int hConHandle;
139  HANDLE lStdHandle;
140  CONSOLE_SCREEN_BUFFER_INFO coninfo;
141  FILE *fp;
142  if (console_is_open)
143  return;
144  console_is_open = 0;
145  FreeConsole();
146  if (!AllocConsole()) {
147  ERROR_WINDOW("Cannot allocate windows console!");
148  return;
149  }
150  SetConsoleTitle(WINDOW_TITLE " console");
151  // set the screen buffer to be big enough to let us scroll text
152  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
153  coninfo.dwSize.Y = 1024;
154  //coninfo.dwSize.X = 100;
155  SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
156  // redirect unbuffered STDOUT to the console
157  lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
158  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
159  fp = _fdopen( hConHandle, "w" );
160  *stdout = *fp;
161  setvbuf( stdout, NULL, _IONBF, 0 );
162  // redirect unbuffered STDIN to the console
163  lStdHandle = GetStdHandle(STD_INPUT_HANDLE);
164  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
165  fp = _fdopen( hConHandle, "r" );
166  *stdin = *fp;
167  setvbuf( stdin, NULL, _IONBF, 0 );
168  // redirect unbuffered STDERR to the console
169  lStdHandle = GetStdHandle(STD_ERROR_HANDLE);
170  hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
171  fp = _fdopen( hConHandle, "w" );
172  *stderr = *fp;
173  setvbuf( stderr, NULL, _IONBF, 0 );
174  // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
175  // ios::sync_with_stdio();
176  // Attributes
177  //SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
178  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
179  SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
180  SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
181  DEBUGPRINT("WINDOWS: console is open" NL);
182 #endif
183  console_is_open = 1;
184  monitor_start();
185 }
186 
187 
188 
189 void console_close_window ( void )
190 {
191  if (!console_is_open)
192  return;
193  monitor_stop();
194 #ifdef _WIN32
195  if (!FreeConsole())
196  ERROR_WINDOW("Cannot release windows console!");
197  else
198  console_is_open = 0;
199 #else
200  console_is_open = 0;
201 #endif
202 }
203 
204 
205 
207 {
208 #ifdef _WIN32
209  if (console_is_open && !monitor_stop())
210  INFO_WINDOW("Click to close console window");
211 #else
212  monitor_stop();
213 #endif
215 }
216 
217 
218 
220 {
221  ok_for_monitor = 1;
222  monitor_start();
223 }
224 #endif
console_is_open
int console_is_open
Definition: console.c:54
console.h
monitor_queue_used
int monitor_queue_used(void)
Definition: emu_monitor.c:784
monitor_stop
int monitor_stop(void)
Definition: emu_monitor.c:897
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
console_open_window
void console_open_window(void)
Definition: console.c:135
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
NL
#define NL
Definition: fat32.c:37
console_close_window
void console_close_window(void)
Definition: console.c:189
xep128.h
USE_MONITOR
#define USE_MONITOR
Definition: console.c:52
monitor_queue_command
int monitor_queue_command(char *buffer)
Definition: emu_monitor.c:791
monitor_start
int monitor_start(void)
Definition: emu_monitor.c:873
console_monitor_ready
void console_monitor_ready(void)
Definition: console.c:219
WINDOW_TITLE
#define WINDOW_TITLE
Definition: xep128.h:50
emu_monitor.h
console_close_window_on_exit
void console_close_window_on_exit(void)
Definition: console.c:206