showterm 0.1.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/showterm +1 -3
- data/ext/Makefile +34 -0
- data/ext/README +27 -0
- data/ext/extconf.rb +0 -0
- data/ext/io.c +161 -0
- data/ext/io.h +13 -0
- data/ext/ttyplay.1 +62 -0
- data/ext/ttyplay.c +312 -0
- data/ext/ttyrec.1 +76 -0
- data/ext/ttyrec.c +483 -0
- data/ext/ttyrec.h +12 -0
- data/ext/ttytime.1 +27 -0
- data/ext/ttytime.c +70 -0
- data/lib/showterm.rb +69 -23
- data/showterm.gemspec +2 -1
- metadata +17 -3
data/bin/showterm
CHANGED
data/ext/Makefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
CC = gcc
|
2
|
+
CFLAGS = -O2
|
3
|
+
VERSION = 1.0.8
|
4
|
+
|
5
|
+
TARGET = ttyrec ttyplay ttytime
|
6
|
+
|
7
|
+
DIST = ttyrec.c ttyplay.c ttyrec.h io.c io.h ttytime.c\
|
8
|
+
README Makefile ttyrec.1 ttyplay.1 ttytime.1
|
9
|
+
|
10
|
+
all: $(TARGET)
|
11
|
+
|
12
|
+
ttyrec: ttyrec.o io.o
|
13
|
+
$(CC) $(CFLAGS) -o ttyrec ttyrec.o io.o
|
14
|
+
|
15
|
+
ttyplay: ttyplay.o io.o
|
16
|
+
$(CC) $(CFLAGS) -o ttyplay ttyplay.o io.o
|
17
|
+
|
18
|
+
ttytime: ttytime.o io.o
|
19
|
+
$(CC) $(CFLAGS) -o ttytime ttytime.o io.o
|
20
|
+
|
21
|
+
clean:
|
22
|
+
rm -f *.o $(TARGET) ttyrecord *~
|
23
|
+
|
24
|
+
dist:
|
25
|
+
rm -rf ttyrec-$(VERSION)
|
26
|
+
rm -f ttyrec-$(VERSION).tar.gz
|
27
|
+
|
28
|
+
mkdir ttyrec-$(VERSION)
|
29
|
+
cp $(DIST) ttyrec-$(VERSION)
|
30
|
+
tar zcf ttyrec-$(VERSION).tar.gz ttyrec-$(VERSION)
|
31
|
+
rm -rf ttyrec-$(VERSION)
|
32
|
+
|
33
|
+
install:
|
34
|
+
:
|
data/ext/README
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
ttyrec is a tty recorder. ttyplay is a tty player.
|
2
|
+
|
3
|
+
Installation:
|
4
|
+
|
5
|
+
% make
|
6
|
+
|
7
|
+
or if your system is SVR4 system (Solaris etc.),
|
8
|
+
|
9
|
+
% make CFLAGS=-DSVR4
|
10
|
+
|
11
|
+
or if your system supports getpt(3),
|
12
|
+
|
13
|
+
% make CFLAGS=-DHAVE_getpt
|
14
|
+
|
15
|
+
HAVE_getpt is required if your linux system uses devfs.
|
16
|
+
|
17
|
+
|
18
|
+
Usage:
|
19
|
+
|
20
|
+
% ttyrec
|
21
|
+
(In the excuted shell, do whatever you want and exit)
|
22
|
+
|
23
|
+
% ttyplay ttyrecord
|
24
|
+
|
25
|
+
Have fun!
|
26
|
+
|
27
|
+
-- Satoru Takabayashi <satoru@namazu.org>
|
data/ext/extconf.rb
ADDED
File without changes
|
data/ext/io.c
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2000 Satoru Takabayashi <satoru@namazu.org>
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions
|
7
|
+
* are met:
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
13
|
+
* 3. All advertising materials mentioning features or use of this software
|
14
|
+
* must display the following acknowledgement:
|
15
|
+
* This product includes software developed by the University of
|
16
|
+
* California, Berkeley and its contributors.
|
17
|
+
* 4. Neither the name of the University nor the names of its contributors
|
18
|
+
* may be used to endorse or promote products derived from this software
|
19
|
+
* without specific prior written permission.
|
20
|
+
*
|
21
|
+
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
22
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
24
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
25
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
27
|
+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
28
|
+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
29
|
+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
30
|
+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
31
|
+
* SUCH DAMAGE.
|
32
|
+
*/
|
33
|
+
|
34
|
+
#include <assert.h>
|
35
|
+
#include <errno.h>
|
36
|
+
#include <stdio.h>
|
37
|
+
#include <stdlib.h>
|
38
|
+
#include <string.h>
|
39
|
+
#include <unistd.h>
|
40
|
+
|
41
|
+
#include "ttyrec.h"
|
42
|
+
|
43
|
+
#define SWAP_ENDIAN(val) ((unsigned int) ( \
|
44
|
+
(((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
|
45
|
+
(((unsigned int) (val) & (unsigned int) 0x0000ff00U) << 8) | \
|
46
|
+
(((unsigned int) (val) & (unsigned int) 0x00ff0000U) >> 8) | \
|
47
|
+
(((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))
|
48
|
+
|
49
|
+
static int
|
50
|
+
is_little_endian ()
|
51
|
+
{
|
52
|
+
static int retval = -1;
|
53
|
+
|
54
|
+
if (retval == -1) {
|
55
|
+
int n = 1;
|
56
|
+
char *p = (char *)&n;
|
57
|
+
char x[] = {1, 0, 0, 0};
|
58
|
+
|
59
|
+
assert(sizeof(int) == 4);
|
60
|
+
|
61
|
+
if (memcmp(p, x, 4) == 0) {
|
62
|
+
retval = 1;
|
63
|
+
} else {
|
64
|
+
retval = 0;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
return retval;
|
69
|
+
}
|
70
|
+
|
71
|
+
static int
|
72
|
+
convert_to_little_endian (int x)
|
73
|
+
{
|
74
|
+
if (is_little_endian()) {
|
75
|
+
return x;
|
76
|
+
} else {
|
77
|
+
return SWAP_ENDIAN(x);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
int
|
82
|
+
read_header (FILE *fp, Header *h)
|
83
|
+
{
|
84
|
+
int buf[3];
|
85
|
+
|
86
|
+
if (fread(buf, sizeof(int), 3, fp) == 0) {
|
87
|
+
return 0;
|
88
|
+
}
|
89
|
+
|
90
|
+
h->tv.tv_sec = convert_to_little_endian(buf[0]);
|
91
|
+
h->tv.tv_usec = convert_to_little_endian(buf[1]);
|
92
|
+
h->len = convert_to_little_endian(buf[2]);
|
93
|
+
|
94
|
+
return 1;
|
95
|
+
}
|
96
|
+
|
97
|
+
int
|
98
|
+
write_header (FILE *fp, Header *h)
|
99
|
+
{
|
100
|
+
int buf[3];
|
101
|
+
|
102
|
+
buf[0] = convert_to_little_endian(h->tv.tv_sec);
|
103
|
+
buf[1] = convert_to_little_endian(h->tv.tv_usec);
|
104
|
+
buf[2] = convert_to_little_endian(h->len);
|
105
|
+
|
106
|
+
if (fwrite(buf, sizeof(int), 3, fp) == 0) {
|
107
|
+
return 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
return 1;
|
111
|
+
}
|
112
|
+
|
113
|
+
static char *progname = "";
|
114
|
+
void
|
115
|
+
set_progname (const char *name)
|
116
|
+
{
|
117
|
+
progname = strdup(name);
|
118
|
+
}
|
119
|
+
|
120
|
+
FILE *
|
121
|
+
efopen (const char *path, const char *mode)
|
122
|
+
{
|
123
|
+
FILE *fp = fopen(path, mode);
|
124
|
+
if (fp == NULL) {
|
125
|
+
fprintf(stderr, "%s: %s: %s\n", progname, path, strerror(errno));
|
126
|
+
exit(EXIT_FAILURE);
|
127
|
+
}
|
128
|
+
return fp;
|
129
|
+
}
|
130
|
+
|
131
|
+
int
|
132
|
+
edup (int oldfd)
|
133
|
+
{
|
134
|
+
int fd = dup(oldfd);
|
135
|
+
if (fd == -1) {
|
136
|
+
fprintf(stderr, "%s: dup failed: %s\n", progname, strerror(errno));
|
137
|
+
exit(EXIT_FAILURE);
|
138
|
+
}
|
139
|
+
return fd;
|
140
|
+
}
|
141
|
+
|
142
|
+
int
|
143
|
+
edup2 (int oldfd, int newfd)
|
144
|
+
{
|
145
|
+
int fd = dup2(oldfd, newfd);
|
146
|
+
if (fd == -1) {
|
147
|
+
fprintf(stderr, "%s: dup2 failed: %s\n", progname, strerror(errno));
|
148
|
+
exit(EXIT_FAILURE);
|
149
|
+
}
|
150
|
+
return fd;
|
151
|
+
}
|
152
|
+
|
153
|
+
FILE *
|
154
|
+
efdopen (int fd, const char *mode)
|
155
|
+
{
|
156
|
+
FILE *fp = fdopen(fd, mode);
|
157
|
+
if (fp == NULL) {
|
158
|
+
fprintf(stderr, "%s: fdopen failed: %s\n", progname, strerror(errno));
|
159
|
+
exit(EXIT_FAILURE);
|
160
|
+
}
|
161
|
+
}
|
data/ext/io.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef __TTYREC_IO_H__
|
2
|
+
#define __TTYREC_IO_H__
|
3
|
+
|
4
|
+
#include "ttyrec.h"
|
5
|
+
|
6
|
+
int read_header (FILE *fp, Header *h);
|
7
|
+
int write_header (FILE *fp, Header *h);
|
8
|
+
FILE* efopen (const char *path, const char *mode);
|
9
|
+
int edup (int oldfd);
|
10
|
+
int edup2 (int oldfd, int newfd);
|
11
|
+
FILE* efdopen (int fd, const char *mode);
|
12
|
+
|
13
|
+
#endif
|
data/ext/ttyplay.1
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
.\"
|
2
|
+
.\" This manual page is written by NAKANO Takeo <nakano@webmasters.gr.jp>
|
3
|
+
.\"
|
4
|
+
.TH TTYPLAY 1
|
5
|
+
.SH NAME
|
6
|
+
ttyplay \- player of the tty session recorded by ttyrec
|
7
|
+
.SH SYNOPSIS
|
8
|
+
.br
|
9
|
+
.B ttyplay
|
10
|
+
.I [\-s SPEED] [\-n] [\-p] file
|
11
|
+
.br
|
12
|
+
.SH DESCRIPTION
|
13
|
+
.B Ttyplay
|
14
|
+
plays the tty session in
|
15
|
+
.IR file ,
|
16
|
+
which was recorded previously by
|
17
|
+
.BR ttyrec (1).
|
18
|
+
.PP
|
19
|
+
When
|
20
|
+
.B \-p
|
21
|
+
option is given,
|
22
|
+
.B ttyplay
|
23
|
+
output the
|
24
|
+
.I file
|
25
|
+
as it grows.
|
26
|
+
It means that you can see the "live" shell session
|
27
|
+
running by another user.
|
28
|
+
.PP
|
29
|
+
If you hit any key during playback, it will go right to the next
|
30
|
+
character typed. This is handy when examining sessions where a user
|
31
|
+
spends a lot of time at a prompt.
|
32
|
+
.PP
|
33
|
+
Additionally, there are some special keys defined:
|
34
|
+
.TP
|
35
|
+
.BI + " or " f
|
36
|
+
double the speed of playback.
|
37
|
+
.TP
|
38
|
+
.BI \- " or " s
|
39
|
+
halve the speed of playback.
|
40
|
+
.TP
|
41
|
+
.BI 1
|
42
|
+
set playback to speed 1.0 again.
|
43
|
+
|
44
|
+
.SH OPTIONS
|
45
|
+
.TP
|
46
|
+
.BI \-s " SPEED"
|
47
|
+
multiple the playing speed by
|
48
|
+
.I SPEED
|
49
|
+
(default is 1).
|
50
|
+
.TP
|
51
|
+
.B \-n
|
52
|
+
no wait mode.
|
53
|
+
Ignore the timing information in
|
54
|
+
.IR file .
|
55
|
+
.TP
|
56
|
+
.B \-p
|
57
|
+
peek another person's tty session.
|
58
|
+
.SH "SEE ALSO"
|
59
|
+
.BR script (1),
|
60
|
+
.BR ttyrec (1),
|
61
|
+
.BR ttytime (1)
|
62
|
+
|
data/ext/ttyplay.c
ADDED
@@ -0,0 +1,312 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2000 Satoru Takabayashi <satoru@namazu.org>
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions
|
7
|
+
* are met:
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
13
|
+
* 3. All advertising materials mentioning features or use of this software
|
14
|
+
* must display the following acknowledgement:
|
15
|
+
* This product includes software developed by the University of
|
16
|
+
* California, Berkeley and its contributors.
|
17
|
+
* 4. Neither the name of the University nor the names of its contributors
|
18
|
+
* may be used to endorse or promote products derived from this software
|
19
|
+
* without specific prior written permission.
|
20
|
+
*
|
21
|
+
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
22
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
24
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
25
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
27
|
+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
28
|
+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
29
|
+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
30
|
+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
31
|
+
* SUCH DAMAGE.
|
32
|
+
*/
|
33
|
+
|
34
|
+
#include <stdio.h>
|
35
|
+
#include <stdlib.h>
|
36
|
+
#include <assert.h>
|
37
|
+
#include <unistd.h>
|
38
|
+
#include <termios.h>
|
39
|
+
#include <sys/time.h>
|
40
|
+
#include <string.h>
|
41
|
+
|
42
|
+
#include "ttyrec.h"
|
43
|
+
#include "io.h"
|
44
|
+
|
45
|
+
typedef double (*WaitFunc) (struct timeval prev,
|
46
|
+
struct timeval cur,
|
47
|
+
double speed);
|
48
|
+
typedef int (*ReadFunc) (FILE *fp, Header *h, char **buf);
|
49
|
+
typedef void (*WriteFunc) (char *buf, int len);
|
50
|
+
typedef void (*ProcessFunc) (FILE *fp, double speed,
|
51
|
+
ReadFunc read_func, WaitFunc wait_func);
|
52
|
+
|
53
|
+
struct timeval
|
54
|
+
timeval_diff (struct timeval tv1, struct timeval tv2)
|
55
|
+
{
|
56
|
+
struct timeval diff;
|
57
|
+
|
58
|
+
diff.tv_sec = tv2.tv_sec - tv1.tv_sec;
|
59
|
+
diff.tv_usec = tv2.tv_usec - tv1.tv_usec;
|
60
|
+
if (diff.tv_usec < 0) {
|
61
|
+
diff.tv_sec--;
|
62
|
+
diff.tv_usec += 1000000;
|
63
|
+
}
|
64
|
+
|
65
|
+
return diff;
|
66
|
+
}
|
67
|
+
|
68
|
+
struct timeval
|
69
|
+
timeval_div (struct timeval tv1, double n)
|
70
|
+
{
|
71
|
+
double x = ((double)tv1.tv_sec + (double)tv1.tv_usec / 1000000.0) / n;
|
72
|
+
struct timeval div;
|
73
|
+
|
74
|
+
div.tv_sec = (int)x;
|
75
|
+
div.tv_usec = (x - (int)x) * 1000000;
|
76
|
+
|
77
|
+
return div;
|
78
|
+
}
|
79
|
+
|
80
|
+
double
|
81
|
+
ttywait (struct timeval prev, struct timeval cur, double speed)
|
82
|
+
{
|
83
|
+
static struct timeval drift = {0, 0};
|
84
|
+
struct timeval start;
|
85
|
+
struct timeval diff = timeval_diff(prev, cur);
|
86
|
+
fd_set readfs;
|
87
|
+
|
88
|
+
gettimeofday(&start, NULL);
|
89
|
+
|
90
|
+
assert(speed != 0);
|
91
|
+
diff = timeval_diff(drift, timeval_div(diff, speed));
|
92
|
+
if (diff.tv_sec < 0) {
|
93
|
+
diff.tv_sec = diff.tv_usec = 0;
|
94
|
+
}
|
95
|
+
|
96
|
+
FD_SET(STDIN_FILENO, &readfs);
|
97
|
+
/*
|
98
|
+
* We use select() for sleeping with subsecond precision.
|
99
|
+
* select() is also used to wait user's input from a keyboard.
|
100
|
+
*
|
101
|
+
* Save "diff" since select(2) may overwrite it to {0, 0}.
|
102
|
+
*/
|
103
|
+
struct timeval orig_diff = diff;
|
104
|
+
select(1, &readfs, NULL, NULL, &diff);
|
105
|
+
diff = orig_diff; /* Restore the original diff value. */
|
106
|
+
if (FD_ISSET(0, &readfs)) { /* a user hits a character? */
|
107
|
+
char c;
|
108
|
+
read(STDIN_FILENO, &c, 1); /* drain the character */
|
109
|
+
switch (c) {
|
110
|
+
case '+':
|
111
|
+
case 'f':
|
112
|
+
speed *= 2;
|
113
|
+
break;
|
114
|
+
case '-':
|
115
|
+
case 's':
|
116
|
+
speed /= 2;
|
117
|
+
break;
|
118
|
+
case '1':
|
119
|
+
speed = 1.0;
|
120
|
+
break;
|
121
|
+
}
|
122
|
+
drift.tv_sec = drift.tv_usec = 0;
|
123
|
+
} else {
|
124
|
+
struct timeval stop;
|
125
|
+
gettimeofday(&stop, NULL);
|
126
|
+
/* Hack to accumulate the drift */
|
127
|
+
if (diff.tv_sec == 0 && diff.tv_usec == 0) {
|
128
|
+
diff = timeval_diff(drift, diff); // diff = 0 - drift.
|
129
|
+
}
|
130
|
+
drift = timeval_diff(diff, timeval_diff(start, stop));
|
131
|
+
}
|
132
|
+
return speed;
|
133
|
+
}
|
134
|
+
|
135
|
+
double
|
136
|
+
ttynowait (struct timeval prev, struct timeval cur, double speed)
|
137
|
+
{
|
138
|
+
/* do nothing */
|
139
|
+
return 0; /* Speed isn't important. */
|
140
|
+
}
|
141
|
+
|
142
|
+
int
|
143
|
+
ttyread (FILE *fp, Header *h, char **buf)
|
144
|
+
{
|
145
|
+
if (read_header(fp, h) == 0) {
|
146
|
+
return 0;
|
147
|
+
}
|
148
|
+
|
149
|
+
*buf = malloc(h->len);
|
150
|
+
if (*buf == NULL) {
|
151
|
+
perror("malloc");
|
152
|
+
}
|
153
|
+
|
154
|
+
if (fread(*buf, 1, h->len, fp) == 0) {
|
155
|
+
perror("fread");
|
156
|
+
}
|
157
|
+
return 1;
|
158
|
+
}
|
159
|
+
|
160
|
+
int
|
161
|
+
ttypread (FILE *fp, Header *h, char **buf)
|
162
|
+
{
|
163
|
+
/*
|
164
|
+
* Read persistently just like tail -f.
|
165
|
+
*/
|
166
|
+
while (ttyread(fp, h, buf) == 0) {
|
167
|
+
struct timeval w = {0, 250000};
|
168
|
+
select(0, NULL, NULL, NULL, &w);
|
169
|
+
clearerr(fp);
|
170
|
+
}
|
171
|
+
return 1;
|
172
|
+
}
|
173
|
+
|
174
|
+
void
|
175
|
+
ttywrite (char *buf, int len)
|
176
|
+
{
|
177
|
+
fwrite(buf, 1, len, stdout);
|
178
|
+
}
|
179
|
+
|
180
|
+
void
|
181
|
+
ttynowrite (char *buf, int len)
|
182
|
+
{
|
183
|
+
/* do nothing */
|
184
|
+
}
|
185
|
+
|
186
|
+
void
|
187
|
+
ttyplay (FILE *fp, double speed, ReadFunc read_func,
|
188
|
+
WriteFunc write_func, WaitFunc wait_func)
|
189
|
+
{
|
190
|
+
int first_time = 1;
|
191
|
+
struct timeval prev;
|
192
|
+
|
193
|
+
setbuf(stdout, NULL);
|
194
|
+
setbuf(fp, NULL);
|
195
|
+
|
196
|
+
while (1) {
|
197
|
+
char *buf;
|
198
|
+
Header h;
|
199
|
+
|
200
|
+
if (read_func(fp, &h, &buf) == 0) {
|
201
|
+
break;
|
202
|
+
}
|
203
|
+
|
204
|
+
if (!first_time) {
|
205
|
+
speed = wait_func(prev, h.tv, speed);
|
206
|
+
}
|
207
|
+
first_time = 0;
|
208
|
+
|
209
|
+
write_func(buf, h.len);
|
210
|
+
prev = h.tv;
|
211
|
+
free(buf);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
void
|
216
|
+
ttyskipall (FILE *fp)
|
217
|
+
{
|
218
|
+
/*
|
219
|
+
* Skip all records.
|
220
|
+
*/
|
221
|
+
ttyplay(fp, 0, ttyread, ttynowrite, ttynowait);
|
222
|
+
}
|
223
|
+
|
224
|
+
void ttyplayback (FILE *fp, double speed,
|
225
|
+
ReadFunc read_func, WaitFunc wait_func)
|
226
|
+
{
|
227
|
+
ttyplay(fp, speed, ttyread, ttywrite, wait_func);
|
228
|
+
}
|
229
|
+
|
230
|
+
void ttypeek (FILE *fp, double speed,
|
231
|
+
ReadFunc read_func, WaitFunc wait_func)
|
232
|
+
{
|
233
|
+
ttyskipall(fp);
|
234
|
+
ttyplay(fp, speed, ttypread, ttywrite, ttynowait);
|
235
|
+
}
|
236
|
+
|
237
|
+
|
238
|
+
void
|
239
|
+
usage (void)
|
240
|
+
{
|
241
|
+
printf("Usage: ttyplay [OPTION] [FILE]\n");
|
242
|
+
printf(" -s SPEED Set speed to SPEED [1.0]\n");
|
243
|
+
printf(" -n No wait mode\n");
|
244
|
+
printf(" -p Peek another person's ttyrecord\n");
|
245
|
+
exit(EXIT_FAILURE);
|
246
|
+
}
|
247
|
+
|
248
|
+
/*
|
249
|
+
* We do some tricks so that select(2) properly works on
|
250
|
+
* STDIN_FILENO in ttywait().
|
251
|
+
*/
|
252
|
+
FILE *
|
253
|
+
input_from_stdin (void)
|
254
|
+
{
|
255
|
+
FILE *fp;
|
256
|
+
int fd = edup(STDIN_FILENO);
|
257
|
+
edup2(STDOUT_FILENO, STDIN_FILENO);
|
258
|
+
return efdopen(fd, "r");
|
259
|
+
}
|
260
|
+
|
261
|
+
int
|
262
|
+
main (int argc, char **argv)
|
263
|
+
{
|
264
|
+
double speed = 1.0;
|
265
|
+
ReadFunc read_func = ttyread;
|
266
|
+
WaitFunc wait_func = ttywait;
|
267
|
+
ProcessFunc process = ttyplayback;
|
268
|
+
FILE *input = NULL;
|
269
|
+
struct termios old, new;
|
270
|
+
|
271
|
+
set_progname(argv[0]);
|
272
|
+
while (1) {
|
273
|
+
int ch = getopt(argc, argv, "s:np");
|
274
|
+
if (ch == EOF) {
|
275
|
+
break;
|
276
|
+
}
|
277
|
+
switch (ch) {
|
278
|
+
case 's':
|
279
|
+
if (optarg == NULL) {
|
280
|
+
perror("-s option requires an argument");
|
281
|
+
exit(EXIT_FAILURE);
|
282
|
+
}
|
283
|
+
sscanf(optarg, "%lf", &speed);
|
284
|
+
break;
|
285
|
+
case 'n':
|
286
|
+
wait_func = ttynowait;
|
287
|
+
break;
|
288
|
+
case 'p':
|
289
|
+
process = ttypeek;
|
290
|
+
break;
|
291
|
+
default:
|
292
|
+
usage();
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
if (optind < argc) {
|
297
|
+
input = efopen(argv[optind], "r");
|
298
|
+
} else {
|
299
|
+
input = input_from_stdin();
|
300
|
+
}
|
301
|
+
assert(input != NULL);
|
302
|
+
|
303
|
+
tcgetattr(0, &old); /* Get current terminal state */
|
304
|
+
new = old; /* Make a copy */
|
305
|
+
new.c_lflag &= ~(ICANON | ECHO | ECHONL); /* unbuffered, no echo */
|
306
|
+
tcsetattr(0, TCSANOW, &new); /* Make it current */
|
307
|
+
|
308
|
+
process(input, speed, read_func, wait_func);
|
309
|
+
tcsetattr(0, TCSANOW, &old); /* Return terminal state */
|
310
|
+
|
311
|
+
return 0;
|
312
|
+
}
|
data/ext/ttyrec.1
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
.\"
|
2
|
+
.\" This manual page is written by NAKANO Takeo <nakano@webmasters.gr.jp>
|
3
|
+
.\"
|
4
|
+
.TH TTYREC 1
|
5
|
+
.SH NAME
|
6
|
+
ttyrec \- a tty recorder
|
7
|
+
.SH SYNOPSIS
|
8
|
+
.br
|
9
|
+
.B ttyrec
|
10
|
+
.I "[\-a][\-u] [file]"
|
11
|
+
.br
|
12
|
+
.SH DESCRIPTION
|
13
|
+
.B Ttyrec
|
14
|
+
is a tty recorder.
|
15
|
+
It is a derivative of
|
16
|
+
.BR script (1)
|
17
|
+
command for recording timing information with microsecond accuracy as well.
|
18
|
+
It can record emacs -nw, vi, lynx, or any programs running on tty.
|
19
|
+
.PP
|
20
|
+
.B Ttyrec
|
21
|
+
invokes a shell and records the session until the shell exits.
|
22
|
+
Recorded data can be played back with
|
23
|
+
.BR ttyplay (1).
|
24
|
+
If the argument
|
25
|
+
.I file
|
26
|
+
is given, the session will be recorded in that file.
|
27
|
+
Otherwise,
|
28
|
+
.I ttyrecord
|
29
|
+
is used as default.
|
30
|
+
.SH OPTIONS
|
31
|
+
.TP
|
32
|
+
.B \-a
|
33
|
+
Append the output to
|
34
|
+
.I file
|
35
|
+
or
|
36
|
+
.IR ttyrecord ,
|
37
|
+
rather than overwriting it.
|
38
|
+
.TP
|
39
|
+
.B \-u
|
40
|
+
With this option,
|
41
|
+
.B ttyrec
|
42
|
+
automatically calls
|
43
|
+
.BR uudecode (1)
|
44
|
+
and saves its output when uuencoded data appear on the session.
|
45
|
+
It allow you to transfer files from remote host.
|
46
|
+
You can call
|
47
|
+
.B ttyrec
|
48
|
+
with this option, login to the remote host
|
49
|
+
and invoke
|
50
|
+
.BR uuencode (1)
|
51
|
+
on it for the file you want to transfer.
|
52
|
+
.TP
|
53
|
+
.BI \-e " command"
|
54
|
+
Invoke
|
55
|
+
.I command
|
56
|
+
when ttyrec starts.
|
57
|
+
|
58
|
+
|
59
|
+
.SH ENVIRONMENT
|
60
|
+
.TP
|
61
|
+
.I SHELL
|
62
|
+
If the variable
|
63
|
+
.I SHELL
|
64
|
+
exists, the shell forked by
|
65
|
+
.B ttyrec
|
66
|
+
will be that shell.
|
67
|
+
If it's not set,
|
68
|
+
the Bourne shell is assumed.
|
69
|
+
(Most shells set this variable automatically).
|
70
|
+
.SH "SEE ALSO"
|
71
|
+
.BR script (1),
|
72
|
+
.BR ttyplay (1),
|
73
|
+
.BR ttytime (1),
|
74
|
+
.BR uuencode (1),
|
75
|
+
.BR uudecode (1)
|
76
|
+
|