Don't write an undesired line-break.

This commit is contained in:
anseki 2015-03-25 21:22:44 +09:00
parent b3d633cb1c
commit e49c13d677
3 changed files with 161 additions and 93 deletions

View file

@ -3,34 +3,42 @@
var var
FSO_ForReading = 1, FSO_ForWriting = 2, FSO_ForReading = 1, FSO_ForWriting = 2,
fso, tty, shell, fso, tty,
args =// Array.prototype.slice.call(WScript.Arguments), args =// Array.prototype.slice.call(WScript.Arguments),
(function() { (function() {
var args = [], i, iLen; var args = [], i, iLen;
for (i = 0, iLen = WScript.Arguments.length; i < iLen; i++) { for (i = 0, iLen = WScript.Arguments.length; i < iLen; i++)
args.push(WScript.Arguments(i)); { args.push(WScript.Arguments(i)); }
}
return args; return args;
})(), })(),
arg, options = {}; arg, options = {};
while (typeof(arg = args.shift()) === 'string') { while (typeof(arg = args.shift()) === 'string') {
if (arg === '--noechoback') { arg = arg.toLowerCase();
if (arg === '--display') {
options.display = args.shift();
} else if (arg === '--noechoback') {
options.noEchoBack = true; options.noEchoBack = true;
} else if (arg === '--mask') {
options.mask = args.shift();
} else if (arg === '--keyin') { } else if (arg === '--keyin') {
options.keyIn = true; options.keyIn = true;
} else if (arg === '--display') {
options.display = args.shift();
} else if (arg === '--encoded') { } else if (arg === '--encoded') {
options.encoded = true; options.encoded = true;
} }
} }
if (typeof options.display === 'string' && options.display !== '') { if (options.encoded) {
writeTTY(options.encoded ? decodeDOS(options.display) : options.display); if (typeof options.display === 'string')
{ options.display = decodeDOS(options.display); }
if (typeof options.mask === 'string')
{ options.mask = decodeDOS(options.mask); }
} }
WScript.StdOut.Write("'" + (options.noEchoBack ? readS() : readTTY()) + "'"); if (typeof options.display === 'string' && options.display !== '')
{ writeTTY(options.display); }
WScript.StdOut.Write("'" + readTTY() + "'");
WScript.Quit(); WScript.Quit();
@ -46,6 +54,27 @@ function writeTTY(text) {
} }
function readTTY() { function readTTY() {
// function psExists() {
// var envPs = getShell().Environment('System')('PSModulePath');
// return typeof envPs === 'string' && envPs !== '';
// }
if (!options.noEchoBack && !options.keyIn) {
return readByCS();
// } else if (psExists()) {
// return readByPS();
} else if (options.noEchoBack && !options.keyIn && options.mask === '*') {
return readByPW();
} else {
WScript.StdErr.WriteLine('Microsoft Windows PowerShell is required.\n' +
'https://technet.microsoft.com/ja-jp/library/hh847837.aspx');
WScript.Quit(1);
}
}
function readByCS() {
WScript.StdErr.Write('<<readByCS>>'); //_DBG_
var text; var text;
try { try {
text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine(); text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine();
@ -57,32 +86,8 @@ function readTTY() {
return text; return text;
} }
function readS() { function readByPW() {
var pw; WScript.StdErr.Write('<<readByPW>>'); //_DBG_
// Microsoft Windows PowerShell https://technet.microsoft.com/ja-jp/library/hh847837.aspx
shellExec('powershell /?', function(exitCode, stdout, stderr, error) {
if (error || exitCode !== 0) {
pw = scriptPW();
} else {
shellExec('powershell -Command "$text = Read-Host -AsSecureString;' +
'$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($text);' +
'[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"',
function(exitCode, stdout, stderr, error) {
if (error || exitCode !== 0) {
WScript.StdErr.WriteLine('Windows PowerShell Error: ' + exitCode +
(error && error.description ? '\n' + error.description : '') +
(stderr ? '\n' + stderr : '') +
(stdout ? '\n' + stdout : ''));
WScript.Quit(1);
}
pw = stdout.replace(/[\r\n]+$/, '');
});
}
});
return pw;
}
function scriptPW() {
var pw; var pw;
// exit-code is not returned even if an error is thrown. // exit-code is not returned even if an error is thrown.
try { try {
@ -107,43 +112,9 @@ function getFso() {
return fso; return fso;
} }
function getShell() {
if (!shell) { shell = WScript.CreateObject('WScript.Shell'); }
return shell;
}
function shellExec(cmd, callback) { // callback(exitCode, stdout, stderr, error)
var wsExec, stdout = '', stderr = '', noOutput;
try {
wsExec = getShell().Exec(cmd);
} catch (e) {
callback(e.number, stdout, stderr, e);
return wsExec;
}
while (true) {
noOutput = true;
if (!wsExec.StdOut.AtEndOfStream) {
stdout += wsExec.StdOut.ReadAll();
noOutput = false;
}
if (!wsExec.StdErr.AtEndOfStream) {
stderr += wsExec.StdErr.ReadAll();
noOutput = false;
}
if (noOutput) {
if (wsExec.Status === 1 /*WshFinished*/) { break; }
WScript.Sleep(100);
}
}
callback(wsExec.ExitCode, stdout, stderr);
return wsExec;
}
function decodeDOS(arg) { function decodeDOS(arg) {
return (arg + '').replace(/#(\d+);/g, function(str, charCode) { return arg.replace(/#(\d+);/g, function(str, charCode) {
return String.fromCharCode(+charCode); return String.fromCharCode(+charCode);
}); });
} }

93
lib/read.ps1 Normal file
View file

@ -0,0 +1,93 @@
Param(
[string] $display,
[switch] $noEchoBack,
[string] $mask = '*',
[switch] $keyIn,
[switch] $encoded
)
$ErrorActionPreference = 'Stop' # for cmdlet
trap {
# `throw $_` and `Write-Error $_` return exit-code 0
$Host.UI.WriteErrorLine($_)
exit 1
}
function decodeDOS($arg) {
[Regex]::Replace($arg, '#(\d+);', { [char][int] $args[0].Groups[1].Value })
}
if ($encoded) {
if ($display -ne '') { $display = decodeDOS $display }
if ($mask -ne '') { $mask = decodeDOS $mask }
}
Write-Warning "[PS] display: <$display>" #_DBG
Write-Warning "[PS] noEchoBack: $noEchoBack" #_DBG
Write-Warning "[PS] mask: <$mask>" #_DBG
Write-Warning "[PS] keyIn: $keyIn" #_DBG
# Instant method that opens TTY without CreateFile via P/Invoke in .NET Framework
# **NOTE** Don't include special characters in $command when $getRes is True.
function execWithTTY ($command, $getRes = $False) {
Write-Warning "[PS] command: <$command> getRes: $getRes" #_DBG
if ($getRes) {
$res = (cmd.exe /C "<CON powershell.exe -Command $command")
if ($LastExitCode -ne 0) { exit 1 }
} else {
$command | cmd.exe /C ">CON powershell.exe -Command -"
if ($LastExitCode -ne 0) { exit 1 }
$res = ''
}
return $res
}
function writeTTY ($text) {
execWithTTY ('Write-Host ''' + ($text -replace '''', '''''') + ''' -NoNewline')
}
[string] $inputTTY = ''
if ($noEchoBack -and (-not $keyIn) -and ($mask -eq '*')) {
$inputTTY = execWithTTY ('$inputTTY = Read-Host -AsSecureString;' +
'$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputTTY);' +
'[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)') $True
return $inputTTY
}
$isEditable = (-not $noEchoBack) -and (-not $keyIn)
if ($keyIn) { $reqSize = 1 }
else { $reqSize = 1024 } # dummy
while ($True) {
if ($isEditable) {
$chunk = execWithTTY 'Read-Host' $True
$chunk += "`n"
} else { # raw
$chunk = execWithTTY '[System.Console]::ReadKey($True).KeyChar' $True
}
if ($chunk -eq '') { break }
$chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', ''
if ($chunk -eq '') { continue }
if (-not $isEditable) {
$displayInput = $chunk -replace '[\r\n]', ''
if ($displayInput -ne '') {
if ($noEchoBack) {
if ($mask -eq '') { $displayInput = '' }
else { $displayInput = $displayInput -replace '.', $mask }
}
if ($displayInput -ne '') { writeTTY $displayInput }
}
}
$inputTTY += $chunk
if (($inputTTY -match '[\r\n]$') -or ($keyIn -and ($inputTTY.Length -ge $reqSize)))
{ break }
}
if (-not $isEditable) { writeTTY "`n" } # new-line
return '''' + $inputTTY + '''' #DBG

View file

@ -27,10 +27,10 @@ var
useExt = false, useExt = false,
fdR = 'none', fdW, ttyR, isRawMode = false, fdR = 'none', fdW, ttyR, isRawMode = false,
extHostPath, extScriptPath, tempdir, salt = 0; extHostPath, extScriptPath, tempdir, salt = 0;
function readlineSync(options) { // display, mask are string function readlineSync(options) { // display, mask are string
var input = '', isEditable, displayInput; var input = '', displayTmp;
function tryExt() { function tryExt() {
var res = readlineExt(options); var res = readlineExt(options);
@ -38,14 +38,6 @@ function readlineSync(options) { // display, mask are string
return res.input; return res.input;
} }
// Node v0.10- returns an error if same mode is set.
function setRawMode(mode) {
if (mode === isRawMode) { return true; }
if (ttyR.setRawMode(mode) !== 0) { return false; }
isRawMode = mode;
return true;
}
(function() { (function() {
var fsB, constants; var fsB, constants;
@ -114,10 +106,22 @@ function readlineSync(options) { // display, mask are string
if (options.display !== '' && typeof print === 'function') if (options.display !== '' && typeof print === 'function')
{ print(options.display, encoding); } { print(options.display, encoding); }
isEditable = !options.noEchoBack && !options.keyIn;
(function() { // try read (function() { // try read
var buffer, reqSize, readSize, chunk; var buffer, reqSize, readSize, chunk, isInputLine = false,
isEditable = !options.noEchoBack && !options.keyIn;
function writeTTY(text) {
fs.writeSync(fdW, text);
isInputLine = true;
}
// Node v0.10- returns an error if same mode is set.
function setRawMode(mode) {
if (mode === isRawMode) { return true; }
if (ttyR.setRawMode(mode) !== 0) { return false; }
isRawMode = mode;
return true;
}
if (useExt || !ttyR || if (useExt || !ttyR ||
typeof fdW !== 'number' && (options.display !== '' || !isEditable)) { typeof fdW !== 'number' && (options.display !== '' || !isEditable)) {
@ -126,7 +130,7 @@ function readlineSync(options) { // display, mask are string
} }
if (options.display !== '') { if (options.display !== '') {
fs.writeSync(fdW, options.display); writeTTY(options.display);
options.display = ''; options.display = '';
} }
@ -154,12 +158,12 @@ function readlineSync(options) { // display, mask are string
if ((chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')) === '') if ((chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')) === '')
{ continue; } { continue; }
if (!isEditable && (displayInput = chunk.replace(/[\r\n]/g, '')) !== '') { if (!isEditable && (displayTmp = chunk.replace(/[\r\n]/g, '')) !== '') {
if (options.noEchoBack) { if (options.noEchoBack) {
displayInput = options.mask === '' ? '' : displayTmp = options.mask === '' ? '' :
(new Array(displayInput.length + 1)).join(options.mask); (new Array(displayTmp.length + 1)).join(options.mask);
} }
if (displayInput !== '') { fs.writeSync(fdW, displayInput); } if (displayTmp !== '') { writeTTY(displayTmp); }
} }
input += chunk; input += chunk;
@ -167,14 +171,14 @@ function readlineSync(options) { // display, mask are string
options.keyIn && input.length >= reqSize) { break; } options.keyIn && input.length >= reqSize) { break; }
} }
if (!isEditable) { fs.writeSync(fdW, '\n'); } if (!isEditable && !(options.keyIn && !isInputLine)) { writeTTY('\n'); }
setRawMode(false); setRawMode(false);
})(); })();
if (typeof print === 'function') { if (typeof print === 'function') {
displayInput = input.replace(/[\r\n]/g, ''); displayTmp = input.replace(/[\r\n]/g, '');
print((options.noEchoBack ? print((options.noEchoBack ?
(new Array(displayInput.length + 1)).join(options.mask) : displayInput) + (new Array(displayTmp.length + 1)).join(options.mask) : displayTmp) +
'\n', encoding); '\n', encoding);
} }