1 /* count.c - Progress indicator from stdin to stdout
2 *
3 * Copyright 2002 Rob Landley <[email protected]>
4
5 USE_COUNT(NEWTOY(count, "<0>0l", TOYFLAG_USR|TOYFLAG_BIN))
6
7 config COUNT
8 bool "count"
9 default y
10 help
11 usage: count [-l]
12
13 -l Long output (total bytes, human readable, transfer rate, elapsed time)
14
15 Copy stdin to stdout, displaying simple progress indicator to stderr.
16 */
17
18 #define FOR_count
19 #include "toys.h"
20
21 GLOBALS(
22 unsigned long long size, start;
23 unsigned tick, *slice;
24 )
25
display(unsigned long long now)26 static void display(unsigned long long now)
27 {
28 unsigned long long bb;
29 unsigned seconds, ii, len = TT.tick ? minof(TT.tick, 63): 1;
30
31 // bytes, human readable size, elapsed time, rate over last 16 seconds
32 if (FLAG(l)) {
33 human_readable(toybuf+256, TT.size, 0);
34 seconds = (now - TT.start)/1000;
35
36 // We zero new period and count it immediately, which lowers the average
37 // if we haven't had time to fill it yet. Compensate by keeping one extra
38 // old period and adding prorated fraction of it.
39 bb = (TT.slice[63&(TT.tick-len)]*(250-(now%250)))/250;
40
41 // Add up periods, convert to seconds via elapsed milliseconds
42 for (ii = 0; ii<len;) bb += TT.slice[63&(TT.tick-ii++)];
43 len *= 250;
44 if (now>TT.start && len>now-TT.start) len = now-TT.start;
45 human_readable(toybuf+512, (bb*1000)/len, 0);
46
47 sprintf(toybuf+1024, ", %sb, %sb/s, %um%02us", toybuf+256, toybuf+512,
48 seconds/60, seconds%60);
49 }
50 dprintf(2, "%llu bytes%s \r", TT.size, toybuf+1024);
51 }
52
count_main(void)53 void count_main(void)
54 {
55 struct pollfd pfd = {0, POLLIN, 0};
56 unsigned long long now, then;
57 char *buf = xmalloc(65536);
58 int len;
59
60 TT.slice = (void *)toybuf;
61 TT.start = now = then = millitime();
62
63 // poll, print if data not ready, update 4x/second otherwise
64 for (;;) {
65 // Update display 4x/second
66 if ((now = millitime())>=then) {
67 display(now);
68 while (then<=now) {
69 then += 250;
70 if (FLAG(l)) TT.slice[63&++TT.tick] = 0;
71 }
72 }
73 if (!(len = poll(&pfd, 1, then-now))) continue;
74 if (len<0 && errno != EINTR && errno != ENOMEM) perror_exit(0);
75 if ((len = xread(0, buf, 65536))) {
76 xwrite(1, buf, len);
77 TT.size += len;
78 TT.slice[63&TT.tick] += len;
79 if ((now = millitime())-then<250) continue;
80 }
81 if (!len) break;
82 }
83 display(now);
84 dprintf(2, "\n");
85 }
86