summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/read-tty5
-rw-r--r--src/read_chars.bash142
2 files changed, 147 insertions, 0 deletions
diff --git a/src/read-tty b/src/read-tty
new file mode 100755
index 0000000..306a69d
--- /dev/null
+++ b/src/read-tty
@@ -0,0 +1,5 @@
1#!/bin/bash
2: "${BASH_LOADABLES_PATH:=/lib/bash:/usr/lib/bash:/usr/local/lib/bash:$HOME/.local/lib/bash}"
3enable -f sleep sleep
4source read_chars.bash
5(read_chars)
diff --git a/src/read_chars.bash b/src/read_chars.bash
new file mode 100644
index 0000000..f34dcc4
--- /dev/null
+++ b/src/read_chars.bash
@@ -0,0 +1,142 @@
1# =================
2# read_chars.bash
3# =================
4#
5# Bash library for reading from tty and writing to standard out.
6# Can be suspended and resumed from bash (or with unix job control in
7# any shell).
8#
9# exporting for users:
10#
11# read_chars() <-- calls readchar in a loop
12#
13# readchar() <-- reads one character
14#
15# readchar_init() <-- must be called before readchar() in the same subshell
16#
17# The function read_chars is also available as the executable read-tty
18
19cfmakeraw()
20{
21 cmd=(stty -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl
22 -ixon -opost -echo -echonl -icanon -isig -iexten -parenb cs8)
23 "${cmd[@]}" "$@" >/dev/null
24}
25
26i()
27{
28 if [ "$DEBUG" ]
29 then
30 printf 'I: %s\n' "$*" >&2
31 fi
32}
33
34x()
35{
36 if [ "$DEBUG" ]
37 then
38 printf '+ %s\n' "${*@Q}" >&2
39 fi
40 "$@"
41}
42
43readchar_init()
44{
45 declare -g SOCAT= SOCAT_PID=
46 declare -g t
47 declare -g -a readchar_termopts
48
49 [ -t 1 ] && t=y || t=
50 readchar_termopts=(
51 opost onlcr isig
52 intr undef
53 quit undef
54 )
55
56 trap "kill $SOCAT_PID 2>/dev/null" EXIT
57 trap "i CONT; readchar_SIGCONT" CONT
58 for sig in TSTP TTIN TTOU
59 do
60 trap "i $sig; x kill -STOP \$BASHPID \$SOCAT_PID 2>/dev/null" $sig
61 done
62}
63
64readchar_SIGCONT()
65{
66 if check_foreground
67 then
68 if [ -t 0 ]
69 then
70 x cfmakeraw "${readchar_termopts[@]}"
71 fi
72 x kill -CONT $SOCAT_PID 2>/dev/null
73 else
74 x kill -STOP $BASHPID $SOCAT_PID 2>/dev/null
75 fi
76}
77
78check_foreground()
79{
80 read _pid _comm _state _ppid pgrp _session _tty_nr tpgid _rest < /proc/self/stat
81 [ "$tpgid" = "$pgrp" ]
82}
83
84readchar()
85{
86 declare -n REPLY="${1:-CHARACTER}"
87
88 if [ -t 0 ]
89 then
90 if check_foreground
91 then
92 if ! [ "$SOCAT_PID" ]
93 then
94 x cfmakeraw "${readchar_termopts[@]}"
95 fi
96 else
97 sleep .25
98 return
99 fi
100 fi
101
102 if ! [ "$SOCAT_PID" ]
103 then
104 exec {SOCAT}< <(trap 'sleep .25' SIGTSTP; socat - -)
105 SOCAT_PID=$!
106 fi
107
108 if read -n 1 -d '' -r -s -u "$SOCAT"
109 then
110 if [ "$t" ]
111 then
112 printf -v quoted_reply "%s" "${REPLY@Q}"
113 if (( (count += 1 + ${#quoted_reply}) < ${COLUMNS:-80} - 10 ))
114 then
115 seperate=' '
116 else
117 seperate=$'\n'
118 count=0
119 fi
120 printf "%s" "$seperate" "$quoted_reply"
121 else
122 if [ "$REPLY" ]
123 then
124 printf "%s" "$REPLY"
125 else
126 printf "\0"
127 fi
128 fi
129 else
130 [ $? -gt 128 ]
131 fi
132}
133
134read_chars()
135{
136 readchar_init
137 while readchar
138 do
139 continue
140 done
141}
142