Add: options.limit
, options.caseSensitive
This commit is contained in:
parent
b4bdf19667
commit
63e5ad583e
4 changed files with 133 additions and 103 deletions
|
@ -60,10 +60,10 @@ var
|
|||
});
|
||||
|
||||
if (!options.noEchoBack && !options.keyIn) {
|
||||
if (options.display !== '') { writeTTY(options.display); }
|
||||
if (options.display) { writeTTY(options.display); }
|
||||
input = readByFSO();
|
||||
} else if (options.noEchoBack && !options.keyIn && options.mask === '') {
|
||||
if (options.display !== '') { writeTTY(options.display); }
|
||||
} else if (options.noEchoBack && !options.keyIn && !options.mask) {
|
||||
if (options.display) { writeTTY(options.display); }
|
||||
input = readByPW();
|
||||
} else {
|
||||
WScript.StdErr.WriteLine(PS_MSG);
|
||||
|
|
76
lib/read.ps1
76
lib/read.ps1
|
@ -9,7 +9,7 @@ Param(
|
|||
[switch] $keyIn,
|
||||
[switch] $noEchoBack,
|
||||
[string] $mask,
|
||||
[string] $exclude,
|
||||
[string] $limit,
|
||||
[switch] $cs,
|
||||
[switch] $encoded
|
||||
)
|
||||
|
@ -26,23 +26,22 @@ function decodeDOS ($arg) {
|
|||
}
|
||||
|
||||
$options = @{}
|
||||
foreach ($arg in @('display', 'keyIn', 'noEchoBack', 'mask', 'exclude', 'cs', 'encoded')) {
|
||||
foreach ($arg in @('display', 'keyIn', 'noEchoBack', 'mask', 'limit', 'cs', 'encoded')) {
|
||||
$options.Add($arg, (Get-Variable $arg -ValueOnly))
|
||||
}
|
||||
if ($options.encoded) {
|
||||
$argList = New-Object string[] $options.Keys.Count
|
||||
$options.Keys.CopyTo($argList, 0);
|
||||
$options.Keys.CopyTo($argList, 0)
|
||||
foreach ($arg in $argList) {
|
||||
if (($options[$arg] -is [string]) -and ($options[$arg] -ne ''))
|
||||
if ($options[$arg] -is [string] -and $options[$arg])
|
||||
{ $options[$arg] = decodeDOS $options[$arg] }
|
||||
}
|
||||
}
|
||||
|
||||
[string] $inputTTY = ''
|
||||
[string] $displaySave = $options.display
|
||||
[bool] $silent = (-not $options.display) -and
|
||||
$options.keyIn -and $options.noEchoBack -and (-not $options.mask)
|
||||
[bool] $isCooked = (-not $options.noEchoBack) -and (-not $options.keyIn)
|
||||
[bool] $silent = -not $options.display -and
|
||||
$options.keyIn -and $options.noEchoBack -and -not $options.mask
|
||||
[bool] $isCooked = -not $options.noEchoBack -and -not $options.keyIn
|
||||
|
||||
# Instant method that opens TTY without CreateFile via P/Invoke in .NET Framework
|
||||
# **NOTE** Don't include special characters of DOS in $command when $getRes is True.
|
||||
|
@ -63,49 +62,58 @@ function writeTTY ($text) {
|
|||
execWithTTY ('Write-Host ''' + ($text -replace '''', '''''') + ''' -NoNewline')
|
||||
}
|
||||
|
||||
if ($options.display -ne '') {
|
||||
if ($options.display) {
|
||||
writeTTY $options.display
|
||||
$options.display = ''
|
||||
}
|
||||
|
||||
if ((-not $options.keyIn) -and $options.noEchoBack -and ($options.mask -eq '*')) {
|
||||
$inputTTY = execWithTTY ('$inputTTY = Read-Host -AsSecureString;' +
|
||||
'$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputTTY);' +
|
||||
'[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)') $True
|
||||
if (-not $options.keyIn -and $options.noEchoBack -and $options.mask -eq '*') {
|
||||
$inputTTY = execWithTTY ('$text = Read-Host -AsSecureString;' +
|
||||
'$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($text);' +
|
||||
'[Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)') $True
|
||||
return '''' + $inputTTY + ''''
|
||||
}
|
||||
|
||||
if ($options.keyIn) { $reqSize = 1 }
|
||||
|
||||
while ($True) {
|
||||
if (-not $isCooked) {
|
||||
$chunk = execWithTTY '[System.Console]::ReadKey($True).KeyChar' $True
|
||||
# ReadKey() may returns [System.Array], then don't cast data.
|
||||
if ($chunk -isnot [string]) { $chunk = '' }
|
||||
$chunk = $chunk -replace '[\r\n]', ''
|
||||
if ($chunk -eq '') { $atEol = $True } # NL or empty-text was input
|
||||
} else {
|
||||
$chunk = execWithTTY 'Read-Host' $True
|
||||
$chunk = $chunk -replace '[\r\n]', ''
|
||||
$atEol = $True
|
||||
if ($options.keyIn -and $options.limit) {
|
||||
$limitPtn = '[^' + $options.limit + ']'
|
||||
}
|
||||
|
||||
# other ctrl-chars
|
||||
$chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', ''
|
||||
while ($True) {
|
||||
if (-not $isCooked) {
|
||||
$chunk = [char][int] (execWithTTY '[int] [Console]::ReadKey($True).KeyChar' $True)
|
||||
} else {
|
||||
$chunk = execWithTTY 'Read-Host' $True
|
||||
$chunk += "`n"
|
||||
}
|
||||
|
||||
if ($chunk -ne '' -and (-not $isCooked)) {
|
||||
if ($chunk -and $chunk -match '^(.*?)[\r\n]') {
|
||||
$chunk = $Matches[1]
|
||||
$atEol = $True
|
||||
} else { $atEol = $False }
|
||||
|
||||
# other ctrl-chars
|
||||
if ($chunk) { $chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '' }
|
||||
if ($chunk -and $limitPtn) {
|
||||
if ($options.cs) { $chunk = $chunk -creplace $limitPtn, '' }
|
||||
else { $chunk = $chunk -ireplace $limitPtn, '' }
|
||||
}
|
||||
|
||||
if ($chunk) {
|
||||
if (-not $isCooked) {
|
||||
if (-not $options.noEchoBack) {
|
||||
writeTTY $chunk
|
||||
} elseif ($options.mask -ne '') {
|
||||
} elseif ($options.mask) {
|
||||
writeTTY ($options.mask * $chunk.Length)
|
||||
}
|
||||
}
|
||||
|
||||
$inputTTY += $chunk
|
||||
if ($atEol -or ($options.keyIn -and ($inputTTY.Length -ge $reqSize))) { break }
|
||||
}
|
||||
|
||||
if ((-not $isCooked) -and (-not ($options.keyIn -and (-not $isInputLine))))
|
||||
{ execWithTTY 'Write-Host ''''' } # new line
|
||||
if ((-not $options.keyIn -and $atEol) -or
|
||||
($options.keyIn -and $inputTTY.Length -ge $reqSize)) { break }
|
||||
}
|
||||
|
||||
return '''' + $inputTTY + ''''
|
||||
if (-not $isCooked -and -not $silent) { execWithTTY 'Write-Host ''''' } # new line
|
||||
|
||||
return "'$inputTTY'"
|
||||
|
|
73
lib/read.sh
73
lib/read.sh
|
@ -9,29 +9,32 @@ while [ $# -ge 1 ]; do
|
|||
arg="$(printf '%s' "$1" | grep -E '^-+[^-]+$' | tr '[A-Z]' '[a-z]' | tr -d '-')"
|
||||
case "$arg" in
|
||||
'display') shift; options_display="$1";;
|
||||
'keyin') options_keyIn='true';;
|
||||
'noechoback') options_noEchoBack='true';;
|
||||
'keyin') options_keyIn=true;;
|
||||
'noechoback') options_noEchoBack=true;;
|
||||
'mask') shift; options_mask="$1";;
|
||||
'exclude') shift; options_exclude="$1";;
|
||||
'cs') options_cs='true';;
|
||||
'encoded') options_encoded='true';;
|
||||
'limit') shift; options_limit="$1";;
|
||||
'cs') options_cs=true;;
|
||||
'encoded') options_encoded=true;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
reset_tty() {
|
||||
if [ -n "$save_tty" ]; then stty "$save_tty"; fi
|
||||
if [ -n "$save_tty" ]; then
|
||||
stty --file=/dev/tty "$save_tty" 2>/dev/null || \
|
||||
stty -F /dev/tty "$save_tty" 2>/dev/null || \
|
||||
stty -f /dev/tty "$save_tty" || exit $?
|
||||
fi
|
||||
}
|
||||
trap 'reset_tty' EXIT
|
||||
save_tty="$(stty -g)"
|
||||
save_tty="$(stty --file=/dev/tty -g 2>/dev/null || stty -F /dev/tty -g 2>/dev/null || stty -f /dev/tty -g || exit $?)"
|
||||
|
||||
write_tty() { # 2nd arg: enable escape sequence
|
||||
if [ -n "$2" ]; then
|
||||
if [ "$2" = true ]; then
|
||||
printf '%b' "$1" >/dev/tty
|
||||
else
|
||||
printf '%s' "$1" >/dev/tty
|
||||
fi
|
||||
is_inputline='true'
|
||||
}
|
||||
|
||||
replace_allchars() { (
|
||||
|
@ -43,14 +46,15 @@ replace_allchars() { (
|
|||
printf '%s' "$text"
|
||||
) }
|
||||
|
||||
[ -z "$options_noEchoBack" ] && [ -z "$options_keyIn" ] && is_cooked='true'
|
||||
[ -z "$options_display" ] && [ "$options_keyIn" = true ] && \
|
||||
[ "$options_noEchoBack" = true ] && [ -z "$options_mask" ] && silent=true
|
||||
[ "$options_noEchoBack" != true ] && [ "$options_keyIn" != true ] && is_cooked=true
|
||||
|
||||
if [ -n "$options_display" ]; then
|
||||
write_tty "$options_display"
|
||||
options_display=''
|
||||
fi
|
||||
|
||||
if [ -n "$is_cooked" ]; then
|
||||
if [ "$is_cooked" = true ]; then
|
||||
stty --file=/dev/tty cooked 2>/dev/null || \
|
||||
stty -F /dev/tty cooked 2>/dev/null || \
|
||||
stty -f /dev/tty cooked || exit $?
|
||||
|
@ -60,41 +64,58 @@ else
|
|||
stty -f /dev/tty raw -echo || exit $?
|
||||
fi
|
||||
|
||||
[ -n "$options_keyIn" ] && req_size=1
|
||||
[ "$options_keyIn" = true ] && req_size=1
|
||||
|
||||
if [ "$options_keyIn" = true ] && [ -n "$options_limit" ]; then
|
||||
if [ "$options_cs" = true ]; then
|
||||
limit_ptn="$options_limit"
|
||||
else
|
||||
# Safe list
|
||||
limit_ptn="$(printf '%s' "$options_limit" | sed 's/\([a-z]\)/\L\1\U\1/ig')"
|
||||
fi
|
||||
fi
|
||||
|
||||
while :
|
||||
do
|
||||
if [ -z "$is_cooked" ]; then
|
||||
if [ "$is_cooked" != true ]; then
|
||||
chunk="$(dd if=/dev/tty bs=1 count=1 2>/dev/null)"
|
||||
chunk="$(printf '%s' "$chunk" | tr -d '\r\n')"
|
||||
[ -z "$chunk" ] && at_eol='true' # NL or empty-text was input
|
||||
else
|
||||
IFS= read -r chunk </dev/tty || exit $?
|
||||
chunk="$(printf '%s' "$chunk" | tr -d '\r\n')"
|
||||
at_eol='true'
|
||||
chunk="$(printf '%s\n_NL_' "$chunk")"
|
||||
fi
|
||||
|
||||
# Don't assign '\n' to chunk.
|
||||
if [ -n "$chunk" ] && [ "$(printf '%s' "$chunk" | tr '\r' '\n' | wc -l)" != "0" ]; then
|
||||
chunk="$(printf '%s' "$chunk" | tr '\r' '\n' | head -n 1)"
|
||||
at_eol=true
|
||||
fi
|
||||
|
||||
# other ctrl-chars
|
||||
if [ -n "$chunk" ]; then
|
||||
# chunk="$(printf '%s' "$chunk" | tr -d '\00-\10\13\14\16-\37\177')"
|
||||
# for System V
|
||||
chunk="$(printf '%s' "$chunk" | tr -d '\00\01\02\03\04\05\06\07\10\13\14\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177')"
|
||||
fi
|
||||
if [ -n "$chunk" ] && [ -n "$limit_ptn" ]; then
|
||||
chunk="$(printf '%s' "$chunk" | tr -cd "$limit_ptn")"
|
||||
fi
|
||||
|
||||
if [ -n "$chunk" ] && [ -z "$is_cooked" ]; then
|
||||
if [ -z "$options_noEchoBack" ]; then
|
||||
if [ -n "$chunk" ]; then
|
||||
if [ "$is_cooked" != true ]; then
|
||||
if [ "$options_noEchoBack" != true ]; then
|
||||
write_tty "$chunk"
|
||||
elif [ -n "$options_mask" ]; then
|
||||
write_tty "$(replace_allchars "$chunk" "$options_mask")"
|
||||
fi
|
||||
fi
|
||||
|
||||
input="$input$chunk"
|
||||
if [ -n "$at_eol" ] || \
|
||||
( [ -n "$options_keyIn" ] && [ ${#input} -ge $req_size ] ); then break; fi
|
||||
fi
|
||||
|
||||
if ( [ "$options_keyIn" != true ] && [ "$at_eol" = true ] ) || \
|
||||
( [ "$options_keyIn" = true ] && [ ${#input} -ge $req_size ] ); then break; fi
|
||||
done
|
||||
|
||||
if [ -z "$is_cooked" ] && ! ( [ -n "$options_keyIn" ] && [ -z "$is_inputline" ] ); then
|
||||
write_tty '\r\n' 'true'
|
||||
fi
|
||||
if [ "$is_cooked" != true ] && [ "$silent" != true ]; then write_tty '\r\n' true; fi
|
||||
|
||||
printf "'%s'" "$input"
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ var
|
|||
keyIn: boolean
|
||||
noEchoBack: boolean
|
||||
mask: string
|
||||
exclude: string (pattern, not RegExp)
|
||||
limit: string (pattern)
|
||||
cs: boolean
|
||||
noTrim: boolean
|
||||
*/
|
||||
|
@ -113,7 +113,7 @@ function readlineSync(options) {
|
|||
})();
|
||||
|
||||
(function() { // try read
|
||||
var atEol, exclude,
|
||||
var atEol, limit,
|
||||
isCooked = !options.noEchoBack && !options.keyIn,
|
||||
buffer, reqSize, readSize, chunk, line;
|
||||
|
||||
|
@ -141,8 +141,8 @@ function readlineSync(options) {
|
|||
}
|
||||
buffer = new Buffer((reqSize = options.keyIn ? 1 : bufSize));
|
||||
|
||||
if (options.keyIn && options.exclude) {
|
||||
exclude = new RegExp(options.exclude, 'g' + (options.cs ? '' : 'i'));
|
||||
if (options.keyIn && options.limit) {
|
||||
limit = new RegExp('[^' + options.limit + ']', 'g' + (options.cs ? '' : 'i'));
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
@ -158,23 +158,26 @@ function readlineSync(options) {
|
|||
}
|
||||
chunk = readSize > 0 ? buffer.toString(encoding, 0, readSize) : '\n';
|
||||
|
||||
if (typeof(line = (chunk.match(/^(.*?)[\r\n]/) || [])[1]) === 'string') {
|
||||
if (chunk && typeof(line = (chunk.match(/^(.*?)[\r\n]/) || [])[1]) === 'string') {
|
||||
chunk = line;
|
||||
atEol = true;
|
||||
}
|
||||
|
||||
chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ''); // other ctrl-chars
|
||||
if (chunk && exclude) { chunk = chunk.replace(exclude, ''); }
|
||||
// other ctrl-chars
|
||||
if (chunk) { chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ''); }
|
||||
if (chunk && limit) { chunk = chunk.replace(limit, ''); }
|
||||
|
||||
if (chunk && !isCooked) {
|
||||
if (chunk) {
|
||||
if (!isCooked) {
|
||||
if (!options.noEchoBack) {
|
||||
fs.writeSync(fdW, chunk);
|
||||
} else if (options.mask) {
|
||||
fs.writeSync(fdW, (new Array(chunk.length + 1)).join(options.mask));
|
||||
}
|
||||
}
|
||||
|
||||
input += chunk;
|
||||
}
|
||||
|
||||
if (!options.keyIn && atEol ||
|
||||
options.keyIn && input.length >= reqSize) { break; }
|
||||
}
|
||||
|
@ -218,7 +221,6 @@ function readlineExt(options) {
|
|||
|
||||
if (childProc.execFileSync) {
|
||||
hostArgs = getHostArgs(options);
|
||||
console.warn('<childProc.execFileSync>');
|
||||
try {
|
||||
res.input = childProc.execFileSync(extHostPath, hostArgs, execOptions);
|
||||
} catch (e) { // non-zero exit code
|
||||
|
@ -232,11 +234,9 @@ function readlineExt(options) {
|
|||
res.error.signal = e.signal;
|
||||
}
|
||||
} else {
|
||||
console.warn('<_execFileSync>');
|
||||
res = _execFileSync(options, execOptions);
|
||||
}
|
||||
if (!res.error) {
|
||||
console.warn('ROW-RES:<'+res.input+'>');
|
||||
res.input = res.input.replace(/^\s*'|'\s*$/g, '');
|
||||
options.display = '';
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ function getHostArgs(options) {
|
|||
keyIn: 'boolean',
|
||||
noEchoBack: 'boolean',
|
||||
mask: 'string',
|
||||
exclude: 'string',
|
||||
limit: 'string',
|
||||
cs: 'boolean',
|
||||
encoded: 'boolean'
|
||||
}));
|
||||
|
@ -429,7 +429,7 @@ exports.prompt = function(options) {
|
|||
keyIn: false,
|
||||
noEchoBack: !!(options && options.noEchoBack),
|
||||
mask: mask,
|
||||
exclude: '',
|
||||
limit: '',
|
||||
cs: !!(options && options.caseSensitive),
|
||||
noTrim: !!(options && options.noTrim)
|
||||
};
|
||||
|
@ -444,7 +444,7 @@ exports.question = function(query, options) {
|
|||
keyIn: false,
|
||||
noEchoBack: !!(options && options.noEchoBack),
|
||||
mask: mask,
|
||||
exclude: '',
|
||||
limit: '',
|
||||
cs: !!(options && options.caseSensitive),
|
||||
noTrim: !!(options && options.noTrim)
|
||||
};
|
||||
|
@ -452,8 +452,10 @@ exports.question = function(query, options) {
|
|||
};
|
||||
|
||||
exports.keyIn = function(query, options) {
|
||||
var limit = options ? flattenArray(options.limit, function(value) {
|
||||
return typeof value === 'string' || typeof value === 'number'; }).join('') : '',
|
||||
var limit = options ?
|
||||
flattenArray(options.limit, function(value)
|
||||
{ return typeof value === 'string' || typeof value === 'number'; })
|
||||
.join('').replace(/\n/g, '').replace(/[^A-Za-z0-9_ ]/g, '\\$&') : '',
|
||||
readOptions = {
|
||||
/* jshint eqnull:true */
|
||||
display: query != null ? query + '' : '',
|
||||
|
@ -461,8 +463,7 @@ exports.keyIn = function(query, options) {
|
|||
keyIn: true,
|
||||
noEchoBack: !!(options && options.noEchoBack),
|
||||
mask: mask,
|
||||
exclude: limit ? '[^' +
|
||||
limit.replace(/\n/g, '').replace(/\W/g, '\\$&') + ']' : '',
|
||||
limit: limit,
|
||||
cs: !!(options && options.caseSensitive),
|
||||
noTrim: true
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue