diff --git a/lib/console.js b/lib/console.js index 873d27c4e8..7c6134a47e 100644 --- a/lib/console.js +++ b/lib/console.js @@ -19,7 +19,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -var writeError = process.binding('stdio').writeError; +var writeError = process.writeError; var util = require('util'); exports.log = function() { diff --git a/lib/tty_uv.js b/lib/tty.js similarity index 100% rename from lib/tty_uv.js rename to lib/tty.js diff --git a/lib/tty_legacy.js b/lib/tty_legacy.js deleted file mode 100644 index 00ee9f6082..0000000000 --- a/lib/tty_legacy.js +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - - -var binding = process.binding('stdio'); - -if (process.platform === 'win32') { - exports = module.exports = require('tty_win32'); -} else { - exports = module.exports = require('tty_posix'); -} - -exports.isatty = binding.isatty; -exports.setRawMode = binding.setRawMode; -exports.getWindowSize = binding.getWindowSize; -exports.setWindowSize = binding.setWindowSize; diff --git a/lib/tty_posix.js b/lib/tty_posix.js deleted file mode 100644 index 79a660730e..0000000000 --- a/lib/tty_posix.js +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - - -var binding = process.binding('stdio'), - net = require('net'), - inherits = require('util').inherits; - - -exports.open = function(path, args) { - var fds = binding.openpty(); - - var slaveFD = fds[0]; - var masterFD = fds[1]; - - var env = { TERM: 'vt100' }; - for (var k in process.env) { - env[k] = process.env[k]; - } - - var stream = require('net').Stream(slaveFD); - stream.readable = stream.writable = true; - stream.resume(); - - - child = require('child_process').spawn(path, args, { - env: env, - customFds: [masterFD, masterFD, masterFD], - setsid: true - }); - - return [stream, child]; -}; - - -function ReadStream(fd) { - if (!(this instanceof ReadStream)) return new ReadStream(fd); - net.Socket.call(this, fd); - - if (this._writeWatcher) { - this._writeWatcher.stop(); - this._writeWatcher = null; - } - this.writable = false; - - var self = this, - keypressListeners = this.listeners('keypress'); - - function onData(b) { - if (keypressListeners.length) { - self._emitKey(b); - } else { - // Nobody's watching anyway - self.removeListener('data', onData); - self.on('newListener', onNewListener); - } - } - - function onNewListener(event) { - if (event == 'keypress') { - self.on('data', onData); - self.removeListener('newListener', onNewListener); - } - } - - this.on('newListener', onNewListener); -} -inherits(ReadStream, net.Socket); -exports.ReadStream = ReadStream; - -ReadStream.prototype.isTTY = true; - -/* - Some patterns seen in terminal key escape codes, derived from combos seen - at http://www.midnight-commander.org/browser/lib/tty/key.c - - ESC letter - ESC [ letter - ESC [ modifier letter - ESC [ 1 ; modifier letter - ESC [ num char - ESC [ num ; modifier char - ESC O letter - ESC O modifier letter - ESC O 1 ; modifier letter - ESC N letter - ESC [ [ num ; modifier char - ESC [ [ 1 ; modifier letter - ESC ESC [ num char - ESC ESC O letter - - - char is usually ~ but $ and ^ also happen with rxvt - - modifier is 1 + - (shift * 1) + - (left_alt * 2) + - (ctrl * 4) + - (right_alt * 8) - - two leading ESCs apparently mean the same as one leading ESC -*/ - -// Regexes used for ansi escape code splitting -var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/; -var functionKeyCodeRe = - /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/; - -ReadStream.prototype._emitKey = function(s) { - var char, - key = { - name: undefined, - ctrl: false, - meta: false, - shift: false - }, - parts; - - if (Buffer.isBuffer(s)) { - if (s[0] > 127 && s[1] === undefined) { - s[0] -= 128; - s = '\x1b' + s.toString(this.encoding || 'utf-8'); - } else { - s = s.toString(this.encoding || 'utf-8'); - } - } - - if (s === '\r' || s === '\n') { - // enter - key.name = 'enter'; - - } else if (s === '\t') { - // tab - key.name = 'tab'; - - } else if (s === '\b' || s === '\x7f' || - s === '\x1b\x7f' || s === '\x1b\b') { - // backspace or ctrl+h - key.name = 'backspace'; - key.meta = (s.charAt(0) === '\x1b'); - - } else if (s === '\x1b' || s === '\x1b\x1b') { - // escape key - key.name = 'escape'; - key.meta = (s.length === 2); - - } else if (s === ' ' || s === '\x1b ') { - key.name = 'space'; - key.meta = (s.length === 2); - - } else if (s <= '\x1a') { - // ctrl+letter - key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1); - key.ctrl = true; - - } else if (s.length === 1 && s >= 'a' && s <= 'z') { - // lowercase letter - key.name = s; - - } else if (s.length === 1 && s >= 'A' && s <= 'Z') { - // shift+letter - key.name = s.toLowerCase(); - key.shift = true; - - } else if (parts = metaKeyCodeRe.exec(s)) { - // meta+character key - key.name = parts[1].toLowerCase(); - key.meta = true; - key.shift = /^[A-Z]$/.test(parts[1]); - - } else if (parts = functionKeyCodeRe.exec(s)) { - // ansi escape sequence - - // reassemble the key code leaving out leading \x1b's, - // the modifier key bitflag and any meaningless "1;" sequence - var code = (parts[1] || '') + (parts[2] || '') + - (parts[4] || '') + (parts[6] || ''), - modifier = (parts[3] || parts[5] || 1) - 1; - - // Parse the key modifier - key.ctrl = !!(modifier & 4); - key.meta = !!(modifier & 10); - key.shift = !!(modifier & 1); - - // Parse the key itself - switch (code) { - /* xterm/gnome ESC O letter */ - case 'OP': key.name = 'f1'; break; - case 'OQ': key.name = 'f2'; break; - case 'OR': key.name = 'f3'; break; - case 'OS': key.name = 'f4'; break; - - /* xterm/rxvt ESC [ number ~ */ - case '[11~': key.name = 'f1'; break; - case '[12~': key.name = 'f2'; break; - case '[13~': key.name = 'f3'; break; - case '[14~': key.name = 'f4'; break; - - /* common */ - case '[15~': key.name = 'f5'; break; - case '[17~': key.name = 'f6'; break; - case '[18~': key.name = 'f7'; break; - case '[19~': key.name = 'f8'; break; - case '[20~': key.name = 'f9'; break; - case '[21~': key.name = 'f10'; break; - case '[23~': key.name = 'f11'; break; - case '[24~': key.name = 'f12'; break; - - /* xterm ESC [ letter */ - case '[A': key.name = 'up'; break; - case '[B': key.name = 'down'; break; - case '[C': key.name = 'right'; break; - case '[D': key.name = 'left'; break; - case '[E': key.name = 'clear'; break; - case '[F': key.name = 'end'; break; - case '[H': key.name = 'home'; break; - - /* xterm/gnome ESC O letter */ - case 'OA': key.name = 'up'; break; - case 'OB': key.name = 'down'; break; - case 'OC': key.name = 'right'; break; - case 'OD': key.name = 'left'; break; - case 'OE': key.name = 'clear'; break; - case 'OF': key.name = 'end'; break; - case 'OH': key.name = 'home'; break; - - /* xterm/rxvt ESC [ number ~ */ - case '[1~': key.name = 'home'; break; - case '[2~': key.name = 'insert'; break; - case '[3~': key.name = 'delete'; break; - case '[4~': key.name = 'end'; break; - case '[5~': key.name = 'pageup'; break; - case '[6~': key.name = 'pagedown'; break; - - /* putty */ - case '[[5~': key.name = 'pageup'; break; - case '[[6~': key.name = 'pagedown'; break; - - /* rxvt */ - case '[7~': key.name = 'home'; break; - case '[8~': key.name = 'end'; break; - - /* rxvt keys with modifiers */ - case '[a': key.name = 'up'; key.shift = true; break; - case '[b': key.name = 'down'; key.shift = true; break; - case '[c': key.name = 'right'; key.shift = true; break; - case '[d': key.name = 'left'; key.shift = true; break; - case '[e': key.name = 'clear'; key.shift = true; break; - - case '[2$': key.name = 'insert'; key.shift = true; break; - case '[3$': key.name = 'delete'; key.shift = true; break; - case '[5$': key.name = 'pageup'; key.shift = true; break; - case '[6$': key.name = 'pagedown'; key.shift = true; break; - case '[7$': key.name = 'home'; key.shift = true; break; - case '[8$': key.name = 'end'; key.shift = true; break; - - case 'Oa': key.name = 'up'; key.ctrl = true; break; - case 'Ob': key.name = 'down'; key.ctrl = true; break; - case 'Oc': key.name = 'right'; key.ctrl = true; break; - case 'Od': key.name = 'left'; key.ctrl = true; break; - case 'Oe': key.name = 'clear'; key.ctrl = true; break; - - case '[2^': key.name = 'insert'; key.ctrl = true; break; - case '[3^': key.name = 'delete'; key.ctrl = true; break; - case '[5^': key.name = 'pageup'; key.ctrl = true; break; - case '[6^': key.name = 'pagedown'; key.ctrl = true; break; - case '[7^': key.name = 'home'; key.ctrl = true; break; - case '[8^': key.name = 'end'; key.ctrl = true; break; - - /* misc. */ - case '[Z': key.name = 'tab'; key.shift = true; break; - - } - } else if (s.length > 1 && s[0] !== '\x1b') { - // Got a longer-than-one string of characters. - // Probably a paste, since it wasn't a control sequence. - Array.prototype.forEach.call(s, this._emitKey, this); - return; - } - - // Don't emit a key if no name was found - if (key.name === undefined) { - key = undefined; - } - - if (s.length === 1) { - char = s; - } - - if (key || char) { - this.emit('keypress', char, key); - } -}; - - -function WriteStream(fd) { - if (!(this instanceof WriteStream)) return new WriteStream(fd); - net.Socket.call(this, fd); - - if (this._readWatcher) { - this._readWatcher.stop(); - this._readWatcher = null; - } - this.readable = false; -} -inherits(WriteStream, net.Socket); -exports.WriteStream = WriteStream; - -WriteStream.prototype.isTTY = true; - -WriteStream.prototype.cursorTo = function(x, y) { - if (typeof x !== 'number' && typeof y !== 'number') - return; - - if (typeof x !== 'number') - throw new Error("Can't set cursor row without also setting it's column"); - - if (typeof y !== 'number') { - this.write('\x1b[' + (x + 1) + 'G'); - } else { - this.write('\x1b[' + (y + 1) + ';' + (x + 1) + 'H'); - } -}; - -WriteStream.prototype.moveCursor = function(dx, dy) { - if (dx < 0) { - this.write('\x1b[' + (-dx) + 'D'); - } else if (dx > 0) { - this.write('\x1b[' + dx + 'C'); - } - - if (dy < 0) { - this.write('\x1b[' + (-dy) + 'A'); - } else if (dy > 0) { - this.write('\x1b[' + dy + 'B'); - } -}; - -WriteStream.prototype.clearLine = function(dir) { - if (dir < 0) { - // to the beginning - this.write('\x1b[1K'); - } else if (dir > 0) { - // to the end - this.write('\x1b[0K'); - } else { - // entire line - this.write('\x1b[2K'); - } -}; - diff --git a/lib/tty_win32.js b/lib/tty_win32.js deleted file mode 100644 index 7f88fa6483..0000000000 --- a/lib/tty_win32.js +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - - -var binding = process.binding('stdio'), - Stream = require('stream').Stream, - inherits = require('util').inherits, - writeTTY = binding.writeTTY, - closeTTY = binding.closeTTY; - - -function ReadStream(fd) { - if (!(this instanceof ReadStream)) return new ReadStream(fd); - Stream.call(this); - - var self = this; - this.fd = fd; - this.paused = true; - this.readable = true; - - var dataListeners = this.listeners('data'), - dataUseString = false; - - function onError(err) { - self.emit('error', err); - } - function onKeypress(char, key) { - self.emit('keypress', char, key); - if (dataListeners.length && char) { - self.emit('data', dataUseString ? char : new Buffer(char, 'utf-8')); - } - } - function onResize() { - process.emit('SIGWINCH'); - } - - // A windows console stream is always UTF-16, actually - // So it makes no sense to set the encoding, however someone could call - // setEncoding to tell us he wants strings not buffers - this.setEncoding = function(encoding) { - dataUseString = !!encoding; - } - - binding.initTTYWatcher(fd, onError, onKeypress, onResize); -} -inherits(ReadStream, Stream); -exports.ReadStream = ReadStream; - -ReadStream.prototype.isTTY = true; - -ReadStream.prototype.pause = function() { - if (this.paused) - return; - - this.paused = true; - binding.stopTTYWatcher(); -}; - -ReadStream.prototype.resume = function() { - if (!this.readable) - throw new Error('Cannot resume() closed tty.ReadStream.'); - if (!this.paused) - return; - - this.paused = false; - binding.startTTYWatcher(); -}; - -ReadStream.prototype.destroy = function() { - if (!this.readable) - return; - - this.readable = false; - binding.destroyTTYWatcher(); - - var self = this; - process.nextTick(function() { - try { - closeTTY(self.fd); - self.emit('close'); - } catch (err) { - self.emit('error', err); - } - }); -}; - -ReadStream.prototype.destroySoon = ReadStream.prototype.destroy; - - -function WriteStream(fd) { - if (!(this instanceof WriteStream)) return new WriteStream(fd); - Stream.call(this); - - var self = this; - this.fd = fd; - this.writable = true; -} -inherits(WriteStream, Stream); -exports.WriteStream = WriteStream; - -WriteStream.prototype.isTTY = true; - -WriteStream.prototype.write = function(data, encoding) { - if (!this.writable) { - this.emit('error', new Error('stream not writable')); - return false; - } - - if (Buffer.isBuffer(data)) { - data = data.toString('utf-8'); - } - - try { - writeTTY(this.fd, data); - } catch (err) { - this.emit('error', err); - } - return true; -}; - -WriteStream.prototype.end = function(data, encoding) { - if (data) { - this.write(data, encoding); - } - this.destroy(); -}; - -WriteStream.prototype.destroy = function() { - if (!this.writable) - return; - - this.writable = false; - - var self = this; - process.nextTick(function() { - var closed = false; - try { - closeTTY(self.fd); - closed = true; - } catch (err) { - self.emit('error', err); - } - if (closed) { - self.emit('close'); - } - }); -}; - -WriteStream.prototype.moveCursor = function(dx, dy) { - if (!this.writable) - throw new Error('Stream not writable'); - - binding.moveCursor(this.fd, dx, dy); -}; - -WriteStream.prototype.cursorTo = function(x, y) { - if (!this.writable) - throw new Error('Stream not writable'); - - binding.cursorTo(this.fd, x, y); -}; - -WriteStream.prototype.clearLine = function(direction) { - if (!this.writable) - throw new Error('Stream not writable'); - - binding.clearLine(this.fd, direction || 0); -}; diff --git a/lib/util.js b/lib/util.js index 500cbaad8a..07d1421399 100644 --- a/lib/util.js +++ b/lib/util.js @@ -72,13 +72,13 @@ exports.puts = function() { exports.debug = function(x) { - process.binding('stdio').writeError('DEBUG: ' + x + '\n'); + process.writeError('DEBUG: ' + x + '\n'); }; var error = exports.error = function(x) { for (var i = 0, len = arguments.length; i < len; ++i) { - process.binding('stdio').writeError(arguments[i] + '\n'); + process.writeError(arguments[i] + '\n'); } }; diff --git a/node.gyp b/node.gyp index 87ba666480..8068ea17e3 100644 --- a/node.gyp +++ b/node.gyp @@ -39,10 +39,7 @@ 'lib/sys.js', 'lib/timers.js', 'lib/tls.js', - 'lib/tty_legacy.js', - 'lib/tty_posix.js', - 'lib/tty_uv.js', - 'lib/tty_win32.js', + 'lib/tty.js', 'lib/url.js', 'lib/util.js', 'lib/vm.js', @@ -109,7 +106,6 @@ 'src/node_os.h', 'src/node_root_certs.h', 'src/node_script.h', - 'src/node_stdio.h', 'src/node_string.h', 'src/node_version.h', 'src/pipe_wrap.h', @@ -153,7 +149,6 @@ [ 'OS=="win"', { 'sources': [ 'src/platform_win32.cc', - 'src/node_stdio_win32.cc', # headers to make for a more pleasant IDE experience 'src/platform_win32.h', ], @@ -169,7 +164,6 @@ 'src/node_signal_watcher.cc', 'src/node_stat_watcher.cc', 'src/node_io_watcher.cc', - 'src/node_stdio.cc', ] }], [ 'OS=="mac"', { diff --git a/src/node.cc b/src/node.cc index e5bdd3564a..9552905d80 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1236,7 +1236,8 @@ void DisplayExceptionLine (TryCatch &try_catch) { Handle message = try_catch.Message(); - node::Stdio::DisableRawMode(STDIN_FILENO); + uv_tty_reset_mode(); + fprintf(stderr, "\n"); if (!message.IsEmpty()) { @@ -1338,6 +1339,34 @@ Local ExecuteString(Handle source, Handle filename) { } +/* STDERR IS ALWAY SYNC ALWAYS UTF8 */ +static Handle WriteError (const Arguments& args) { + HandleScope scope; + + if (args.Length() < 1) { + return Undefined(); + } + + String::Utf8Value msg(args[0]->ToString()); + + ssize_t r; + size_t written = 0; + while (written < (size_t) msg.length()) { + r = write(STDERR_FILENO, (*msg) + written, msg.length() - written); + if (r < 0) { + if (errno == EAGAIN || errno == EIO) { + usleep(100); + continue; + } + return ThrowException(ErrnoException(errno, "write")); + } + written += (size_t)r; + } + + return True(); +} + + static Handle Chdir(const Arguments& args) { HandleScope scope; @@ -2174,6 +2203,8 @@ Handle SetupProcessObject(int argc, char *argv[]) { NODE_SET_METHOD(process, "chdir", Chdir); NODE_SET_METHOD(process, "cwd", Cwd); + NODE_SET_METHOD(process, "writeError", WriteError); + NODE_SET_METHOD(process, "umask", Umask); #ifdef __POSIX__ @@ -2198,7 +2229,6 @@ Handle SetupProcessObject(int argc, char *argv[]) { static void AtExit() { - node::Stdio::Flush(); uv_tty_reset_mode(); } diff --git a/src/node.js b/src/node.js index 7626bb101d..e9e0566832 100644 --- a/src/node.js +++ b/src/node.js @@ -458,9 +458,6 @@ // backend. function translateId(id) { switch (id) { - case 'tty': - return process.features.uv ? 'tty_uv' : 'tty_legacy'; - default: return id; } diff --git a/src/node_extensions.h b/src/node_extensions.h index 6f146544cd..39ddf1748f 100644 --- a/src/node_extensions.h +++ b/src/node_extensions.h @@ -31,7 +31,6 @@ NODE_EXT_LIST_ITEM(node_http_parser) #ifdef __POSIX__ NODE_EXT_LIST_ITEM(node_signal_watcher) #endif -NODE_EXT_LIST_ITEM(node_stdio) NODE_EXT_LIST_ITEM(node_os) NODE_EXT_LIST_ITEM(node_zlib) diff --git a/wscript b/wscript index a352893849..4858349a51 100644 --- a/wscript +++ b/wscript @@ -899,13 +899,10 @@ def build(bld): src/v8_typed_array.cc """ - if sys.platform.startswith("win32"): - node.source += " src/node_stdio_win32.cc " - else: + if not sys.platform.startswith("win32"): node.source += " src/node_signal_watcher.cc " node.source += " src/node_stat_watcher.cc " node.source += " src/node_io_watcher.cc " - node.source += " src/node_stdio.cc " node.source += bld.env["PLATFORM_FILE"] if not product_type_is_lib: