]> git.ipfire.org Git - thirdparty/util-linux.git/blame - term-utils/scriptreplay.c
misc: cosmetics, remove argument from usage(int)
[thirdparty/util-linux.git] / term-utils / scriptreplay.c
CommitLineData
18a706bd
KZ
1/*
2 * Copyright (C) 2008, Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2008, James Youngman <jay@gnu.org>
4 *
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.
9 *
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.
14 *
15 *
16 * Based on scriptreplay.pl by Joey Hess <joey@kitenet.net>
17 */
18
19#include <stdio.h>
20#include <stdarg.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <time.h>
25#include <limits.h>
26#include <math.h>
27#include <sys/select.h>
28#include <unistd.h>
84adb5e6 29#include <getopt.h>
18a706bd 30
cdd2a8c3 31#include "closestream.h"
18a706bd 32#include "nls.h"
f0b3b904 33#include "strutils.h"
eb76ca98 34#include "c.h"
18a706bd
KZ
35
36#define SCRIPT_MIN_DELAY 0.0001 /* from original sripreplay.pl */
37
5769a938 38static void __attribute__((__noreturn__))
84adb5e6 39usage(FILE *out)
18a706bd 40{
db433bf7 41 fputs(USAGE_HEADER, out);
14cc9dda
KZ
42 fprintf(out,
43 _(" %s [-t] timingfile [typescript] [divisor]\n"),
44 program_invocation_short_name);
45
451dbcfa
BS
46 fputs(USAGE_SEPARATOR, out);
47 fputs(_("Play back terminal typescripts, using timing information.\n"), out);
48
db433bf7 49 fputs(USAGE_OPTIONS, out);
14cc9dda
KZ
50 fputs(_(" -t, --timing <file> script timing output file\n"
51 " -s, --typescript <file> script terminal session output file\n"
52 " -d, --divisor <num> speed up or slow down execution with time divisor\n"
7f1d4836 53 " -m, --maxdelay <num> wait at most this many seconds between updates\n"
84adb5e6 54 " -V, --version output version information and exit\n"
14cc9dda 55 " -h, --help display this help and exit\n\n"), out);
84adb5e6 56
a587cc55 57 fprintf(out, USAGE_MAN_TAIL("scriptreplay(1)"));
84adb5e6 58 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
18a706bd
KZ
59}
60
61static double
62getnum(const char *s)
63{
f0b3b904 64 const double d = strtod_or_err(s, _("failed to parse number"));
18a706bd 65
f0b3b904 66 if (isnan(d)) {
18a706bd 67 errno = EINVAL;
f0b3b904 68 err(EXIT_FAILURE, "%s: %s", _("failed to parse number"), s);
18a706bd
KZ
69 }
70 return d;
71}
72
73static void
74delay_for(double delay)
75{
76#ifdef HAVE_NANOSLEEP
77 struct timespec ts, remainder;
78 ts.tv_sec = (time_t) delay;
79 ts.tv_nsec = (delay - ts.tv_sec) * 1.0e9;
80
81 while (-1 == nanosleep(&ts, &remainder)) {
82 if (EINTR == errno)
83 ts = remainder;
84 else
85 break;
86 }
87#else
88 struct timeval tv;
89 tv.tv_sec = (long) delay;
90 tv.tv_usec = (delay - tv.tv_sec) * 1.0e6;
91 select(0, NULL, NULL, NULL, &tv);
92#endif
93}
94
95static void
96emit(FILE *fd, const char *filename, size_t ct)
97{
98 char buf[BUFSIZ];
99
100 while(ct) {
101 size_t len, cc;
102
103 cc = ct > sizeof(buf) ? sizeof(buf) : ct;
104 len = fread(buf, 1, cc, fd);
105
106 if (!len)
107 break;
108
109 ct -= len;
110 cc = write(STDOUT_FILENO, buf, len);
111 if (cc != len)
3e6e4bf6 112 err(EXIT_FAILURE, _("write to stdout failed"));
18a706bd
KZ
113 }
114
115 if (!ct)
116 return;
117 if (feof(fd))
118 errx(EXIT_FAILURE, _("unexpected end of file on %s"), filename);
119
120 err(EXIT_FAILURE, _("failed to read typescript file %s"), filename);
121}
122
123
124int
125main(int argc, char *argv[])
126{
127 FILE *tfile, *sfile;
0da871b5 128 const char *sname = NULL, *tname = NULL;
7f1d4836
JDN
129 double divi = 1, maxdelay = 0;
130 int c, diviopt = FALSE, maxdelayopt = FALSE, idx;
18a706bd 131 unsigned long line;
94757ece 132 int ch;
84adb5e6
SK
133
134 static const struct option longopts[] = {
0da871b5
SK
135 { "timing", required_argument, 0, 't' },
136 { "typescript", required_argument, 0, 's' },
137 { "divisor", required_argument, 0, 'd' },
7f1d4836 138 { "maxdelay", required_argument, 0, 'm' },
84adb5e6
SK
139 { "version", no_argument, 0, 'V' },
140 { "help", no_argument, 0, 'h' },
141 { NULL, 0, 0, 0 }
142 };
18a706bd
KZ
143
144 /* Because we use space as a separator, we can't afford to use any
145 * locale which tolerates a space in a number. In any case, script.c
146 * sets the LC_NUMERIC locale to C, anyway.
147 */
148 setlocale(LC_ALL, "");
149 setlocale(LC_NUMERIC, "C");
150
151 bindtextdomain(PACKAGE, LOCALEDIR);
152 textdomain(PACKAGE);
cdd2a8c3 153 atexit(close_stdout);
18a706bd 154
7f1d4836 155 while ((ch = getopt_long(argc, argv, "t:s:d:m:Vh", longopts, NULL)) != -1)
84adb5e6 156 switch(ch) {
0da871b5
SK
157 case 't':
158 tname = optarg;
159 break;
160 case 's':
161 sname = optarg;
162 break;
163 case 'd':
164 diviopt = TRUE;
165 divi = getnum(optarg);
166 break;
7f1d4836
JDN
167 case 'm':
168 maxdelayopt = TRUE;
169 maxdelay = getnum(optarg);
170 break;
84adb5e6 171 case 'V':
f6277500 172 printf(UTIL_LINUX_VERSION);
84adb5e6
SK
173 exit(EXIT_SUCCESS);
174 case 'h':
175 usage(stdout);
176 default:
677ec86c 177 errtryhelp(EXIT_FAILURE);
84adb5e6
SK
178 }
179 argc -= optind;
180 argv += optind;
0da871b5 181 idx = 0;
84adb5e6 182
0da871b5 183 if ((argc < 1 && !tname) || argc > 3) {
84adb5e6 184 warnx(_("wrong number of arguments"));
677ec86c 185 errtryhelp(EXIT_FAILURE);
84adb5e6 186 }
0da871b5
SK
187 if (!tname)
188 tname = argv[idx++];
189 if (!sname)
190 sname = idx < argc ? argv[idx++] : "typescript";
191 if (!diviopt)
192 divi = idx < argc ? getnum(argv[idx]) : 1;
7f1d4836
JDN
193 if (maxdelay < 0)
194 maxdelay = 0;
18a706bd
KZ
195 tfile = fopen(tname, "r");
196 if (!tfile)
289dcc90 197 err(EXIT_FAILURE, _("cannot open %s"), tname);
18a706bd
KZ
198 sfile = fopen(sname, "r");
199 if (!sfile)
289dcc90 200 err(EXIT_FAILURE, _("cannot open %s"), sname);
18a706bd
KZ
201
202 /* ignore the first typescript line */
203 while((c = fgetc(sfile)) != EOF && c != '\n');
204
ba660b99 205 for(line = 1; ; line++) {
18a706bd
KZ
206 double delay;
207 size_t blk;
208 char nl;
66fc0665 209 if (fscanf(tfile, "%lf %zu%c\n", &delay, &blk, &nl) != 3 ||
739de076 210 nl != '\n') {
18a706bd
KZ
211 if (feof(tfile))
212 break;
213 if (ferror(tfile))
214 err(EXIT_FAILURE,
3e6e4bf6 215 _("failed to read timing file %s"), tname);
18a706bd 216 errx(EXIT_FAILURE,
ba660b99 217 _("timing file %s: line %lu: unexpected format"),
18a706bd
KZ
218 tname, line);
219 }
220 delay /= divi;
221
7f1d4836
JDN
222 if (maxdelayopt && delay > maxdelay)
223 delay = maxdelay;
224
18a706bd
KZ
225 if (delay > SCRIPT_MIN_DELAY)
226 delay_for(delay);
227
a21f7ec9 228 emit(sfile, sname, blk);
18a706bd
KZ
229 }
230
231 fclose(sfile);
232 fclose(tfile);
f004a02d 233 printf("\n");
18a706bd
KZ
234 exit(EXIT_SUCCESS);
235}