Windows: move on-demand console to rktio
In GUI-application mode (e.g., running GRacket), a console is allocated on demand if a program tries to use the original ports. Move that on-demand handling into rktio, where it's simpler and works for RacketCS.
This commit is contained in:
parent
982942b258
commit
67b721e5b7
|
@ -144,8 +144,12 @@ static char *get_self_path()
|
|||
}
|
||||
|
||||
static int scheme_utf8_encode(unsigned int *path, int zero_offset, int len,
|
||||
char *dest, int dest_len, int get_utf16)
|
||||
char *dest, int offset, int get_utf16)
|
||||
{
|
||||
int dest_len = 0;
|
||||
if (dest) {
|
||||
dest_len = WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)path, len, NULL, 0, NULL, NULL);
|
||||
}
|
||||
return WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)path, len, dest, dest_len, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
/* Hack: overwrite "y" with "n" in binary to disable checking for another
|
||||
instance of the same app. */
|
||||
char *check_for_another = "yes, please check for another";
|
||||
static int wx_in_terminal = 0;
|
||||
# define MZ_DEFINE_UTF8_MAIN
|
||||
# define PRE_FILTER_CMDLINE_ARGUMENTS
|
||||
static void pre_filter_cmdline_arguments(int *argc, char ***argv);
|
||||
|
@ -69,104 +68,28 @@ static void pre_filter_cmdline_arguments(int *argc, char ***argv);
|
|||
|
||||
#ifdef WIN32
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* stdio to console */
|
||||
/* ---------------------------------------- */
|
||||
# ifdef MZ_PRECISE_GC
|
||||
START_XFORM_SKIP;
|
||||
# endif
|
||||
|
||||
static void MrEdSchemeMessages(char *, ...);
|
||||
static Scheme_Object *stdin_pipe;
|
||||
# include "../start/win_single.inc"
|
||||
|
||||
static HANDLE console_out;
|
||||
static HANDLE console_in;
|
||||
static Scheme_Object *console_inport;
|
||||
static HWND console_hwnd;
|
||||
static int has_stdio, stdio_kills_prog;
|
||||
static HANDLE waiting_sema;
|
||||
static void *orig_signal_handle;
|
||||
static void *orig_break_handle;
|
||||
|
||||
typedef HWND (WINAPI* gcw_proc)();
|
||||
|
||||
static void init_console_in()
|
||||
static void pre_filter_cmdline_arguments(int *argc, char ***argv)
|
||||
{
|
||||
if (!console_in) {
|
||||
console_in = GetStdHandle(STD_INPUT_HANDLE);
|
||||
MZ_REGISTER_STATIC(console_inport);
|
||||
console_inport = scheme_make_fd_input_port((intptr_t)console_in, scheme_intern_symbol("stdin"), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL WINAPI ConsoleHandler(DWORD op)
|
||||
{
|
||||
if (stdio_kills_prog) {
|
||||
ReleaseSemaphore(waiting_sema, 1, NULL);
|
||||
} else {
|
||||
scheme_break_main_thread_at(orig_break_handle);
|
||||
scheme_signal_received_at(orig_signal_handle);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WaitOnConsole()
|
||||
{
|
||||
DWORD wrote;
|
||||
|
||||
stdio_kills_prog = 1;
|
||||
if (console_hwnd) {
|
||||
AppendMenu(GetSystemMenu(console_hwnd, FALSE),
|
||||
MF_STRING,
|
||||
SC_CLOSE,
|
||||
"Close");
|
||||
/* Un-gray the close box: */
|
||||
RedrawWindow(console_hwnd, NULL, NULL,
|
||||
RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
|
||||
}
|
||||
|
||||
WriteConsole(console_out, "\n[Exited. Close box or Ctrl-C closes the console.]\n", 51, &wrote, NULL);
|
||||
|
||||
WaitForSingleObject(waiting_sema, INFINITE);
|
||||
scheme_register_process_global("PLT_WM_IS_GRACKET", (void *)(intptr_t)wm_is_gracket);
|
||||
scheme_register_process_global("PLT_GRACKET_GUID", GRACKET_GUID);
|
||||
}
|
||||
|
||||
static void MrEdSchemeMessages(char *msg, ...)
|
||||
{
|
||||
GC_CAN_IGNORE va_list args;
|
||||
HANDLE console_out;
|
||||
va_list args;
|
||||
|
||||
scheme_ensure_console_ready();
|
||||
|
||||
scheme_start_atomic();
|
||||
va_start(args, msg);
|
||||
|
||||
XFORM_HIDE_EXPR(va_start(args, msg));
|
||||
|
||||
if (!console_out) {
|
||||
AllocConsole();
|
||||
console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (!wx_in_terminal) {
|
||||
has_stdio = 1;
|
||||
waiting_sema = CreateSemaphore(NULL, 0, 1, NULL);
|
||||
orig_signal_handle = scheme_get_signal_handle();
|
||||
orig_break_handle = scheme_get_main_thread_break_handle();
|
||||
SetConsoleCtrlHandler(ConsoleHandler, TRUE);
|
||||
|
||||
{
|
||||
HMODULE hm;
|
||||
gcw_proc gcw;
|
||||
|
||||
hm = LoadLibrary("kernel32.dll");
|
||||
if (hm)
|
||||
gcw = (gcw_proc)GetProcAddress(hm, "GetConsoleWindow");
|
||||
else
|
||||
gcw = NULL;
|
||||
|
||||
if (gcw)
|
||||
console_hwnd = gcw();
|
||||
}
|
||||
|
||||
if (console_hwnd) {
|
||||
EnableMenuItem(GetSystemMenu(console_hwnd, FALSE), SC_CLOSE,
|
||||
MF_BYCOMMAND | MF_GRAYED);
|
||||
RemoveMenu(GetSystemMenu(console_hwnd, FALSE), SC_CLOSE, MF_BYCOMMAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (!msg) {
|
||||
char *s;
|
||||
|
@ -190,9 +113,7 @@ static void MrEdSchemeMessages(char *msg, ...)
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
scheme_end_atomic_no_swap();
|
||||
|
||||
XFORM_HIDE_EXPR(va_end(args));
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void MrEdSchemeMessagesOutput(char *s, intptr_t l)
|
||||
|
@ -201,232 +122,13 @@ static void MrEdSchemeMessagesOutput(char *s, intptr_t l)
|
|||
MrEdSchemeMessages(NULL, s, 0, l);
|
||||
}
|
||||
|
||||
static Scheme_Object *console_reading;
|
||||
|
||||
static void add_console_reading()
|
||||
{
|
||||
Scheme_Thread *thread;
|
||||
thread = scheme_get_current_thread();
|
||||
|
||||
if (!console_reading) {
|
||||
MZ_REGISTER_STATIC(console_reading);
|
||||
console_reading = scheme_make_null();
|
||||
}
|
||||
|
||||
console_reading = scheme_make_pair((Scheme_Object *)thread,
|
||||
console_reading);
|
||||
}
|
||||
|
||||
static void remove_console_reading()
|
||||
{
|
||||
Scheme_Object *p, *prev = NULL;
|
||||
Scheme_Thread *thread;
|
||||
thread = scheme_get_current_thread();
|
||||
|
||||
if (!console_reading)
|
||||
return;
|
||||
|
||||
p = console_reading;
|
||||
while (SCHEME_PAIRP(p)) {
|
||||
if (SAME_OBJ(SCHEME_CAR(p), (Scheme_Object *)thread)) {
|
||||
if (prev)
|
||||
SCHEME_CDR(prev) = SCHEME_CDR(p);
|
||||
else
|
||||
console_reading = SCHEME_CDR(p);
|
||||
return;
|
||||
}
|
||||
prev = p;
|
||||
p = SCHEME_CDR(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void break_console_reading_threads()
|
||||
{
|
||||
Scheme_Object *p;
|
||||
|
||||
if (!console_reading)
|
||||
return;
|
||||
|
||||
for (p = console_reading; SCHEME_PAIRP(p); p = SCHEME_CDR(p)) {
|
||||
scheme_break_thread((Scheme_Thread *)SCHEME_CAR(p));
|
||||
}
|
||||
}
|
||||
|
||||
static intptr_t mrconsole_get_string(Scheme_Input_Port *ip,
|
||||
char *buffer, intptr_t offset, intptr_t size,
|
||||
int nonblock, Scheme_Object *unless)
|
||||
{
|
||||
intptr_t result;
|
||||
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
||||
|
||||
if (!pipe) return 0;
|
||||
MrEdSchemeMessages("");
|
||||
|
||||
init_console_in();
|
||||
pipe = console_inport;
|
||||
|
||||
add_console_reading();
|
||||
result = scheme_get_byte_string_unless("console get-string", pipe,
|
||||
buffer, offset, size,
|
||||
nonblock, 0, NULL,
|
||||
unless);
|
||||
remove_console_reading();
|
||||
return result;
|
||||
}
|
||||
|
||||
static Scheme_Object *mrconsole_progress_evt(Scheme_Input_Port *ip)
|
||||
{
|
||||
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
||||
|
||||
if (!pipe) return NULL;
|
||||
MrEdSchemeMessages("");
|
||||
|
||||
init_console_in();
|
||||
pipe = console_inport;
|
||||
|
||||
return scheme_progress_evt(pipe);
|
||||
}
|
||||
|
||||
static int mrconsole_peeked_read(Scheme_Input_Port *ip,
|
||||
intptr_t amount,
|
||||
Scheme_Object *unless,
|
||||
Scheme_Object *target_ch)
|
||||
{
|
||||
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
||||
|
||||
if (!pipe) return 0;
|
||||
MrEdSchemeMessages("");
|
||||
|
||||
init_console_in();
|
||||
pipe = console_inport;
|
||||
|
||||
return scheme_peeked_read(pipe, amount, unless, target_ch);
|
||||
}
|
||||
|
||||
static int mrconsole_char_ready(Scheme_Input_Port *ip)
|
||||
{
|
||||
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
||||
|
||||
if (!pipe) return 0;
|
||||
MrEdSchemeMessages("");
|
||||
|
||||
init_console_in();
|
||||
pipe = console_inport;
|
||||
|
||||
return scheme_char_ready(pipe);
|
||||
}
|
||||
|
||||
static void mrconsole_close(Scheme_Input_Port *ip)
|
||||
{
|
||||
Scheme_Object *pipe = (Scheme_Object *)ip->port_data;
|
||||
|
||||
if (!pipe) return;
|
||||
|
||||
init_console_in();
|
||||
pipe = console_inport;
|
||||
|
||||
scheme_close_input_port(pipe);
|
||||
}
|
||||
|
||||
static Scheme_Object *MrEdMakeStdIn(void)
|
||||
{
|
||||
Scheme_Object *readp;
|
||||
Scheme_Input_Port *ip;
|
||||
|
||||
if (scheme_get_place_id() == 0) {
|
||||
MZ_REGISTER_STATIC(stdin_pipe);
|
||||
|
||||
scheme_pipe(&readp, &stdin_pipe);
|
||||
} else {
|
||||
/* for a non-main place, the port will be replaced anyway */
|
||||
readp = NULL;
|
||||
}
|
||||
|
||||
ip = scheme_make_input_port(scheme_make_port_type("mred-console-input-port"),
|
||||
readp,
|
||||
scheme_intern_symbol("mred-console"),
|
||||
mrconsole_get_string,
|
||||
NULL,
|
||||
mrconsole_progress_evt,
|
||||
mrconsole_peeked_read,
|
||||
mrconsole_char_ready,
|
||||
mrconsole_close,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
return (Scheme_Object *)ip;
|
||||
}
|
||||
|
||||
static intptr_t stdout_write(Scheme_Output_Port*op, const char *s, intptr_t d, intptr_t l,
|
||||
int rarely_block, int enable_break)
|
||||
{
|
||||
if (l)
|
||||
MrEdSchemeMessages(NULL, s, d, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
static Scheme_Object *MrEdMakeStdOut(void)
|
||||
{
|
||||
Scheme_Object *outtype;
|
||||
|
||||
outtype = scheme_make_port_type("stdout");
|
||||
|
||||
return (Scheme_Object *)scheme_make_output_port(outtype, NULL,
|
||||
scheme_intern_symbol("mred-console"),
|
||||
scheme_write_evt_via_write,
|
||||
stdout_write,
|
||||
NULL, NULL, NULL, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static intptr_t stderr_write(Scheme_Output_Port*op, const char *s, intptr_t d, intptr_t l,
|
||||
int rarely_block, int enable_break)
|
||||
{
|
||||
if (l)
|
||||
MrEdSchemeMessages(NULL, s, d, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
static Scheme_Object *MrEdMakeStdErr(void)
|
||||
{
|
||||
Scheme_Object *errtype;
|
||||
|
||||
errtype = scheme_make_port_type("stderr");
|
||||
|
||||
return (Scheme_Object *)scheme_make_output_port(errtype, NULL,
|
||||
scheme_intern_symbol("mred-console"),
|
||||
scheme_write_evt_via_write,
|
||||
stderr_write,
|
||||
NULL, NULL, NULL, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static void MrEdExit(int v)
|
||||
{
|
||||
if (has_stdio) {
|
||||
WaitOnConsole();
|
||||
}
|
||||
|
||||
scheme_immediate_exit(v);
|
||||
}
|
||||
|
||||
# ifdef MZ_PRECISE_GC
|
||||
START_XFORM_SKIP;
|
||||
# endif
|
||||
|
||||
# include "../start/win_single.inc"
|
||||
|
||||
static void pre_filter_cmdline_arguments(int *argc, char ***argv)
|
||||
{
|
||||
scheme_register_process_global("PLT_WM_IS_GRACKET", (void *)(intptr_t)wm_is_gracket);
|
||||
scheme_register_process_global("PLT_GRACKET_GUID", GRACKET_GUID);
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* command-line parsing */
|
||||
/* ---------------------------------------- */
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored, int nCmdShow)
|
||||
{
|
||||
int j, argc;
|
||||
int j, argc, in_terminal = 0;
|
||||
char **argv, *normalized_path;
|
||||
|
||||
load_delayed();
|
||||
|
@ -436,7 +138,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored
|
|||
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (h && (h != INVALID_HANDLE_VALUE)
|
||||
&& (GetFileType(h) != FILE_TYPE_UNKNOWN)) {
|
||||
wx_in_terminal = 1;
|
||||
in_terminal = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,18 +147,13 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored
|
|||
if (CheckSingleInstance(normalized_path, argv))
|
||||
return 0;
|
||||
|
||||
if (!wx_in_terminal) {
|
||||
scheme_set_stdio_makers(MrEdMakeStdIn,
|
||||
MrEdMakeStdOut,
|
||||
MrEdMakeStdErr);
|
||||
if (!in_terminal)
|
||||
scheme_set_console_output(MrEdSchemeMessagesOutput);
|
||||
}
|
||||
scheme_set_console_printf(MrEdSchemeMessages);
|
||||
scheme_set_exit(MrEdExit);
|
||||
|
||||
j = MAIN(argc, argv);
|
||||
|
||||
MrEdExit(j);
|
||||
scheme_immediate_exit(j);
|
||||
/* shouldn't get here */
|
||||
|
||||
return j;
|
||||
|
|
|
@ -1883,6 +1883,7 @@ MZ_EXTERN void scheme_set_console_printf(scheme_console_printf_t p);
|
|||
typedef void (*scheme_console_output_t)(char *str, intptr_t len);
|
||||
MZ_EXTERN scheme_console_output_t scheme_console_output;
|
||||
MZ_EXTERN void scheme_set_console_output(scheme_console_output_t p);
|
||||
MZ_EXTERN void scheme_ensure_console_ready();
|
||||
MZ_EXTERN void (*scheme_sleep)(float seconds, void *fds);
|
||||
MZ_EXTERN void (*scheme_notify_multithread)(int on);
|
||||
MZ_EXTERN void (*scheme_wakeup_on_input)(void *fds);
|
||||
|
|
|
@ -1136,6 +1136,11 @@ void scheme_warning(char *msg, ...)
|
|||
scheme_get_param(scheme_current_config(), MZCONFIG_ERROR_PORT));
|
||||
}
|
||||
|
||||
void scheme_ensure_console_ready()
|
||||
{
|
||||
rktio_create_console();
|
||||
}
|
||||
|
||||
void scheme_log(Scheme_Logger *logger, int level, int flags,
|
||||
const char *msg, ...)
|
||||
{
|
||||
|
|
|
@ -3617,8 +3617,10 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[])
|
|||
fd_ok = 1;
|
||||
}
|
||||
else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) {
|
||||
fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd);
|
||||
fd_ok = 1;
|
||||
if (rktio_fd_is_terminal(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd))
|
||||
return scheme_true;
|
||||
else
|
||||
return scheme_false;
|
||||
}
|
||||
} else if (SCHEME_OUTPUT_PORTP(p)) {
|
||||
Scheme_Output_Port *op;
|
||||
|
@ -3633,8 +3635,10 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[])
|
|||
fd_ok = 1;
|
||||
}
|
||||
else if (SAME_OBJ(op->sub_type, fd_output_port_type)) {
|
||||
fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)op->port_data)->fd);
|
||||
fd_ok = 1;
|
||||
if (rktio_fd_is_terminal(scheme_rktio, ((Scheme_FD *)op->port_data)->fd))
|
||||
return scheme_true;
|
||||
else
|
||||
return scheme_false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ OBJS = rktio_fs.@LTO@ \
|
|||
rktio_error.@LTO@ \
|
||||
rktio_hash.@LTO@ \
|
||||
rktio_wide.@LTO@ \
|
||||
rktio_console.@LTO@ \
|
||||
rktio_main.@LTO@
|
||||
|
||||
default_rktio:
|
||||
|
@ -137,6 +138,9 @@ rktio_hash.@LTO@: $(srcdir)/rktio_hash.c $(RKTIO_HEADERS)
|
|||
rktio_wide.@LTO@: $(srcdir)/rktio_wide.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_wide.@LTO@ -c $(srcdir)/rktio_wide.c
|
||||
|
||||
rktio_console.@LTO@: $(srcdir)/rktio_console.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_console.@LTO@ -c $(srcdir)/rktio_console.c
|
||||
|
||||
rktio_main.@LTO@: $(srcdir)/rktio_main.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.@LTO@ -c $(srcdir)/rktio_main.c
|
||||
|
||||
|
|
|
@ -245,6 +245,13 @@ RKTIO_EXTERN rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which);
|
|||
#define RKTIO_STDOUT 1
|
||||
#define RKTIO_STDERR 2
|
||||
|
||||
RKTIO_EXTERN void rktio_create_console();
|
||||
/* On Windows, ensures that a console is available for output. If a
|
||||
console is created for an application started in GUI mode, The
|
||||
console cannot be closed by the user until the process exits, and
|
||||
then an atexit callback pauses the exit until the user closes the
|
||||
console. */
|
||||
|
||||
RKTIO_EXTERN_ERR(RKTIO_READ_ERROR)
|
||||
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
|
||||
/* Returns the number of bytes read, possibly 0, in non-blocking mode.
|
||||
|
|
86
racket/src/rktio/rktio_console.c
Normal file
86
racket/src/rktio/rktio_console.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
|
||||
void rktio_create_console()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
static int has_console;
|
||||
static HWND console_hwnd;
|
||||
static HANDLE waiting_sema;
|
||||
typedef HWND (WINAPI* gcw_proc)();
|
||||
|
||||
void rktio_console_ctl_c()
|
||||
{
|
||||
if (waiting_sema)
|
||||
ReleaseSemaphore(waiting_sema, 1, NULL);
|
||||
}
|
||||
|
||||
static void WaitOnConsole()
|
||||
{
|
||||
DWORD wrote;
|
||||
|
||||
if (!has_console)
|
||||
return;
|
||||
|
||||
waiting_sema = CreateSemaphore(NULL, 0, 1, NULL);
|
||||
|
||||
if (console_hwnd) {
|
||||
AppendMenu(GetSystemMenu(console_hwnd, FALSE),
|
||||
MF_STRING,
|
||||
SC_CLOSE,
|
||||
"Close");
|
||||
/* Un-gray the close box: */
|
||||
RedrawWindow(console_hwnd, NULL, NULL,
|
||||
RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
|
||||
}
|
||||
|
||||
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
L"\n[Exited. Close box or Ctrl-C closes the console.]\n",
|
||||
51,
|
||||
&wrote,
|
||||
NULL);
|
||||
|
||||
WaitForSingleObject(waiting_sema, INFINITE);
|
||||
|
||||
has_console = 0;
|
||||
}
|
||||
|
||||
void rktio_create_console()
|
||||
{
|
||||
if (!has_console) {
|
||||
HMODULE hm;
|
||||
gcw_proc gcw;
|
||||
|
||||
AllocConsole();
|
||||
|
||||
rktio_set_console_handler();
|
||||
|
||||
hm = LoadLibraryW(L"kernel32.dll");
|
||||
if (hm)
|
||||
gcw = (gcw_proc)GetProcAddress(hm, "GetConsoleWindow");
|
||||
else
|
||||
gcw = NULL;
|
||||
|
||||
if (gcw)
|
||||
console_hwnd = gcw();
|
||||
|
||||
if (console_hwnd) {
|
||||
EnableMenuItem(GetSystemMenu(console_hwnd, FALSE), SC_CLOSE,
|
||||
MF_BYCOMMAND | MF_GRAYED);
|
||||
RemoveMenu(GetSystemMenu(console_hwnd, FALSE), SC_CLOSE, MF_BYCOMMAND);
|
||||
}
|
||||
|
||||
has_console = 1;
|
||||
|
||||
atexit(WaitOnConsole);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -103,6 +103,9 @@ static void deinit_fd(rktio_fd_t *rfd, int full_close)
|
|||
deinit_write_fd(rfd, full_close);
|
||||
}
|
||||
|
||||
#define DELAYED_CONSOLE_HANDLE ((HANDLE)-2)
|
||||
static void force_console(rktio_fd_t *rfd);
|
||||
|
||||
static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th);
|
||||
static void WindowsFDICleanup(Win_FD_Input_Thread *th, int close_mode);
|
||||
|
||||
|
@ -174,7 +177,8 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
|
|||
rfd->sock = (SOCKET)system_fd;
|
||||
else
|
||||
rfd->fd = (HANDLE)system_fd;
|
||||
if (!(modes & (RKTIO_OPEN_REGFILE | RKTIO_OPEN_NOT_REGFILE | RKTIO_OPEN_SOCKET))) {
|
||||
if (!(modes & (RKTIO_OPEN_REGFILE | RKTIO_OPEN_NOT_REGFILE | RKTIO_OPEN_SOCKET))
|
||||
&& (rfd->fd != DELAYED_CONSOLE_HANDLE)) {
|
||||
if ((GetFileType(rfd->fd) == FILE_TYPE_DISK))
|
||||
rfd->modes |= RKTIO_OPEN_REGFILE;
|
||||
if (!(modes & (RKTIO_OPEN_DIR | RKTIO_OPEN_NOT_DIR))) {
|
||||
|
@ -205,8 +209,10 @@ intptr_t rktio_internal_fd_system_fd(rktio_fd_t *rfd)
|
|||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
if (rfd->modes & RKTIO_OPEN_SOCKET)
|
||||
return (intptr_t)rfd->sock;
|
||||
else
|
||||
else {
|
||||
force_console(rfd);
|
||||
return (intptr_t)rfd->fd;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -224,6 +230,7 @@ rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
|
|||
return rktio_system_fd(rktio, which, mode | RKTIO_OPEN_NOT_DIR);
|
||||
#endif
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
HANDLE h;
|
||||
switch (which) {
|
||||
case RKTIO_STDIN:
|
||||
which = STD_INPUT_HANDLE;
|
||||
|
@ -235,8 +242,12 @@ rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
|
|||
which = STD_ERROR_HANDLE;
|
||||
break;
|
||||
}
|
||||
h = GetStdHandle(which);
|
||||
if ((h == INVALID_HANDLE_VALUE) || (h == NULL)) {
|
||||
h = DELAYED_CONSOLE_HANDLE; /* => open a console on demand */
|
||||
}
|
||||
return rktio_system_fd(rktio,
|
||||
(intptr_t)GetStdHandle(which),
|
||||
(intptr_t)h,
|
||||
mode | RKTIO_OPEN_NOT_DIR);
|
||||
#endif
|
||||
}
|
||||
|
@ -272,7 +283,9 @@ int rktio_system_fd_is_terminal(rktio_t *rktio, intptr_t fd)
|
|||
return isatty(fd);
|
||||
#endif
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
if (GetFileType((HANDLE)fd) == FILE_TYPE_CHAR) {
|
||||
if ((HANDLE)fd == DELAYED_CONSOLE_HANDLE)
|
||||
return 1; /* delayed console */
|
||||
else if (GetFileType((HANDLE)fd) == FILE_TYPE_CHAR) {
|
||||
DWORD mode;
|
||||
if (GetConsoleMode((HANDLE)fd, &mode))
|
||||
return 1;
|
||||
|
@ -324,9 +337,13 @@ rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd)
|
|||
HANDLE newhandle;
|
||||
BOOL rc;
|
||||
|
||||
rc = DuplicateHandle(GetCurrentProcess(), rfd->fd,
|
||||
GetCurrentProcess(), &newhandle,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if (rfd->fd == DELAYED_CONSOLE_HANDLE) {
|
||||
newhandle = DELAYED_CONSOLE_HANDLE;
|
||||
rc = TRUE;
|
||||
} else
|
||||
rc = DuplicateHandle(GetCurrentProcess(), rfd->fd,
|
||||
GetCurrentProcess(), &newhandle,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
if (rc == FALSE) {
|
||||
get_windows_error();
|
||||
|
@ -384,7 +401,7 @@ static rktio_ok_t do_close(rktio_t *rktio /* maybe NULL */, rktio_fd_t *rfd, int
|
|||
deinit_fd(rfd, 1);
|
||||
|
||||
ok = 1;
|
||||
if (!rfd->th && !rfd->oth) {
|
||||
if (!rfd->th && !rfd->oth && (rfd->fd != DELAYED_CONSOLE_HANDLE)) {
|
||||
if (!CloseHandle(rfd->fd)) {
|
||||
ok = 0;
|
||||
if (set_error)
|
||||
|
@ -612,6 +629,8 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
|
|||
}
|
||||
#endif
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
force_console(rfd);
|
||||
|
||||
if (rfd->modes & RKTIO_OPEN_SOCKET) {
|
||||
if (check_flushed)
|
||||
return RKTIO_POLL_READY;
|
||||
|
@ -698,6 +717,8 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
|
|||
fds2 = RKTIO_GET_FDSET(fds, 2);
|
||||
RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
|
||||
} else {
|
||||
force_console(rfd);
|
||||
|
||||
if (modes & RKTIO_POLL_READ) {
|
||||
init_read_fd(rktio, rfd);
|
||||
if (rfd->th) {
|
||||
|
@ -980,6 +1001,8 @@ static intptr_t adjust_input_text_for_pending_cr(rktio_fd_t *rfd, char *buffer,
|
|||
|
||||
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd)
|
||||
{
|
||||
force_console(rfd);
|
||||
|
||||
if (!rktio_fd_is_regular_file(rktio, rfd) && !rfd->th) {
|
||||
/* To get non-blocking I/O for anything that can block, we create
|
||||
a separate reader thread.
|
||||
|
@ -1243,6 +1266,8 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr
|
|||
if (rfd->modes & RKTIO_OPEN_SOCKET)
|
||||
return rktio_socket_write(rktio, rfd, buffer, len);
|
||||
|
||||
force_console(rfd);
|
||||
|
||||
if (rktio_fd_is_regular_file(rktio, rfd)
|
||||
|| rktio_fd_is_terminal(rktio, rfd)) {
|
||||
/* Regular files never block, so this code looks like the Unix
|
||||
|
@ -1832,3 +1857,29 @@ static void WindowsFDOCleanup(Win_FD_Output_Thread *oth, int close_mode)
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* console */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
static void force_console(rktio_fd_t *rfd) {
|
||||
/* DELAYED_CONSOLE_HANDLE is used to indicate that a console should be created on demand */
|
||||
if (rfd->fd == DELAYED_CONSOLE_HANDLE) {
|
||||
HANDLE h;
|
||||
int which;
|
||||
|
||||
rktio_create_console();
|
||||
|
||||
if (rfd->modes & RKTIO_OPEN_READ)
|
||||
which = STD_INPUT_HANDLE;
|
||||
else
|
||||
which = STD_OUTPUT_HANDLE;
|
||||
h = GetStdHandle(which);
|
||||
|
||||
rfd->fd = h;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -376,3 +376,7 @@ void rktio_forget_os_signal_handler(rktio_t *rktio);
|
|||
int rktio_system_time_is_dst(SYSTEMTIME *st, TIME_ZONE_INFORMATION *_tz);
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
void rktio_console_ctl_c(void);
|
||||
void rktio_set_console_handler(void);
|
||||
#endif
|
||||
|
|
|
@ -26,9 +26,15 @@ static void signal_received(int i)
|
|||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||
static BOOL WINAPI ConsoleBreakHandler(DWORD op)
|
||||
{
|
||||
rktio_console_ctl_c();
|
||||
signal_received(RKTIO_OS_SIGNAL_INT);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void rktio_set_console_handler(void)
|
||||
{
|
||||
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX)
|
||||
|
@ -66,7 +72,7 @@ void rktio_install_os_signal_handler(rktio_t *rktio)
|
|||
#endif
|
||||
|
||||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
||||
rktio_set_console_handler();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,10 @@
|
|||
RelativePath="..\..\rktio\rktio_wide.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_console.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\rktio\rktio_main.c"
|
||||
>
|
||||
|
|
|
@ -140,6 +140,7 @@
|
|||
<ClCompile Include="..\..\rktio\rktio_error.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_hash.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_wide.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_console.c" />
|
||||
<ClCompile Include="..\..\rktio\rktio_main.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
Loading…
Reference in New Issue
Block a user