~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to term-utils/scriptreplay.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>
 
29
#include <getopt.h>
 
30
 
 
31
#include "nls.h"
 
32
#include "c.h"
 
33
 
 
34
#define SCRIPT_MIN_DELAY 0.0001         /* from original sripreplay.pl */
 
35
 
 
36
void __attribute__((__noreturn__))
 
37
usage(FILE *out)
 
38
{
 
39
        fputs(_("\nUsage:\n"), out);
 
40
        fprintf(out,
 
41
              _(" %s [-t] timingfile [typescript] [divisor]\n"),
 
42
              program_invocation_short_name);
 
43
 
 
44
        fputs(_("\nOptions:\n"), out);
 
45
        fputs(_(" -t, --timing <file>     script timing output file\n"
 
46
                " -s, --typescript <file> script terminal session output file\n"
 
47
                " -d, --divisor <num>     speed up or slow down execution with time divisor\n"
 
48
                " -V, --version           output version information and exit\n"
 
49
                " -h, --help              display this help and exit\n\n"), out);
 
50
 
 
51
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 
52
}
 
53
 
 
54
static double
 
55
getnum(const char *s)
 
56
{
 
57
        double d;
 
58
        char *end;
 
59
 
 
60
        errno = 0;
 
61
        d = strtod(s, &end);
 
62
 
 
63
        if (end && *end != '\0')
 
64
                errx(EXIT_FAILURE, _("expected a number, but got '%s'"), s);
 
65
 
 
66
        if ((d == HUGE_VAL || d == -HUGE_VAL) && ERANGE == errno)
 
67
                err(EXIT_FAILURE, _("divisor '%s'"), s);
 
68
 
 
69
        if (!(d==d)) { /* did they specify "nan"? */
 
70
                errno = EINVAL;
 
71
                err(EXIT_FAILURE, _("divisor '%s'"), s);
 
72
        }
 
73
        return d;
 
74
}
 
75
 
 
76
static void
 
77
delay_for(double delay)
 
78
{
 
79
#ifdef HAVE_NANOSLEEP
 
80
        struct timespec ts, remainder;
 
81
        ts.tv_sec = (time_t) delay;
 
82
        ts.tv_nsec = (delay - ts.tv_sec) * 1.0e9;
 
83
 
 
84
        while (-1 == nanosleep(&ts, &remainder)) {
 
85
                if (EINTR == errno)
 
86
                        ts = remainder;
 
87
                else
 
88
                        break;
 
89
        }
 
90
#else
 
91
        struct timeval tv;
 
92
        tv.tv_sec = (long) delay;
 
93
        tv.tv_usec = (delay - tv.tv_sec) * 1.0e6;
 
94
        select(0, NULL, NULL, NULL, &tv);
 
95
#endif
 
96
}
 
97
 
 
98
static void
 
99
emit(FILE *fd, const char *filename, size_t ct)
 
100
{
 
101
        char buf[BUFSIZ];
 
102
 
 
103
        while(ct) {
 
104
                size_t len, cc;
 
105
 
 
106
                cc = ct > sizeof(buf) ? sizeof(buf) : ct;
 
107
                len = fread(buf, 1, cc, fd);
 
108
 
 
109
                if (!len)
 
110
                       break;
 
111
 
 
112
                ct -= len;
 
113
                cc = write(STDOUT_FILENO, buf, len);
 
114
                if (cc != len)
 
115
                        err(EXIT_FAILURE, _("write to stdout failed"));
 
116
        }
 
117
 
 
118
        if (!ct)
 
119
                return;
 
120
        if (feof(fd))
 
121
                errx(EXIT_FAILURE, _("unexpected end of file on %s"), filename);
 
122
 
 
123
        err(EXIT_FAILURE, _("failed to read typescript file %s"), filename);
 
124
}
 
125
 
 
126
 
 
127
int
 
128
main(int argc, char *argv[])
 
