Add display to shell script.

This commit is contained in:
anseki 2015-03-11 17:06:27 +09:00
parent e552f97db1
commit 16c0c476cd
4 changed files with 143 additions and 82 deletions

10
lib/decodedos.js Normal file
View file

@ -0,0 +1,10 @@
process.stdout.write(decodeDOS(process.argv[2] /*text*/ || ''),
process.env.RLS_ENCODING || 'binary', function() {
process.exit(0);
});
function decodeDOS(arg) {
return arg.replace(/#(\d+);/g, function(str, charCode) {
return String.fromCharCode(+charCode);
});
}

View file

@ -1,14 +1,39 @@
@echo off @echo off
setlocal
setlocal ENABLEDELAYEDEXPANSION setlocal ENABLEDELAYEDEXPANSION
if "%~1"=="noechoback" ( :args_loop
if "%~1"=="" (
goto args_end
) else if "%~1"=="--noechoback" (
set noechoback=1
) else if "%~1"=="--keyin" (
set keyin=1
) else if "%~1"=="--display" (
set "display=%~2"
shift /1
)
shift /1
goto args_loop
:args_end
:: type tmpfile.txt >CON
if "%display%" NEQ "" if "%NODE_EXEC_PATH%" NEQ "" (
"%NODE_EXEC_PATH%" "%~dp0decodedos.js" "%display%" >CON
if ERRORLEVEL 1 exit /b 1
)
if "%noechoback%"=="1" (
call :read_s call :read_s
if ERRORLEVEL 1 exit /b 1 if ERRORLEVEL 1 exit /b 1
) else ( ) else (
set /p INPUT=<CON >CON set /p input=<CON >CON
) )
set /p ="'%INPUT%'"<NUL set /p ="'%input%'"<NUL
endlocal endlocal
exit /b 0 exit /b 0
@ -22,21 +47,22 @@ powershell /? >NUL 2>&1
:: Win XP and Server2003 have `ScriptPW` (`scriptpw.dll`). :: Win XP and Server2003 have `ScriptPW` (`scriptpw.dll`).
:: In the systems that don't have both, an error is thrown. :: In the systems that don't have both, an error is thrown.
if ERRORLEVEL 1 ( if ERRORLEVEL 1 (
set "EXECOMMAND=cscript //nologo "%~dp0read.cs.js"" set "exec_line=cscript //nologo "%~dp0read.cs.js""
) else ( ) else (
set "EXECOMMAND=powershell -Command "$text = read-host -AsSecureString; ^ set "exec_line=powershell -Command "$text = read-host -AsSecureString; ^
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR^($text^); ^ $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR^($text^); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto^($BSTR^)"" [System.Runtime.InteropServices.Marshal]::PtrToStringAuto^($BSTR^)""
) )
:: Can't get `ERRORLEVEL` from sub-shell (`for`). :: Can't get `ERRORLEVEL` from sub-shell.
:: 2 `%ERRCODE%` lines are returned if an error is thrown. :: 2 `%ERRCODE%` lines are returned if an error is thrown.
set ERRCODE=ERR set ERRCODE=ERR
set "EXECOMMAND=%EXECOMMAND% ^& if ERRORLEVEL 1 ^(echo %ERRCODE%^& echo %ERRCODE%^)" set "exec_line=%exec_line% ^& if ERRORLEVEL 1 ^(echo %ERRCODE%^& echo %ERRCODE%^)"
:: echo %EXECOMMAND% :: echo %exec_line%
for /f "usebackq delims=" %%i in (`%EXECOMMAND%`) do ( for /f "usebackq delims=" %%i in (`%exec_line%`) do (
if "%%i"=="%ERRCODE%" if "!INPUT!"=="%ERRCODE%" exit /b 1 if "%%i"=="%ERRCODE%" if "!input!"=="%ERRCODE%" exit /b 1
set "INPUT=%%i" set "input=%%i"
) )
exit /b 0 exit /b 0

View file

@ -3,21 +3,36 @@ read_s() {
stty --file=/dev/tty -echo echonl 2>/dev/null || \ 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 || \
stty -f /dev/tty -echo echonl || exit 1 stty -f /dev/tty -echo echonl || exit 1
IFS= read -r INPUT </dev/tty || exit 1 IFS= read -r input </dev/tty || exit 1
stty --file=/dev/tty echo -echonl 2>/dev/null || \ 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 || \
stty -f /dev/tty echo -echonl || exit 1 stty -f /dev/tty echo -echonl || exit 1
} }
if [ "$1" = "noechoback" ]; then # getopt(s)
while [ $# -ge 1 ]; do
case "$1" in
"--noechoback") noechoback=1;;
"--keyin") keyin=1;;
"--display") shift; display=$1;;
esac
shift
done
if [ -n "$display" ]; then
printf '%s' "$display" >/dev/tty
fi
if [ "$noechoback" = "1" ]; then
# Try `-s` option. *ksh have it that not `--silent`. Therefore, don't try it. # Try `-s` option. *ksh have it that not `--silent`. Therefore, don't try it.
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
IFS= read -rs INPUT </dev/tty 2>/dev/null && printf '\n' >/dev/tty || read_s IFS= read -rs input </dev/tty 2>/dev/null && printf '\n' >/dev/tty || read_s
else else
read_s read_s
fi fi
else else
IFS= read -r INPUT </dev/tty || exit 1 IFS= read -r input </dev/tty || exit 1
fi fi
printf '%s' "'$INPUT'" printf '%s' "'$input'"
exit 0 exit 0

