diff options
Diffstat (limited to 'src/read_chars.bash')
-rw-r--r-- | src/read_chars.bash | 142 |
1 files changed, 142 insertions, 0 deletions
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 | |||
19 | cfmakeraw() | ||
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 | |||
26 | i() | ||
27 | { | ||
28 | if [ "$DEBUG" ] | ||
29 | then | ||
30 | printf 'I: %s\n' "$*" >&2 | ||
31 | fi | ||
32 | } | ||
33 | |||
34 | x() | ||
35 | { | ||
36 | if [ "$DEBUG" ] | ||
37 | then | ||
38 | printf '+ %s\n' "${*@Q}" >&2 | ||
39 | fi | ||
40 | "$@" | ||
41 | } | ||
42 | |||
43 | readchar_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 | |||
64 | readchar_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 | |||
78 | check_foreground() | ||
79 | { | ||
80 | read _pid _comm _state _ppid pgrp _session _tty_nr tpgid _rest < /proc/self/stat | ||
81 | [ "$tpgid" = "$pgrp" ] | ||
82 | } | ||
83 | |||
84 | readchar() | ||
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 | |||
134 | read_chars() | ||
135 | { | ||
136 | readchar_init | ||
137 | while readchar | ||
138 | do | ||
139 | continue | ||
140 | done | ||
141 | } | ||
142 | |||