diff --git a/lib/read.sh b/lib/read.sh index f974814..bbaa43d 100644 --- a/lib/read.sh +++ b/lib/read.sh @@ -1,29 +1,24 @@ silentRead() { - # `typeset` doesn't work in `func()` of ksh. - # `function fnc` for local-var of ksh is not compatible. - # Therefore, `_input` is not local-var on ksh. - local _input="" 2>/dev/null || typeset _input="" stty --file=/dev/tty -echo echonl 2>/dev/null || \ stty -F /dev/tty -echo echonl 2>/dev/null || \ stty -f /dev/tty -echo echonl 2>/dev/null || \ exit 1 - IFS= read -r _input /dev/null || \ stty -F /dev/tty echo -echonl 2>/dev/null || \ stty -f /dev/tty echo -echonl 2>/dev/null - printf '%s' "$_input" } if [ "$1" = "noechoback" ]; then # Try `-s` option. *ksh have it that not `--silent`. Therefore, don't try it. if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then - IFS= read -rs INPUT /dev/null || INPUT=`silentRead` || exit 1 + IFS= read -rs INPUT /dev/null || silentRead printf '\n' >/dev/tty else - INPUT=`silentRead` || exit 1 + silentRead fi else - IFS= read -r INPUT /dev/null || exit 1 fi printf '%s' "'$INPUT'" exit 0 diff --git a/lib/readline-sync.js b/lib/readline-sync.js index edb7e77..924dfd5 100644 --- a/lib/readline-sync.js +++ b/lib/readline-sync.js @@ -11,6 +11,7 @@ var IS_WIN = process.platform === 'win32', SHELL_PATH = IS_WIN ? 'cmd.exe' : '/bin/sh', + SHELL_COMMAND = __dirname + (IS_WIN ? '\\read.bat' : '/read.sh'), ALGORITHM_CIPHER = 'aes-256-cbc', ALGORITHM_HASH = 'sha256', @@ -23,20 +24,21 @@ var promptText = '> ', encoding = 'utf8', bufSize = 1024, - useShell = true, print, tempdir, salt = 0; + useShell = false, print, tempdir, salt = 0; function _readlineSync(display, options) { var input = '', buffer = new Buffer(bufSize), rsize, err; + options = options || {}; if (display !== '') { // null and undefined were excluded. if (typeof print === 'function') { print(display, encoding); } stdout.write(display + '', encoding); } - if (options && options.noEchoBack) { // Try reading via shell + if (useShell || options.noEchoBack) { // Try reading via shell - input = _readlineShell(true); + input = _readlineShell(options); if (typeof input !== 'string') { if (display !== '') { stdout.write('\n', encoding); } // Return from prompt line. throw new Error('Can\'t read via shell'); @@ -53,11 +55,9 @@ function _readlineSync(display, options) { } catch (e) { if (e.code === 'EOF') { break; } // pipe - if (useShell) { - // Try reading via shell - input = _readlineShell(); - if (typeof input === 'string') { break; } - } + // Try reading via shell + input = _readlineShell(options); + if (typeof input === 'string') { break; } // Give up... if (e.code === 'EAGAIN') { // EAGAIN, resource temporarily unavailable @@ -78,40 +78,35 @@ function _readlineSync(display, options) { } - return options && options.noTrim ? input.replace(/[\r\n]+$/, '') : input.trim(); + return options.noTrim ? input.replace(/[\r\n]+$/, '') : input.trim(); } -function _readlineShell(noEchoBack) { - var shellStdout, command, - options = { +function _readlineShell(options) { + var shellStdout, args = [], + execOptions = { env: process.env, stdio: [stdin], // ScriptPW needs piped stdin encoding: encoding - }, - optEchoBack = noEchoBack ? ' noechoback' : ''; + }; - if (IS_WIN) { - // The quote (") is escaped by node before parsed by shell. Then use ENV{Q}. - process.env.Q = '"'; - command = '%Q%' + __dirname + '\\read.bat%Q%' + optEchoBack; - } else { - command = '"' + __dirname + '/read.sh"' + optEchoBack; + if (options.noEchoBack) { + args.push('noechoback'); } stdin.pause(); // re-start in child process if (childProc.execFileSync) { shellStdout = childProc.execFileSync(SHELL_PATH, - IS_WIN ? ['/S', '/C', command] : ['-c', command], options); + [SHELL_COMMAND].concat(args), execOptions); shellStdout = shellStdout.replace(/^'|'$/g, ''); } else { - shellStdout = _execSyncByFile(command, options); + shellStdout = _execSyncByFile(args, execOptions); } return shellStdout; } // piping via files (node v0.10-) -function _execSyncByFile(command, options) { +function _execSyncByFile(args, execOptions) { function getTempfile(name) { var path = require('path'), filepath, suffix = '', fd; @@ -135,7 +130,7 @@ function _execSyncByFile(command, options) { return filepath; } - var shellStdout, + var commandArgs, shellStdout, pathStdout = getTempfile('readline-sync.stdout'), pathStatus = getTempfile('readline-sync.status'), pathDone = getTempfile('readline-sync.done'), @@ -146,20 +141,25 @@ function _execSyncByFile(command, options) { password = shasum.digest('hex'); decipher = crypto.createDecipher(ALGORITHM_CIPHER, password); - childProc.spawn(SHELL_PATH, - IS_WIN ? ['/V:ON', '/S', '/C', - command + ' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' + - ' %Q%' + ALGORITHM_CIPHER + '%Q% %Q%' + password + '%Q%' + - ' >%Q%' + pathStdout + '%Q%' + - ' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%'] : - ['-c', - 'DATA=`(' + SHELL_PATH + ' ' + command + ')`; RTN=$?;' + - ' if [ $RTN -eq 0 ]; then (printf \'%s\' "$DATA" |' + - '"' + process.execPath + '" "' + __dirname + '/encrypt.js"' + - ' "' + ALGORITHM_CIPHER + '" "' + password + '"' + - ' >"' + pathStdout + '") fi;' + - ' expr $RTN + $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"'], - options); + if (IS_WIN) { + // The quote (") is escaped by node before parsed by shell. Then use ENV{Q}. + process.env.Q = '"'; + commandArgs = ['/V:ON', '/S', '/C', + '%Q%' + SHELL_COMMAND + '%Q% ' + args.join(' ') + + ' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' + + ' %Q%' + ALGORITHM_CIPHER + '%Q% %Q%' + password + '%Q%' + + ' >%Q%' + pathStdout + '%Q%' + + ' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%']; + } else { + commandArgs = ['-c', + 'DATA=`(' + SHELL_PATH + ' "' + SHELL_COMMAND + '" ' + args.join(' ') + ')`;' + + ' RTN=$?; if [ $RTN -eq 0 ]; then (printf \'%s\' "$DATA"' + + ' |"' + process.execPath + '" "' + __dirname + '/encrypt.js"' + + ' "' + ALGORITHM_CIPHER + '" "' + password + '"' + + ' >"' + pathStdout + '") fi;' + + ' expr $RTN + $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"']; + } + childProc.spawn(SHELL_PATH, commandArgs, execOptions); while (fs.readFileSync(pathDone, {encoding: encoding}).trim() !== '1') {} if (fs.readFileSync(pathStatus, {encoding: encoding}).trim() === '0') { @@ -177,7 +177,7 @@ function _execSyncByFile(command, options) { } // for dev -//exports.useShellSet = function(use) { useShell = use; }; +exports._useShellSet = function(use) { useShell = use; }; exports.setPrint = function(fnc) { print = fnc; }; diff --git a/package.json b/package.json index 3a85ce3..acd261c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readline-sync", - "version": "0.7.2", + "version": "0.7.3", "title": "readlineSync", "description": "Synchronous Readline", "keywords": [