diff --git a/node.gyp b/node.gyp index 021e9ff648..ae13115dd3 100644 --- a/node.gyp +++ b/node.gyp @@ -93,6 +93,7 @@ 'src/stream_wrap.cc', 'src/tcp_wrap.cc', 'src/timer_wrap.cc', + 'src/tty_wrap.cc', 'src/process_wrap.cc', 'src/v8_typed_array.cc', 'src/udp_wrap.cc', diff --git a/src/node_extensions.h b/src/node_extensions.h index 19e0777e74..d2e486d1d5 100644 --- a/src/node_extensions.h +++ b/src/node_extensions.h @@ -49,6 +49,7 @@ NODE_EXT_LIST_ITEM(node_udp_wrap) NODE_EXT_LIST_ITEM(node_pipe_wrap) NODE_EXT_LIST_ITEM(node_cares_wrap) NODE_EXT_LIST_ITEM(node_stdio_wrap) +NODE_EXT_LIST_ITEM(node_tty_wrap) NODE_EXT_LIST_ITEM(node_process_wrap) NODE_EXT_LIST_END diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc new file mode 100644 index 0000000000..692b2bbafd --- /dev/null +++ b/src/tty_wrap.cc @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +namespace node { + +using v8::Object; +using v8::Handle; +using v8::Local; +using v8::Persistent; +using v8::Value; +using v8::HandleScope; +using v8::FunctionTemplate; +using v8::String; +using v8::Function; +using v8::TryCatch; +using v8::Context; +using v8::Arguments; +using v8::Integer; +using v8::Undefined; + + +class TTYWrap : StreamWrap { + public: + static void Initialize(Handle target) { + StreamWrap::Initialize(target); + + HandleScope scope; + + Local t = FunctionTemplate::New(New); + t->SetClassName(String::NewSymbol("TTY")); + + t->InstanceTemplate()->SetInternalFieldCount(1); + + NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); + + NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); + NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop); + NODE_SET_PROTOTYPE_METHOD(t, "write", StreamWrap::Write); + NODE_SET_PROTOTYPE_METHOD(t, "write", StreamWrap::Write); + + NODE_SET_METHOD(target, "isTTY", IsTTY); + + target->Set(String::NewSymbol("TTY"), t->GetFunction()); + } + + private: + static Handle IsTTY(const Arguments& args) { + HandleScope scope; + int fd = args[0]->Int32Value(); + assert(fd >= 0); + return uv_is_tty(fd) ? v8::True() : v8::False(); + } + + static Handle New(const Arguments& args) { + HandleScope scope; + + // This constructor should not be exposed to public javascript. + // Therefore we assert that we are not trying to call this as a + // normal function. + assert(args.IsConstructCall()); + + int fd = args[0]->Int32Value(); + assert(fd >= 0); + + TTYWrap* wrap = new TTYWrap(args.This(), fd); + assert(wrap); + wrap->UpdateWriteQueueSize(); + + return scope.Close(args.This()); + } + + TTYWrap(Handle object, int fd) + : StreamWrap(object, (uv_stream_t*)&handle_) { + uv_tty_init(uv_default_loop(), &handle_, fd); + } + + uv_tty_t handle_; +}; + +} // namespace node + +NODE_MODULE(node_tty_wrap, node::TTYWrap::Initialize); diff --git a/test/simple/test-tty-wrap.js b/test/simple/test-tty-wrap.js new file mode 100644 index 0000000000..1398e1f025 --- /dev/null +++ b/test/simple/test-tty-wrap.js @@ -0,0 +1,31 @@ +var common = require('../common'); +var assert = require('assert'); + +var TTY = process.binding('tty_wrap').TTY; +var isTTY = process.binding('tty_wrap').isTTY; + +if (isTTY(1) == false) { + console.error("fd 1 is not a tty. skipping test."); + process.exit(0); +} + +var handle = new TTY(1); +var callbacks = 0; + +var req1 = handle.write(Buffer("hello world\n")); +req1.oncomplete = function() { + callbacks++; +}; + +var req2 = handle.write(Buffer("hello world\n")); +req2.oncomplete = function() { + callbacks++; +}; + +handle.close(); + +process.on('exit', function() { + assert.equal(2, callbacks); +}); + + diff --git a/wscript b/wscript index bc8d25bd46..404a722200 100644 --- a/wscript +++ b/wscript @@ -889,6 +889,7 @@ def build(bld): src/pipe_wrap.cc src/cares_wrap.cc src/stdio_wrap.cc + src/tty_wrap.cc src/process_wrap.cc src/v8_typed_array.cc """