View file

@ -10,7 +10,7 @@
var var
IS_WIN = process.platform === 'win32', IS_WIN = process.platform === 'win32',
SHELL_PATH = IS_WIN ? process.env.comspec || 'cmd.exe' : '/bin/sh', SHELL_PATH = IS_WIN ? process.env.ComSpec || 'cmd.exe' : '/bin/sh',
SHELL_CMD = __dirname + (IS_WIN ? '\\read.bat' : '/read.sh'), SHELL_CMD = __dirname + (IS_WIN ? '\\read.bat' : '/read.sh'),
ALGORITHM_CIPHER = 'aes-256-cbc', ALGORITHM_CIPHER = 'aes-256-cbc',
ALGORITHM_HASH = 'sha256', ALGORITHM_HASH = 'sha256',
@ -39,8 +39,6 @@ function _readlineSync(options) { // options.display is string
if (IS_WIN) { // r/w mode not supported if (IS_WIN) { // r/w mode not supported
if (process.stdin.isTTY && process.stdout.isTTY) { if (process.stdin.isTTY && process.stdout.isTTY) {
console.warn('STD TRY');
if (options.display !== '') { if (options.display !== '') {
// process.stdout.write(options.display, encoding); // process.stdout.write(options.display, encoding);
fs.writeSync(process.stdout.fd, options.display); fs.writeSync(process.stdout.fd, options.display);
@ -48,12 +46,9 @@ function _readlineSync(options) { // options.display is string
} }
fd = process.stdin.fd; fd = process.stdin.fd;
isOpened = true; isOpened = true;
console.warn('STD OK');
} else { } else {
try { try {
console.warn('CON TRY');
if (options.display !== '') { if (options.display !== '') {
fd = fs.openSync('\\\\.\\CON', 'w'); fd = fs.openSync('\\\\.\\CON', 'w');
fs.writeSync(fd, options.display); fs.writeSync(fd, options.display);
@ -62,13 +57,10 @@ function _readlineSync(options) { // options.display is string
} }
fd = fs.openSync('\\\\.\\CON', 'rs'); fd = fs.openSync('\\\\.\\CON', 'rs');
isOpened = true; isOpened = true;
console.warn('CON OK');
} catch (e) {} } catch (e) {}
if (!isOpened || options.display !== '') { // Retry if (!isOpened || options.display !== '') { // Retry
try { try {
console.warn('CONINOUT TRY');
// For raw device path // For raw device path
// On XP, 2000, 7 (x86), it might fail. // On XP, 2000, 7 (x86), it might fail.
// And, process.binding('fs') might be no good. // And, process.binding('fs') might be no good.
@ -84,24 +76,19 @@ function _readlineSync(options) { // options.display is string
fd = fsBind.open('CONIN$', fd = fsBind.open('CONIN$',
constBind.O_RDWR | constBind.O_SYNC, parseInt('0666', 8)); constBind.O_RDWR | constBind.O_SYNC, parseInt('0666', 8));
isOpened = true; isOpened = true;
console.warn('CONINOUT OK');
} catch (e) {} } catch (e) {}
}
}
}
}
} else { } else {
try { try {
console.warn('/dev/tty TRY');
fd = fs.openSync('/dev/tty', 'rs+'); fd = fs.openSync('/dev/tty', 'rs+');
isOpened = true; isOpened = true;
if (options.display !== '') { if (options.display !== '') {
fs.writeSync(fd, options.display); fs.writeSync(fd, options.display);
options.display = ''; options.display = '';
} }
console.warn('/dev/tty OK');
} catch (e) {} } catch (e) {}
} }
if (isOpened && options.display === '') { if (isOpened && options.display === '') {
@ -148,12 +135,26 @@ function _readlineShell(options) {
encoding: encoding encoding: encoding
}; };
if (options.noEchoBack) { // To send any text to crazy Windows shell safely.
cmdArgs.push('noechoback'); function encodeDOS(arg) {
return arg.replace(/[^\w\u0080-\uFFFF]/g, function(chr) {
return '#' + chr.charCodeAt(0) + ';';
});
}
if (options.keyIn) { cmdArgs.push('--keyin'); }
else if (options.noEchoBack) { cmdArgs.push('--noechoback'); }
if (options.display !== '') {
if (IS_WIN) {
cmdArgs.push('--display', encodeDOS(options.display));
process.env.NODE_EXEC_PATH = process.execPath;
process.env.RLS_ENCODING = encoding;
} else {
cmdArgs.push('--display', options.display);
}
} }
if (childProc.execFileSync) { if (childProc.execFileSync) {
console.warn('execFileSync');
if (IS_WIN) { if (IS_WIN) {
process.env.Q = '"'; // The quote (") that isn't escaped. process.env.Q = '"'; // The quote (") that isn't escaped.
execArgs = ['/V:ON', '/S', '/C', execArgs = ['/V:ON', '/S', '/C',
@ -173,10 +174,10 @@ function _readlineShell(options) {
res.error.shellMessage = e.stderr.trim(); res.error.shellMessage = e.stderr.trim();
} }
} else { } else {
console.warn('_execSyncByFile');
res = _execSyncByFile(cmdArgs, execOptions); res = _execSyncByFile(cmdArgs, execOptions);
} }
if (!res.error) { res.input = res.input.replace(/^'|'$/g, ''); } if (!res.error) { res.input = res.input.replace(/^'|'$/g, ''); }
options.display = '';
return res; return res;
} }
@ -222,7 +223,7 @@ function _execSyncByFile(cmdArgs, execOptions) {
process.env.Q = '"'; // The quote (") that isn't escaped. process.env.Q = '"'; // The quote (") that isn't escaped.
// `()` for ignore space by echo // `()` for ignore space by echo
execArgs = ['/V:ON', '/S', '/C', execArgs = ['/V:ON', '/S', '/C',
'(' + SHELL_PATH + ' /V:ON /S /C %Q%%Q%' + SHELL_CMD + '%Q%' + '(%Q%' + SHELL_PATH + '%Q% /V:ON /S /C %Q%%Q%' + SHELL_CMD + '%Q%' +
cmdArgs.map(function(arg) { return ' %Q%' + arg + '%Q%'; }).join('') + cmdArgs.map(function(arg) { return ' %Q%' + arg + '%Q%'; }).join('') +
' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q%%Q%) 2>%Q%' + pathStderr + '%Q%' + ' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q%%Q%) 2>%Q%' + pathStderr + '%Q%' +
' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' + ' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' +
@ -232,8 +233,9 @@ function _execSyncByFile(cmdArgs, execOptions) {
} else { } else {
execArgs = ['-c', execArgs = ['-c',
// Use `()`, not `{}` for `-c` (text param) // Use `()`, not `{}` for `-c` (text param)
'(' + SHELL_PATH + ' "' + SHELL_CMD + '"' + '("' + SHELL_PATH + '" "' + SHELL_CMD + '"' +
cmdArgs.map(function(arg) { return ' "' + arg + '"'; }).join('') + cmdArgs.map(function(arg)
{ return ' "' + arg.replace(/[\\"`]/g, '\\\$&') + '"'; }).join('') +
'; echo $?>"' + pathStatus + '") 2>"' + pathStderr + '"' + '; echo $?>"' + pathStatus + '") 2>"' + pathStderr + '"' +
' |"' + process.execPath + '" "' + __dirname + '/encrypt.js"' + ' |"' + process.execPath + '" "' + __dirname + '/encrypt.js"' +
' "' + ALGORITHM_CIPHER + '" "' + password + '"' + ' "' + ALGORITHM_CIPHER + '" "' + password + '"' +
@ -292,27 +294,35 @@ exports.setBufferSize = function(newBufSize) {
}; };
exports.prompt = function(options) { exports.prompt = function(options) {
options = options || {}; var readOptions = {
options.display = promptText + ''; display: promptText + '',
options.keyIn = false; noEchoBack: options.noEchoBack,
return _readlineSync(options); keyIn: false,
noTrim: options.noTrim
};
return _readlineSync(readOptions);
}; };
exports.question = function(query, options) { exports.question = function(query, options) {
options = options || {}; var readOptions = {
/* jshint eqnull:true */ /* jshint eqnull:true */
options.display = query != null ? query + '' : ''; display: query != null ? query + '' : '',
/* jshint eqnull:false */ /* jshint eqnull:false */
options.keyIn = false; noEchoBack: options.noEchoBack,
return _readlineSync(options); keyIn: false,
noTrim: options.noTrim
};
return _readlineSync(readOptions);
}; };
exports.keyIn = function(query, options) { exports.keyIn = function(query, options) {
options = options || {}; var readOptions = {
/* jshint eqnull:true */ /* jshint eqnull:true */
options.display = query != null ? query + '' : ''; display: query != null ? query + '' : '',
/* jshint eqnull:false */ /* jshint eqnull:false */
options.keyIn = true; noEchoBack: false,
options.noEchoBack = false; keyIn: true,
return _readlineSync(options); noTrim: true
};
return _readlineSync(readOptions);
}; };