Windows: implement missing stdio methods
This commit is contained in:
Родитель
b70f8aec84
Коммит
dc99aa0c8c
|
@ -49,8 +49,7 @@ function Interface(output, completer) {
|
|||
this.history = [];
|
||||
this.historyIndex = -1;
|
||||
|
||||
// 0 for stdin
|
||||
var winSize = tty.getWindowSize(0);
|
||||
var winSize = tty.getWindowSize(output.fd);
|
||||
exports.columns = winSize[1];
|
||||
|
||||
if (process.listeners('SIGWINCH').length === 0) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <io.h>
|
||||
#include <node.h>
|
||||
#include <node_stdio.h>
|
||||
#include <platform_win32.h>
|
||||
#include <v8.h>
|
||||
|
@ -5,24 +7,23 @@
|
|||
using namespace v8;
|
||||
namespace node {
|
||||
|
||||
#define THROW_ERROR(msg) \
|
||||
return ThrowException(Exception::Error(String::New(msg)));
|
||||
#define THROW_BAD_ARGS \
|
||||
return ThrowException(Exception::TypeError(String::New("Bad argument")));
|
||||
|
||||
NO_IMPL(void, Stdio::DisableRawMode, , int fd);
|
||||
NO_IMPL(void, Stdio::Flush, , );
|
||||
NO_IMPL(static Handle<Value>, OpenStdin, RET_V8UNDEFINED, const Arguments& args);
|
||||
NO_IMPL(static Handle<Value>, IsStdinBlocking, RET_V8FALSE, const Arguments& args);
|
||||
NO_IMPL(static Handle<Value>, SetRawMode, RET_V8TRUE, const Arguments& args);
|
||||
NO_IMPL(static Handle<Value>, GetColumns, RET_V8INT(80), const Arguments& args);
|
||||
NO_IMPL(static Handle<Value>, GetRows, RET_V8INT(25), const Arguments& args);
|
||||
NO_IMPL(static Handle<Value>, IsATTY, RET_V8FALSE, const Arguments& args);
|
||||
/*
|
||||
* Flush stdout and stderr on node exit
|
||||
* Not necessary on windows, so a no-op
|
||||
*/
|
||||
void Stdio::Flush() {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* STDERR should always be blocking & utf-8
|
||||
* TODO: check correctness
|
||||
* STDERR should always be blocking
|
||||
*/
|
||||
static Handle<Value>
|
||||
WriteError (const Arguments& args)
|
||||
{
|
||||
static Handle<Value> WriteError(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args.Length() < 1)
|
||||
|
@ -30,36 +31,125 @@ WriteError (const Arguments& args)
|
|||
|
||||
String::Utf8Value msg(args[0]->ToString());
|
||||
|
||||
fprintf(stderr, "%s", (char*)*msg);
|
||||
fprintf(stderr, "%s", reinterpret_cast<char*>(*msg));
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Assume that stdout is never blocking on windows
|
||||
* TODO: check correctness and really implement this
|
||||
*/
|
||||
static Handle<Value>
|
||||
IsStdoutBlocking (const Arguments& args)
|
||||
{
|
||||
static Handle<Value> IsATTY(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
int fd = args[0]->IntegerValue();
|
||||
DWORD result;
|
||||
int r = GetConsoleMode((HANDLE)_get_osfhandle(fd), &result);
|
||||
return scope.Close(r ? True() : False());
|
||||
}
|
||||
|
||||
|
||||
/* Whether stdio is currently in raw mode */
|
||||
/* -1 means that it has not been set */
|
||||
static int rawMode = -1;
|
||||
|
||||
|
||||
static void setRawMode(int newMode) {
|
||||
DWORD flags;
|
||||
BOOL result;
|
||||
|
||||
if (newMode != rawMode) {
|
||||
if (newMode) {
|
||||
// raw input
|
||||
flags = ENABLE_WINDOW_INPUT;
|
||||
} else {
|
||||
// input not raw, but still processing enough messages to make the
|
||||
// tty watcher work (this mode is not the windows default)
|
||||
flags = ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
|
||||
ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT;
|
||||
}
|
||||
|
||||
result = SetConsoleMode((HANDLE)_get_osfhandle(STDIN_FILENO), flags);
|
||||
if (result) {
|
||||
rawMode = newMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> SetRawMode(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
int newMode = !args[0]->IsFalse();
|
||||
setRawMode(newMode);
|
||||
|
||||
if (newMode != rawMode) {
|
||||
return ThrowException(ErrnoException(GetLastError(), "EnableRawMode"));
|
||||
}
|
||||
|
||||
return scope.Close(rawMode ? True() : False());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Stdio::DisableRawMode(int fd) {
|
||||
if (rawMode == 1)
|
||||
setRawMode(0);
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> OpenStdin(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
setRawMode(0); // init into nonraw mode
|
||||
return scope.Close(Integer::New(STDIN_FILENO));
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> IsStdinBlocking(const Arguments& args) {
|
||||
// On windows stdin always blocks
|
||||
return True();
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> IsStdoutBlocking(const Arguments& args) {
|
||||
// On windows stdout always blocks
|
||||
return True();
|
||||
}
|
||||
|
||||
|
||||
// process.binding('stdio').getWindowSize(fd);
|
||||
// returns [row, col]
|
||||
static Handle<Value> GetWindowSize (const Arguments& args) {
|
||||
HandleScope scope;
|
||||
int fd;
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
|
||||
if (!args[0]->IsNumber())
|
||||
THROW_BAD_ARGS
|
||||
fd = args[0]->IntegerValue();
|
||||
handle = (HANDLE)_get_osfhandle(fd);
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(handle, &info))
|
||||
return ThrowException(ErrnoException(GetLastError(), "GetConsoleScreenBufferInfo"));
|
||||
|
||||
Local<Array> ret = Array::New(2);
|
||||
ret->Set(0, Integer::New(static_cast<int>(info.dwSize.Y)));
|
||||
ret->Set(1, Integer::New(static_cast<int>(info.dwSize.X)));
|
||||
|
||||
return scope.Close(ret);
|
||||
}
|
||||
|
||||
|
||||
void Stdio::Initialize(v8::Handle<v8::Object> target) {
|
||||
target->Set(String::NewSymbol("stdoutFD"), Integer::New(STDOUT_FILENO));
|
||||
target->Set(String::NewSymbol("stderrFD"), Integer::New(STDERR_FILENO));
|
||||
target->Set(String::NewSymbol("stdinFD"), Integer::New(STDIN_FILENO));
|
||||
|
||||
NODE_SET_METHOD(target, "writeError", WriteError);
|
||||
NODE_SET_METHOD(target, "openStdin", OpenStdin);
|
||||
NODE_SET_METHOD(target, "isatty", IsATTY);
|
||||
NODE_SET_METHOD(target, "isStdoutBlocking", IsStdoutBlocking);
|
||||
NODE_SET_METHOD(target, "isStdinBlocking", IsStdinBlocking);
|
||||
NODE_SET_METHOD(target, "setRawMode", SetRawMode);
|
||||
NODE_SET_METHOD(target, "getColumns", GetColumns);
|
||||
NODE_SET_METHOD(target, "getRows", GetRows);
|
||||
NODE_SET_METHOD(target, "isatty", IsATTY);
|
||||
NODE_SET_METHOD(target, "openStdin", OpenStdin);
|
||||
NODE_SET_METHOD(target, "getWindowSize", GetWindowSize);
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче