source: MondoRescue/branches/3.3/mindi-busybox/libbb/progress.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Progress bar code.
4 */
5/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
6 * much of which was blatantly stolen from openssh.
7 */
8/*-
9 * Copyright (c) 1992, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. BSD Advertising Clause omitted per the July 22, 1999 licensing change
22 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
23 *
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40#include "libbb.h"
41#include "unicode.h"
42
43enum {
44 /* Seconds when xfer considered "stalled" */
45 STALLTIME = 5
46};
47
48void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
49{
50#if ENABLE_UNICODE_SUPPORT
51 init_unicode();
52 p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20);
53#else
54 p->curfile = curfile;
55#endif
56 p->start_sec = monotonic_sec();
57 p->last_update_sec = p->start_sec;
58 p->last_change_sec = p->start_sec;
59 p->last_size = 0;
60}
61
62/* File already had beg_size bytes.
63 * Then we started downloading.
64 * We downloaded "transferred" bytes so far.
65 * Download is expected to stop when total size (beg_size + transferred)
66 * will be "totalsize" bytes.
67 * If totalsize == 0, then it is unknown.
68 */
69void FAST_FUNC bb_progress_update(bb_progress_t *p,
70 uoff_t beg_size,
71 uoff_t transferred,
72 uoff_t totalsize)
73{
74 uoff_t beg_and_transferred;
75 unsigned since_last_update, elapsed;
76 int notty;
77 int kiloscale;
78
79 //transferred = 1234; /* use for stall detection testing */
80 //totalsize = 0; /* use for unknown size download testing */
81
82 elapsed = monotonic_sec();
83 since_last_update = elapsed - p->last_update_sec;
84 p->last_update_sec = elapsed;
85
86 if (totalsize != 0 && transferred >= totalsize - beg_size) {
87 /* Last call. Do not skip this update */
88 transferred = totalsize - beg_size; /* sanitize just in case */
89 }
90 else if (since_last_update == 0) {
91 /*
92 * Do not update on every call
93 * (we can be called on every network read!)
94 */
95 return;
96 }
97
98 kiloscale = 0;
99 /*
100 * Scale sizes down if they are close to overflowing.
101 * This allows calculations like (100 * transferred / totalsize)
102 * without risking overflow: we guarantee 10 highest bits to be 0.
103 * Introduced error is less than 1 / 2^12 ~= 0.025%
104 */
105 if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) {
106 /*
107 * 64-bit CPU || small off_t: in either case,
108 * >> is cheap, single-word operation.
109 * ... || strange off_t: also use this code
110 * (it is safe, just suboptimal wrt code size),
111 * because 32/64 optimized one works only for 64-bit off_t.
112 */
113 if (totalsize >= (1 << 22)) {
114 totalsize >>= 10;
115 beg_size >>= 10;
116 transferred >>= 10;
117 kiloscale = 1;
118 }
119 } else {
120 /* 32-bit CPU and 64-bit off_t.
121 * Use a 40-bit shift, it is easier to do on 32-bit CPU.
122 */
123/* ONE suppresses "warning: shift count >= width of type" */
124#define ONE (sizeof(off_t) > 4)
125 if (totalsize >= (uoff_t)(1ULL << 54*ONE)) {
126 totalsize = (uint32_t)(totalsize >> 32*ONE) >> 8;
127 beg_size = (uint32_t)(beg_size >> 32*ONE) >> 8;
128 transferred = (uint32_t)(transferred >> 32*ONE) >> 8;
129 kiloscale = 4;
130 }
131 }
132
133 notty = !isatty(STDERR_FILENO);
134
135 if (ENABLE_UNICODE_SUPPORT)
136 fprintf(stderr, "\r%s" + notty, p->curfile);
137 else
138 fprintf(stderr, "\r%-20.20s" + notty, p->curfile);
139
140 beg_and_transferred = beg_size + transferred;
141
142 if (totalsize != 0) {
143 int barlength;
144 unsigned ratio = 100 * beg_and_transferred / totalsize;
145 fprintf(stderr, "%4u%%", ratio);
146
147 barlength = get_terminal_width(2) - 49;
148 if (barlength > 0) {
149 /* god bless gcc for variable arrays :) */
150 char buf[barlength + 1];
151 unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
152 memset(buf, ' ', barlength);
153 buf[barlength] = '\0';
154 memset(buf, '*', stars);
155 fprintf(stderr, " |%s|", buf);
156 }
157 }
158
159 while (beg_and_transferred >= 100000) {
160 beg_and_transferred >>= 10;
161 kiloscale++;
162 }
163 /* see http://en.wikipedia.org/wiki/Tera */
164 fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
165#define beg_and_transferred dont_use_beg_and_transferred_below()
166
167 since_last_update = elapsed - p->last_change_sec;
168 if ((unsigned)transferred != p->last_size) {
169 p->last_change_sec = elapsed;
170 p->last_size = (unsigned)transferred;
171 if (since_last_update >= STALLTIME) {
172 /* We "cut out" these seconds from elapsed time
173 * by adjusting start time */
174 p->start_sec += since_last_update;
175 }
176 since_last_update = 0; /* we are un-stalled now */
177 }
178
179 elapsed -= p->start_sec; /* now it's "elapsed since start" */
180
181 if (since_last_update >= STALLTIME) {
182 fprintf(stderr, " - stalled -");
183 } else if (!totalsize || !transferred || (int)elapsed < 0) {
184 fprintf(stderr, " --:--:-- ETA");
185 } else {
186 unsigned eta, secs, hours;
187
188 totalsize -= beg_size; /* now it's "total to upload" */
189
190 /* Estimated remaining time =
191 * estimated_sec_to_dl_totalsize_bytes - elapsed_sec =
192 * totalsize / average_bytes_sec_so_far - elapsed =
193 * totalsize / (transferred/elapsed) - elapsed =
194 * totalsize * elapsed / transferred - elapsed
195 */
196 eta = totalsize * elapsed / transferred - elapsed;
197 if (eta >= 1000*60*60)
198 eta = 1000*60*60 - 1;
199 secs = eta % 3600;
200 hours = eta / 3600;
201 fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
202 }
203 if (notty)
204 fputc('\n', stderr);
205}
Note: See TracBrowser for help on using the repository browser.