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,
|
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);
|
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
|
/* Hack: overwrite "y" with "n" in binary to disable checking for another
|
||||||
instance of the same app. */
|
instance of the same app. */
|
||||||
char *check_for_another = "yes, please check for another";
|
char *check_for_another = "yes, please check for another";
|
||||||
static int wx_in_terminal = 0;
|
|
||||||
# define MZ_DEFINE_UTF8_MAIN
|
# define MZ_DEFINE_UTF8_MAIN
|
||||||
# define PRE_FILTER_CMDLINE_ARGUMENTS
|
# define PRE_FILTER_CMDLINE_ARGUMENTS
|
||||||
static void pre_filter_cmdline_arguments(int *argc, char ***argv);
|
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
|
#ifdef WIN32
|
||||||
|
|
||||||
/* ---------------------------------------- */
|
# ifdef MZ_PRECISE_GC
|
||||||
/* stdio to console */
|
START_XFORM_SKIP;
|
||||||
/* ---------------------------------------- */
|
# endif
|
||||||
|
|
||||||
static void MrEdSchemeMessages(char *, ...);
|
# include "../start/win_single.inc"
|
||||||
static Scheme_Object *stdin_pipe;
|
|
||||||
|
|
||||||
static HANDLE console_out;
|
static void pre_filter_cmdline_arguments(int *argc, char ***argv)
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
if (!console_in) {
|
scheme_register_process_global("PLT_WM_IS_GRACKET", (void *)(intptr_t)wm_is_gracket);
|
||||||
console_in = GetStdHandle(STD_INPUT_HANDLE);
|
scheme_register_process_global("PLT_GRACKET_GUID", GRACKET_GUID);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MrEdSchemeMessages(char *msg, ...)
|
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));
|
console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
char *s;
|
char *s;
|
||||||
|
@ -190,9 +113,7 @@ static void MrEdSchemeMessages(char *msg, ...)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme_end_atomic_no_swap();
|
va_end(args);
|
||||||
|
|
||||||
XFORM_HIDE_EXPR(va_end(args));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MrEdSchemeMessagesOutput(char *s, intptr_t l)
|
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);
|
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 */
|
/* command-line parsing */
|
||||||
/* ---------------------------------------- */
|
/* ---------------------------------------- */
|
||||||
|
|
||||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored, int nCmdShow)
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored, int nCmdShow)
|
||||||
{
|
{
|
||||||
int j, argc;
|
int j, argc, in_terminal = 0;
|
||||||
char **argv, *normalized_path;
|
char **argv, *normalized_path;
|
||||||
|
|
||||||
load_delayed();
|
load_delayed();
|
||||||
|
@ -436,7 +138,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored
|
||||||
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (h && (h != INVALID_HANDLE_VALUE)
|
if (h && (h != INVALID_HANDLE_VALUE)
|
||||||
&& (GetFileType(h) != FILE_TYPE_UNKNOWN)) {
|
&& (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))
|
if (CheckSingleInstance(normalized_path, argv))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!wx_in_terminal) {
|
if (!in_terminal)
|
||||||
scheme_set_stdio_makers(MrEdMakeStdIn,
|
|
||||||
MrEdMakeStdOut,
|
|
||||||
MrEdMakeStdErr);
|
|
||||||
scheme_set_console_output(MrEdSchemeMessagesOutput);
|
scheme_set_console_output(MrEdSchemeMessagesOutput);
|
||||||
}
|
|
||||||
scheme_set_console_printf(MrEdSchemeMessages);
|
scheme_set_console_printf(MrEdSchemeMessages);
|
||||||
scheme_set_exit(MrEdExit);
|
|
||||||
|
|
||||||
j = MAIN(argc, argv);
|
j = MAIN(argc, argv);
|
||||||
|
|
||||||
MrEdExit(j);
|
scheme_immediate_exit(j);
|
||||||
/* shouldn't get here */
|
/* shouldn't get here */
|
||||||
|
|
||||||
return j;
|
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);
|
typedef void (*scheme_console_output_t)(char *str, intptr_t len);
|
||||||
MZ_EXTERN scheme_console_output_t scheme_console_output;
|
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_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_sleep)(float seconds, void *fds);
|
||||||
MZ_EXTERN void (*scheme_notify_multithread)(int on);
|
MZ_EXTERN void (*scheme_notify_multithread)(int on);
|
||||||
MZ_EXTERN void (*scheme_wakeup_on_input)(void *fds);
|
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));
|
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,
|
void scheme_log(Scheme_Logger *logger, int level, int flags,
|
||||||
const char *msg, ...)
|
const char *msg, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3617,8 +3617,10 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[])
|
||||||
fd_ok = 1;
|
fd_ok = 1;
|
||||||
}
|
}
|
||||||
else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) {
|
else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) {
|
||||||
fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd);
|
if (rktio_fd_is_terminal(scheme_rktio, ((Scheme_FD *)ip->port_data)->fd))
|
||||||
fd_ok = 1;
|
return scheme_true;
|
||||||
|
else
|
||||||
|
return scheme_false;
|
||||||
}
|
}
|
||||||
} else if (SCHEME_OUTPUT_PORTP(p)) {
|
} else if (SCHEME_OUTPUT_PORTP(p)) {
|
||||||
Scheme_Output_Port *op;
|
Scheme_Output_Port *op;
|
||||||
|
@ -3633,8 +3635,10 @@ Scheme_Object *scheme_terminal_port_p(int argc, Scheme_Object *argv[])
|
||||||
fd_ok = 1;
|
fd_ok = 1;
|
||||||
}
|
}
|
||||||
else if (SAME_OBJ(op->sub_type, fd_output_port_type)) {
|
else if (SAME_OBJ(op->sub_type, fd_output_port_type)) {
|
||||||
fd = rktio_fd_system_fd(scheme_rktio, ((Scheme_FD *)op->port_data)->fd);
|
if (rktio_fd_is_terminal(scheme_rktio, ((Scheme_FD *)op->port_data)->fd))
|
||||||
fd_ok = 1;
|
return scheme_true;
|
||||||
|
else
|
||||||
|
return scheme_false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ OBJS = rktio_fs.@LTO@ \
|
||||||
rktio_error.@LTO@ \
|
rktio_error.@LTO@ \
|
||||||
rktio_hash.@LTO@ \
|
rktio_hash.@LTO@ \
|
||||||
rktio_wide.@LTO@ \
|
rktio_wide.@LTO@ \
|
||||||
|
rktio_console.@LTO@ \
|
||||||
rktio_main.@LTO@
|
rktio_main.@LTO@
|
||||||
|
|
||||||
default_rktio:
|
default_rktio:
|
||||||
|
@ -137,6 +138,9 @@ rktio_hash.@LTO@: $(srcdir)/rktio_hash.c $(RKTIO_HEADERS)
|
||||||
rktio_wide.@LTO@: $(srcdir)/rktio_wide.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
|
$(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)
|
rktio_main.@LTO@: $(srcdir)/rktio_main.c $(RKTIO_HEADERS)
|
||||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.@LTO@ -c $(srcdir)/rktio_main.c
|
$(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_STDOUT 1
|
||||||
#define RKTIO_STDERR 2
|
#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)
|
RKTIO_EXTERN_ERR(RKTIO_READ_ERROR)
|
||||||
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
|
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.
|
/* 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);
|
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 long WINAPI WindowsFDReader(Win_FD_Input_Thread *th);
|
||||||
static void WindowsFDICleanup(Win_FD_Input_Thread *th, int close_mode);
|
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;
|
rfd->sock = (SOCKET)system_fd;
|
||||||
else
|
else
|
||||||
rfd->fd = (HANDLE)system_fd;
|
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))
|
if ((GetFileType(rfd->fd) == FILE_TYPE_DISK))
|
||||||
rfd->modes |= RKTIO_OPEN_REGFILE;
|
rfd->modes |= RKTIO_OPEN_REGFILE;
|
||||||
if (!(modes & (RKTIO_OPEN_DIR | RKTIO_OPEN_NOT_DIR))) {
|
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
|
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||||
if (rfd->modes & RKTIO_OPEN_SOCKET)
|
if (rfd->modes & RKTIO_OPEN_SOCKET)
|
||||||
return (intptr_t)rfd->sock;
|
return (intptr_t)rfd->sock;
|
||||||
else
|
else {
|
||||||
|
force_console(rfd);
|
||||||
return (intptr_t)rfd->fd;
|
return (intptr_t)rfd->fd;
|
||||||
|
}
|
||||||
#endif
|
#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);
|
return rktio_system_fd(rktio, which, mode | RKTIO_OPEN_NOT_DIR);
|
||||||
#endif
|
#endif
|
||||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||||
|
HANDLE h;
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case RKTIO_STDIN:
|
case RKTIO_STDIN:
|
||||||
which = STD_INPUT_HANDLE;
|
which = STD_INPUT_HANDLE;
|
||||||
|
@ -235,8 +242,12 @@ rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which)
|
||||||
which = STD_ERROR_HANDLE;
|
which = STD_ERROR_HANDLE;
|
||||||
break;
|
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,
|
return rktio_system_fd(rktio,
|
||||||
(intptr_t)GetStdHandle(which),
|
(intptr_t)h,
|
||||||
mode | RKTIO_OPEN_NOT_DIR);
|
mode | RKTIO_OPEN_NOT_DIR);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -272,7 +283,9 @@ int rktio_system_fd_is_terminal(rktio_t *rktio, intptr_t fd)
|
||||||
return isatty(fd);
|
return isatty(fd);
|
||||||
#endif
|
#endif
|
||||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
#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;
|
DWORD mode;
|
||||||
if (GetConsoleMode((HANDLE)fd, &mode))
|
if (GetConsoleMode((HANDLE)fd, &mode))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -324,9 +337,13 @@ rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd)
|
||||||
HANDLE newhandle;
|
HANDLE newhandle;
|
||||||
BOOL rc;
|
BOOL rc;
|
||||||
|
|
||||||
rc = DuplicateHandle(GetCurrentProcess(), rfd->fd,
|
if (rfd->fd == DELAYED_CONSOLE_HANDLE) {
|
||||||
GetCurrentProcess(), &newhandle,
|
newhandle = DELAYED_CONSOLE_HANDLE;
|
||||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
rc = TRUE;
|
||||||
|
} else
|
||||||
|
rc = DuplicateHandle(GetCurrentProcess(), rfd->fd,
|
||||||
|
GetCurrentProcess(), &newhandle,
|
||||||
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
|
|
||||||
if (rc == FALSE) {
|
if (rc == FALSE) {
|
||||||
get_windows_error();
|
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);
|
deinit_fd(rfd, 1);
|
||||||
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
if (!rfd->th && !rfd->oth) {
|
if (!rfd->th && !rfd->oth && (rfd->fd != DELAYED_CONSOLE_HANDLE)) {
|
||||||
if (!CloseHandle(rfd->fd)) {
|
if (!CloseHandle(rfd->fd)) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
if (set_error)
|
if (set_error)
|
||||||
|
@ -612,6 +629,8 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||||
|
force_console(rfd);
|
||||||
|
|
||||||
if (rfd->modes & RKTIO_OPEN_SOCKET) {
|
if (rfd->modes & RKTIO_OPEN_SOCKET) {
|
||||||
if (check_flushed)
|
if (check_flushed)
|
||||||
return RKTIO_POLL_READY;
|
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);
|
fds2 = RKTIO_GET_FDSET(fds, 2);
|
||||||
RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
|
RKTIO_FD_SET((intptr_t)rfd->sock, fds2);
|
||||||
} else {
|
} else {
|
||||||
|
force_console(rfd);
|
||||||
|
|
||||||
if (modes & RKTIO_POLL_READ) {
|
if (modes & RKTIO_POLL_READ) {
|
||||||
init_read_fd(rktio, rfd);
|
init_read_fd(rktio, rfd);
|
||||||
if (rfd->th) {
|
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)
|
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) {
|
if (!rktio_fd_is_regular_file(rktio, rfd) && !rfd->th) {
|
||||||
/* To get non-blocking I/O for anything that can block, we create
|
/* To get non-blocking I/O for anything that can block, we create
|
||||||
a separate reader thread.
|
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)
|
if (rfd->modes & RKTIO_OPEN_SOCKET)
|
||||||
return rktio_socket_write(rktio, rfd, buffer, len);
|
return rktio_socket_write(rktio, rfd, buffer, len);
|
||||||
|
|
||||||
|
force_console(rfd);
|
||||||
|
|
||||||
if (rktio_fd_is_regular_file(rktio, rfd)
|
if (rktio_fd_is_regular_file(rktio, rfd)
|
||||||
|| rktio_fd_is_terminal(rktio, rfd)) {
|
|| rktio_fd_is_terminal(rktio, rfd)) {
|
||||||
/* Regular files never block, so this code looks like the Unix
|
/* 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
|
#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);
|
int rktio_system_time_is_dst(SYSTEMTIME *st, TIME_ZONE_INFORMATION *_tz);
|
||||||
#endif
|
#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)
|
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||||
static BOOL WINAPI ConsoleBreakHandler(DWORD op)
|
static BOOL WINAPI ConsoleBreakHandler(DWORD op)
|
||||||
{
|
{
|
||||||
|
rktio_console_ctl_c();
|
||||||
signal_received(RKTIO_OS_SIGNAL_INT);
|
signal_received(RKTIO_OS_SIGNAL_INT);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rktio_set_console_handler(void)
|
||||||
|
{
|
||||||
|
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RKTIO_SYSTEM_UNIX)
|
#if defined(RKTIO_SYSTEM_UNIX)
|
||||||
|
@ -66,7 +72,7 @@ void rktio_install_os_signal_handler(rktio_t *rktio)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||||
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
rktio_set_console_handler();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,10 @@
|
||||||
RelativePath="..\..\rktio\rktio_wide.c"
|
RelativePath="..\..\rktio\rktio_wide.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\rktio\rktio_console.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\rktio\rktio_main.c"
|
RelativePath="..\..\rktio\rktio_main.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
<ClCompile Include="..\..\rktio\rktio_error.c" />
|
<ClCompile Include="..\..\rktio\rktio_error.c" />
|
||||||
<ClCompile Include="..\..\rktio\rktio_hash.c" />
|
<ClCompile Include="..\..\rktio\rktio_hash.c" />
|
||||||
<ClCompile Include="..\..\rktio\rktio_wide.c" />
|
<ClCompile Include="..\..\rktio\rktio_wide.c" />
|
||||||
|
<ClCompile Include="..\..\rktio\rktio_console.c" />
|
||||||
<ClCompile Include="..\..\rktio\rktio_main.c" />
|
<ClCompile Include="..\..\rktio\rktio_main.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user