xref: /aosp_15_r20/external/toybox/toys/other/count.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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