-
Notifications
You must be signed in to change notification settings - Fork 0
/
typeback.py
executable file
·114 lines (100 loc) · 2.96 KB
/
typeback.py
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
#!/usr/bin/python
"""
Player piano without restriction that you start in python.
Also, when you're done, control returns to the controlling terminal,
so you can continue working on your demo live if you so choose.
"""
import os
import pty
import select
import sys
import termios
import tty
def typeback(input_stream):
pid, fd = pty.fork()
if not pid:
try:
os.execv("/bin/bash", ["/bin/bash", "-l"])
finally:
os._exit(1)
old_mask = _mask_stdin()
try:
_process_loop(fd, input_stream)
finally:
_restore_stdin(old_mask)
def _process_loop(pty_fd, input_stream):
read_from_file = True
stdin = sys.stdin.fileno()
to_read = [stdin, pty_fd]
to_write = [sys.stdout.fileno(), pty_fd]
all_fds = to_read + to_write
stdout_buf = []
stdin_buf = []
while True:
read_ready, write_ready, exc_fds = select.select(to_read, [],
all_fds, 0)
if exc_fds:
print "Exec fds - done"
return
if read_ready:
if pty_fd in read_ready:
stdout_buf = _read_buffer(pty_fd, stdout_buf)
if not stdout_buf:
# pty died
return
stdout_buf = _write_buffer(sys.stdout.fileno(), stdout_buf)
if stdin in read_ready:
if read_from_file:
_eat_char(stdin)
char = input_stream.read(1)
if not char:
# out of characters in the file - switch back to
# stdin
read_from_file = False
os.write(pty_fd, char)
else:
stdin_buf = _read_buffer(stdin, stdin_buf)
if not stdin_buf:
return
stdin_buf = _write_buffer(pty_fd, stdin_buf)
def _write_buffer(fd, buf):
while buf:
rc = os.write(fd, buf[0])
if rc != len(buf[0]):
buf[0] = buf[rc:]
return buf
buf = buf[1:]
return []
def _read_buffer(fd, buf):
try:
new_data = os.read(fd, 4096)
except OSError:
return
if not new_data:
return
return buf + [new_data]
def _eat_char(fd):
os.read(fd, 1)
def _mask_stdin():
"""
disable echo of stdin
"""
stdin_fd = sys.stdin.fileno()
old_mask = termios.tcgetattr(stdin_fd)
new = old_mask[:]
new[3] = new[3] & ~termios.ECHO # 3 == 'lflags'
termios.tcsetattr(stdin_fd, termios.TCSADRAIN, new)
tty.setraw(stdin_fd)
return old_mask
def _restore_stdin(old_mask):
"""
restore stdin
"""
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_mask)
def main(argv):
if len(argv) != 2:
print "usage: %s [filename]" % argv[0]
sys.exit(1)
typeback(open(argv[1]))
if __name__ == '__main__':
main(sys.argv)