File: read.ps1

package info (click to toggle)
node-yarnpkg 4.1.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 24,752 kB
  • sloc: javascript: 38,953; ansic: 26,035; cpp: 7,247; sh: 2,829; makefile: 724; perl: 493
file content (128 lines) | stat: -rw-r--r-- 3,862 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# readlineSync
# https://github.com/anseki/readline-sync
#
# Copyright (c) 2019 anseki
# Licensed under the MIT license.

Param(
  [string] $display,
  [switch] $displayOnly,
  [switch] $keyIn,
  [switch] $hideEchoBack,
  [string] $mask,
  [string] $limit,
  [switch] $caseSensitive
)

$ErrorActionPreference = 'Stop' # for cmdlet
trap {
  # `throw $_` and `Write-Error $_` return exit-code 0
  $Host.UI.WriteErrorLine($_)
  exit 1
}

function decodeArg ($arg) {
  [Regex]::Replace($arg, '#(\d+);', { [char][int] $args[0].Groups[1].Value })
}

$options = @{}
foreach ($arg in @('display', 'displayOnly', 'keyIn', 'hideEchoBack', 'mask', 'limit', 'caseSensitive')) {
  $options.Add($arg, (Get-Variable $arg -ValueOnly))
}
$argList = New-Object string[] $options.Keys.Count
$options.Keys.CopyTo($argList, 0)
foreach ($arg in $argList) {
  if ($options[$arg] -is [string] -and $options[$arg])
    { $options[$arg] = decodeArg $options[$arg] }
}

[string] $inputTTY = ''
[bool] $silent = -not $options.display -and
  $options.keyIn -and $options.hideEchoBack -and -not $options.mask
[bool] $isCooked = -not $options.hideEchoBack -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.
# [string] $cmdPath = $Env:ComSpec
# [string] $psPath = 'powershell.exe'
function execWithTTY ($command, $getRes = $False, $throwError = $False) {
  if ($getRes) {
    $res = (cmd.exe /C "<CON powershell.exe -Command $command")
    if ($LastExitCode -ne 0) {
      if ($throwError) { throw $LastExitCode }
      else { exit $LastExitCode }
    }
    return $res
  } else {
    $command | cmd.exe /C ">CON powershell.exe -Command -"
    if ($LastExitCode -ne 0) {
      if ($throwError) { throw $LastExitCode }
      else { exit $LastExitCode }
    }
  }
}

function writeTTY ($text) {
  execWithTTY ('Write-Host (''' +
    (($text -replace '''', '''''') -replace '[\r\n]', '''+"`n"+''') + ''') -NoNewline')
}

if ($options.display) {
  writeTTY $options.display
}
if ($options.displayOnly) { return "''" }

if (-not $options.keyIn -and $options.hideEchoBack -and $options.mask -eq '*') {
  # It fails when it's not ready.
  try {
    $inputTTY = execWithTTY ('$text = Read-Host -AsSecureString;' +
      '$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($text);' +
      '[Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)') $True $True
    return '''' + $inputTTY + ''''
  } catch {} # ignore
}

if ($options.keyIn) { $reqSize = 1 }

if ($options.keyIn -and $options.limit) {
  $limitPtn = '[^' + $options.limit + ']'
}

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 -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.caseSensitive)   { $chunk = $chunk -creplace $limitPtn, '' }
    else                          { $chunk = $chunk -ireplace $limitPtn, '' }
  }

  if ($chunk) {
    if (-not $isCooked) {
      if (-not $options.hideEchoBack) {
        writeTTY $chunk
      } elseif ($options.mask) {
        writeTTY ($options.mask * $chunk.Length)
      }
    }
    $inputTTY += $chunk
  }

  if ((-not $options.keyIn -and $atEol) -or
    ($options.keyIn -and $inputTTY.Length -ge $reqSize)) { break }
}

if (-not $isCooked -and -not $silent) { execWithTTY 'Write-Host ''''' } # new line

return "'$inputTTY'"