129
{
 
130
        FILE *tfile, *sfile;
 
131
        const char *sname = NULL, *tname = NULL;
 
132
        double divi = 1;
 
133
        int c, diviopt = FALSE, idx;
 
134
        unsigned long line;
 
135
        size_t oldblk = 0;
 
136
        char ch;
 
137
 
 
138
        static const struct option longopts[] = {
 
139
                { "timing",     required_argument,      0, 't' },
 
140
                { "typescript", required_argument,      0, 's' },
 
141
                { "divisor",    required_argument,      0, 'd' },
 
142
                { "version",    no_argument,            0, 'V' },
 
143
                { "help",       no_argument,            0, 'h' },
 
144
                { NULL,         0, 0, 0 }
 
145
        };
 
146
 
 
147
        /* Because we use space as a separator, we can't afford to use any
 
148
         * locale which tolerates a space in a number.  In any case, script.c
 
149
         * sets the LC_NUMERIC locale to C, anyway.
 
150
         */
 
151
        setlocale(LC_ALL, "");
 
152
        setlocale(LC_NUMERIC, "C");
 
153
 
 
154
        bindtextdomain(PACKAGE, LOCALEDIR);
 
155
        textdomain(PACKAGE);
 
156
 
 
157
        while ((ch = getopt_long(argc, argv, "t:s:d:Vh", longopts, NULL)) != -1)
 
158
                switch(ch) {
 
159
                case 't':
 
160
                        tname = optarg;
 
161
                        break;
 
162
                case 's':
 
163
                        sname = optarg;
 
164
                        break;
 
165
                case 'd':
 
166
                        diviopt = TRUE;
 
167
                        divi = getnum(optarg);
 
168
                        break;
 
169
                case 'V':
 
170
                        printf(_("%s from %s\n"), program_invocation_short_name,
 
171
                                                  PACKAGE_STRING);
 
172
                        exit(EXIT_SUCCESS);
 
173
                case 'h':
 
174
                        usage(stdout);
 
175
                default:
 
176
                        usage(stderr);
 
177
                        }
 
178
        argc -= optind;
 
179
        argv += optind;
 
180
        idx = 0;
 
181
 
 
182
        if ((argc < 1 && !tname) || argc > 3) {
 
183
                warnx(_("wrong number of arguments"));
 
184
                usage(stderr);
 
185
        }
 
186
        if (!tname)
 
187
                tname = argv[idx++];
 
188
        if (!sname)
 
189
                sname = idx < argc ? argv[idx++] : "typescript";
 
190
        if (!diviopt)
 
191
                divi = idx < argc ? getnum(argv[idx]) : 1;
 
192
 
 
193
        tfile = fopen(tname, "r");
 
194
        if (!tfile)
 
195
                err(EXIT_FAILURE, _("cannot open timing file %s"), tname);
 
196
        sfile = fopen(sname, "r");
 
197
        if (!sfile)
 
198
                err(EXIT_FAILURE, _("cannot open typescript file %s"), sname);
 
199
 
 
200
        /* ignore the first typescript line */
 
201
        while((c = fgetc(sfile)) != EOF && c != '\n');
 
202
 
 
203
        for(line = 0; ; line++) {
 
204
                double delay;
 
205
                size_t blk;
 
206
                char nl;
 
207
 
 
208
                if (fscanf(tfile, "%lf %zd%c\n", &delay, &blk, &nl) != 3 ||
 
209
                                                                 nl != '\n') {
 
210
                        if (feof(tfile))
 
211
                                break;
 
212
                        if (ferror(tfile))
 
213
                                err(EXIT_FAILURE,
 
214
                                        _("failed to read timing file %s"), tname);
 
215
                        errx(EXIT_FAILURE,
 
216
                                _("timings file %s: %lu: unexpected format"),
 
217
                                tname, line);
 
218
                }
 
219
                delay /= divi;
 
220
 
 
221
                if (delay > SCRIPT_MIN_DELAY)
 
222
                        delay_for(delay);
 
223
 
 
224
                if (oldblk)
 
225
                        emit(sfile, sname, oldblk);
 
226
                oldblk = blk;
 
227
        }
 
228
 
 
229
        fclose(sfile);
 
230
        fclose(tfile);
 
231
        printf("\n");
 
232
        exit(EXIT_SUCCESS);
 
233
}