2 * Copyright (C) 2008, Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2008, James Youngman <jay@gnu.org>
5 * This file is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This file is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 * Based on scriptreplay.pl by Joey Hess <joey@kitenet.net>
27 #include <sys/select.h>
31 #include "closestream.h"
35 #define SCRIPT_MIN_DELAY 0.0001 /* from original sripreplay.pl */
37 static void __attribute__((__noreturn__
))
40 fputs(_("\nUsage:\n"), out
);
42 _(" %s [-t] timingfile [typescript] [divisor]\n"),
43 program_invocation_short_name
);
45 fputs(_("\nOptions:\n"), out
);
46 fputs(_(" -t, --timing <file> script timing output file\n"
47 " -s, --typescript <file> script terminal session output file\n"
48 " -d, --divisor <num> speed up or slow down execution with time divisor\n"
49 " -m, --maxdelay <num> wait at most this many seconds between updates\n"
50 " -V, --version output version information and exit\n"
51 " -h, --help display this help and exit\n\n"), out
);
53 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
65 if (end
&& *end
!= '\0')
66 errx(EXIT_FAILURE
, _("expected a number, but got '%s'"), s
);
68 if ((d
== HUGE_VAL
|| d
== -HUGE_VAL
) && ERANGE
== errno
)
69 err(EXIT_FAILURE
, _("divisor '%s'"), s
);
71 if (!(d
==d
)) { /* did they specify "nan"? */
73 err(EXIT_FAILURE
, _("divisor '%s'"), s
);
79 delay_for(double delay
)
82 struct timespec ts
, remainder
;
83 ts
.tv_sec
= (time_t) delay
;
84 ts
.tv_nsec
= (delay
- ts
.tv_sec
) * 1.0e9
;
86 while (-1 == nanosleep(&ts
, &remainder
)) {
94 tv
.tv_sec
= (long) delay
;
95 tv
.tv_usec
= (delay
- tv
.tv_sec
) * 1.0e6
;
96 select(0, NULL
, NULL
, NULL
, &tv
);
101 emit(FILE *fd
, const char *filename
, size_t ct
)
108 cc
= ct
> sizeof(buf
) ? sizeof(buf
) : ct
;
109 len
= fread(buf
, 1, cc
, fd
);
115 cc
= write(STDOUT_FILENO
, buf
, len
);
117 err(EXIT_FAILURE
, _("write to stdout failed"));
123 errx(EXIT_FAILURE
, _("unexpected end of file on %s"), filename
);
125 err(EXIT_FAILURE
, _("failed to read typescript file %s"), filename
);
130 main(int argc
, char *argv
[])
133 const char *sname
= NULL
, *tname
= NULL
;
134 double divi
= 1, maxdelay
= 0;
135 int c
, diviopt
= FALSE
, maxdelayopt
= FALSE
, idx
;
139 static const struct option longopts
[] = {
140 { "timing", required_argument
, 0, 't' },
141 { "typescript", required_argument
, 0, 's' },
142 { "divisor", required_argument
, 0, 'd' },
143 { "maxdelay", required_argument
, 0, 'm' },
144 { "version", no_argument
, 0, 'V' },
145 { "help", no_argument
, 0, 'h' },
149 /* Because we use space as a separator, we can't afford to use any
150 * locale which tolerates a space in a number. In any case, script.c
151 * sets the LC_NUMERIC locale to C, anyway.
153 setlocale(LC_ALL
, "");
154 setlocale(LC_NUMERIC
, "C");
156 bindtextdomain(PACKAGE
, LOCALEDIR
);
158 atexit(close_stdout
);
160 while ((ch
= getopt_long(argc
, argv
, "t:s:d:m:Vh", longopts
, NULL
)) != -1)
170 divi
= getnum(optarg
);
174 maxdelay
= getnum(optarg
);
177 printf(UTIL_LINUX_VERSION
);
188 if ((argc
< 1 && !tname
) || argc
> 3) {
189 warnx(_("wrong number of arguments"));
195 sname
= idx
< argc
? argv
[idx
++] : "typescript";
197 divi
= idx
< argc
? getnum(argv
[idx
]) : 1;
200 tfile
= fopen(tname
, "r");
202 err(EXIT_FAILURE
, _("cannot open %s"), tname
);
203 sfile
= fopen(sname
, "r");
205 err(EXIT_FAILURE
, _("cannot open %s"), sname
);
207 /* ignore the first typescript line */
208 while((c
= fgetc(sfile
)) != EOF
&& c
!= '\n');
210 for(line
= 0; ; line
++) {
214 if (fscanf(tfile
, "%lf %zu%c\n", &delay
, &blk
, &nl
) != 3 ||
220 _("failed to read timing file %s"), tname
);
222 _("timings file %s: %lu: unexpected format"),
227 if (maxdelayopt
&& delay
> maxdelay
)
230 if (delay
> SCRIPT_MIN_DELAY
)
233 emit(sfile
, sname
, blk
);