Set up Windows console during MRI init

This commit is contained in:
Joni Savolainen 2022-01-15 08:55:22 +02:00
parent 8a9cdf9266
commit c2deb233e0
5 changed files with 53 additions and 38 deletions

View file

@ -51,6 +51,7 @@ extern "C" {
#ifdef __WIN32__
#include <fcntl.h>
#include "util/win-consoleutils.h"
#endif
#include <assert.h>
@ -273,7 +274,10 @@ static void mriBindingInit() {
// Set $stdout and its ilk accordingly on Windows
#ifdef __WIN32__
if (shState->config().editor.debug)
{
reopenWindowsStreams();
configureWindowsStreams();
}
#endif
// Load zlib, if it's present. Requires --with-static-linked-ext or zlib.so.
@ -957,7 +961,7 @@ static void configureWindowsStreams() {
const int stdoutFD = _open_osfhandle((intptr_t)outputHandle, _O_TEXT);
VALUE winStdout = rb_funcall(rb_cIO, rb_intern("new"), 2,
INT2NUM(stdoutFD), rb_str_new_cstr("w"));
INT2NUM(stdoutFD), rb_str_new_cstr("w+"));
rb_gv_set("stdout", winStdout);
}
@ -974,6 +978,18 @@ static void configureWindowsStreams() {
rb_gv_set("stdin", winStdin);
}
const HANDLE errorHandle = GetStdHandle(STD_ERROR_HANDLE);
// Configure $stderr
if (HANDLE_VALID(errorHandle)) {
const int stderrFD = _open_osfhandle((intptr_t)errorHandle, _O_TEXT);
VALUE winStderr = rb_funcall(rb_cIO, rb_intern("new"), 2,
INT2NUM(stderrFD), rb_str_new_cstr("w+"));
rb_gv_set("stderr", winStderr);
}
#undef HANDLE_VALID
}
#endif // #ifdef __WIN32__
@ -1053,15 +1069,9 @@ static void mriBindingExecute() {
/* Normally only a ruby executable would do a sysinit,
* but not doing it will lead to crashes due to closed
* stdio streams on some platforms (eg. Windows) */
#ifdef __WIN32__
if (!conf.editor.debug) {
#endif
int argc = 0;
char **argv = 0;
ruby_sysinit(&argc, &argv);
#ifdef __WIN32__
}
#endif
RUBY_INIT_STACK;
ruby_init();

View file

@ -296,11 +296,7 @@ int main(int argc, char *argv[]) {
// Create a debug console in debug mode
if (conf.editor.debug) {
HANDLE winConsoleHandle;
if (setupWindowsConsole(winConsoleHandle)) {
reopenWindowsStreams();
} else {
if (!setupWindowsConsole()) {
char buf[200];
snprintf(buf, sizeof(buf), "Error allocating console: %lu",
GetLastError());

View file

@ -147,6 +147,7 @@ main_source = files(
'display/gl/vertex.cpp',
'util/iniconfig.cpp',
'util/win-consoleutils.cpp',
'etc/etc.cpp',
'etc/table.cpp',

View file

@ -0,0 +1,31 @@
#include "win-consoleutils.h"
// Attempts to allocate a console and fetch the output handle.
// Returns whether the operation was successful.
// Extended error information can be received via GetLastError().
bool setupWindowsConsole()
{
if (!AllocConsole())
return false;
const HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
return (handle != NULL && handle != INVALID_HANDLE_VALUE);
}
FILE *outStream;
FILE *inStream;
FILE *errStream;
// Reopens the file streams. This should be done after successfully
// setting up the console.
void reopenWindowsStreams()
{
freopen_s(&outStream, "CONOUT$", "w+", stdout);
freopen_s(&errStream, "CONOUT$", "w+", stderr);
freopen_s(&inStream, "CONIN$", "r", stdin);
std::cout.clear();
std::clog.clear();
std::cerr.clear();
std::cin.clear();
}

View file

@ -2,33 +2,10 @@
#define WIN_CONSOLEUTIL_H
#include <iostream>
#include "windows.h"
#include <windows.h>
// Attempts to allocate a console and fetch the output handle.
// Returns whether the operation was successful.
// Extended error information can be received via GetLastError().
bool setupWindowsConsole(HANDLE &handle)
{
if (!AllocConsole())
return false;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
bool setupWindowsConsole();
return (handle != NULL && handle != INVALID_HANDLE_VALUE);
}
// Reopens the file streams. This should be done after successfully
// setting up the console.
void reopenWindowsStreams()
{
FILE* fDummy;
freopen_s(&fDummy, "CONOUT$", "w", stdout);
freopen_s(&fDummy, "CONOUT$", "w", stderr);
freopen_s(&fDummy, "CONIN$", "r", stdin);
std::cout.clear();
std::clog.clear();
std::cerr.clear();
std::cin.clear();
}
void reopenWindowsStreams();
#endif