Upload Tizen:Base source
[framework/base/util-linux-ng.git] / misc-utils / scriptreplay.c
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 <err.h>
30
31 #include "nls.h"
32
33 #define SCRIPT_MIN_DELAY 0.0001         /* from original sripreplay.pl */
34
35 void __attribute__((__noreturn__))
36 usage(int rc)
37 {
38         printf(_("%s <timingfile> [<typescript> [<divisor>]]\n"),
39                         program_invocation_short_name);
40         exit(rc);
41 }
42
43 static double
44 getnum(const char *s)
45 {
46         double d;
47         char *end;
48
49         errno = 0;
50         d = strtod(s, &end);
51
52         if (end && *end != '\0')
53                 errx(EXIT_FAILURE, _("expected a number, but got '%s'"), s);
54
55         if ((d == HUGE_VAL || d == -HUGE_VAL) && ERANGE == errno)
56                 err(EXIT_FAILURE, _("divisor '%s'"), s);
57
58         if (!(d==d)) { /* did they specify "nan"? */
59                 errno = EINVAL;
60                 err(EXIT_FAILURE, _("divisor '%s'"), s);
61         }
62         return d;
63 }
64
65 static void
66 delay_for(double delay)
67 {
68 #ifdef HAVE_NANOSLEEP
69         struct timespec ts, remainder;
70         ts.tv_sec = (time_t) delay;
71         ts.tv_nsec = (delay - ts.tv_sec) * 1.0e9;
72
73         while (-1 == nanosleep(&ts, &remainder)) {
74                 if (EINTR == errno)
75                         ts = remainder;
76                 else
77                         break;
78         }
79 #else
80         struct timeval tv;
81         tv.tv_sec = (long) delay;
82         tv.tv_usec = (delay - tv.tv_sec) * 1.0e6;
83         select(0, NULL, NULL, NULL, &tv);
84 #endif
85 }
86
87 static void
88 emit(FILE *fd, const char *filename, size_t ct)
89 {
90         char buf[BUFSIZ];
91
92         while(ct) {
93                 size_t len, cc;
94
95                 cc = ct > sizeof(buf) ? sizeof(buf) : ct;
96                 len = fread(buf, 1, cc, fd);
97
98                 if (!len)
99                        break;
100
101                 ct -= len;
102                 cc = write(STDOUT_FILENO, buf, len);
103                 if (cc != len)
104                         err(EXIT_FAILURE, _("write to stdout failed"));
105         }
106
107         if (!ct)
108                 return;
109         if (feof(fd))
110                 errx(EXIT_FAILURE, _("unexpected end of file on %s"), filename);
111
112         err(EXIT_FAILURE, _("failed to read typescript file %s"), filename);
113 }
114
115
116 int
117 main(int argc, char *argv[])
118 {
119         FILE *tfile, *sfile;
120         const char *sname, *tname;
121         double divi;
122         int c;
123         unsigned long line;
124         size_t oldblk = 0;
125
126         /* Because we use space as a separator, we can't afford to use any
127          * locale which tolerates a space in a number.  In any case, script.c
128          * sets the LC_NUMERIC locale to C, anyway.
129          */
130         setlocale(LC_ALL, "");
131         setlocale(LC_NUMERIC, "C");
132
133         bindtextdomain(PACKAGE, LOCALEDIR);
134         textdomain(PACKAGE);
135
136         if (argc < 2 && argc > 4)
137                 usage(EXIT_FAILURE);
138
139         tname = argv[1];
140         sname = argc > 2 ? argv[2] : "typescript";
141         divi = argc == 4 ? getnum(argv[3]) : 1;
142
143         tfile = fopen(tname, "r");
144         if (!tfile)
145                 err(EXIT_FAILURE, _("cannot open timing file %s"), tname);
146         sfile = fopen(sname, "r");
147         if (!sfile)
148                 err(EXIT_FAILURE, _("cannot open typescript file %s"), sname);
149
150         /* ignore the first typescript line */
151         while((c = fgetc(sfile)) != EOF && c != '\n');
152
153         for(line = 0; ; line++) {
154                 double delay;
155                 size_t blk;
156                 char nl;
157
158                 if ((fscanf(tfile, "%lf %zd%[\n]\n", &delay, &blk, &nl) != 3) ||
159                                                         (nl != '\n')) {
160                         if (feof(tfile))
161                                 break;
162                         if (ferror(tfile))
163                                 err(EXIT_FAILURE,
164                                         _("failed to read timing file %s"), tname);
165                         errx(EXIT_FAILURE,
166                                 _("timings file %s: %lu: unexpected format"),
167                                 tname, line);
168                 }
169                 delay /= divi;
170
171                 if (delay > SCRIPT_MIN_DELAY)
172                         delay_for(delay);
173
174                 if (oldblk)
175                         emit(sfile, sname, oldblk);
176                 oldblk = blk;
177         }
178
179         fclose(sfile);
180         fclose(tfile);
181         exit(EXIT_SUCCESS);
182 }