progress bar: better overflow protection; more precise bar

function                                             old     new   delta
bb_progress_update                                   639     749    +110

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2011-02-10 14:25:51 +01:00
parent 9213a55bf0
commit 805aa9fec9
2 changed files with 34 additions and 25 deletions

View File

@ -1592,8 +1592,9 @@ typedef struct bb_progress_t {
void bb_progress_init(bb_progress_t *p) FAST_FUNC; void bb_progress_init(bb_progress_t *p) FAST_FUNC;
void bb_progress_update(bb_progress_t *p, const char *curfile, void bb_progress_update(bb_progress_t *p, const char *curfile,
off_t beg_range, off_t transferred, uoff_t beg_range,
off_t totalsize) FAST_FUNC; uoff_t transferred,
uoff_t totalsize) FAST_FUNC;
extern const char *applet_name; extern const char *applet_name;

View File

@ -62,35 +62,45 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p)
void FAST_FUNC bb_progress_update(bb_progress_t *p, void FAST_FUNC bb_progress_update(bb_progress_t *p,
const char *curfile, const char *curfile,
off_t beg_range, uoff_t beg_range,
off_t transferred, uoff_t transferred,
off_t totalsize) uoff_t totalsize)
{ {
uoff_t beg_and_transferred; uoff_t beg_and_transferred;
unsigned since_last_update, elapsed; unsigned since_last_update, elapsed;
unsigned ratio; unsigned ratio;
int barlength, i; int barlength;
int kiloscale;
/* totalsize == 0 if it is unknown */ /* totalsize == 0 if it is unknown */
beg_and_transferred = beg_range + transferred;
elapsed = monotonic_sec(); elapsed = monotonic_sec();
since_last_update = elapsed - p->lastupdate_sec; since_last_update = elapsed - p->lastupdate_sec;
/* Do not update on every call /* Do not update on every call
* (we can be called on every network read!) */ * (we can be called on every network read!) */
if (since_last_update == 0 && !totalsize) if (since_last_update == 0 && beg_and_transferred < totalsize)
return; return;
beg_and_transferred = beg_range + transferred; /* Scale sizes down if they are close to overflowing.
ratio = 100; * If off_t is only 32 bits, this allows calculations
if (beg_and_transferred < totalsize) { * like (100 * transferred / totalsize) without risking overflow.
/* Do not update on every call * Introduced error is < 0.1%
* (we can be called on every network read!) */ */
if (since_last_update == 0) kiloscale = 0;
return; if (totalsize >= (1 << 20)) {
/* long long helps to have it working even if !LFS */ totalsize >>= 10;
ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; beg_range >>= 10;
transferred >>= 10;
beg_and_transferred >>= 10;
kiloscale++;
} }
if (beg_and_transferred >= totalsize)
beg_and_transferred = totalsize;
ratio = 100 * beg_and_transferred / totalsize;
#if ENABLE_UNICODE_SUPPORT #if ENABLE_UNICODE_SUPPORT
init_unicode(); init_unicode();
{ {
@ -106,21 +116,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
if (barlength > 0) { if (barlength > 0) {
/* god bless gcc for variable arrays :) */ /* god bless gcc for variable arrays :) */
char buf[barlength + 1]; char buf[barlength + 1];
unsigned stars = (unsigned)barlength * ratio / (unsigned)100; unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
memset(buf, ' ', barlength); memset(buf, ' ', barlength);
buf[barlength] = '\0'; buf[barlength] = '\0';
memset(buf, '*', stars); memset(buf, '*', stars);
fprintf(stderr, "|%s|", buf); fprintf(stderr, "|%s|", buf);
} }
i = 0;
while (beg_and_transferred >= 100000) { while (beg_and_transferred >= 100000) {
i++; kiloscale++;
beg_and_transferred >>= 10; beg_and_transferred >>= 10;
} }
/* see http://en.wikipedia.org/wiki/Tera */ /* see http://en.wikipedia.org/wiki/Tera */
fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
#define beg_and_transferred dont_use_beg_and_transferred_below #define beg_and_transferred dont_use_beg_and_transferred_below()
if (transferred > p->lastsize) { if (transferred > p->lastsize) {
p->lastupdate_sec = elapsed; p->lastupdate_sec = elapsed;
@ -137,13 +146,12 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
if (since_last_update >= STALLTIME) { if (since_last_update >= STALLTIME) {
fprintf(stderr, " - stalled -"); fprintf(stderr, " - stalled -");
} else { } else {
off_t to_download = totalsize - beg_range; uoff_t to_download = totalsize - beg_range;
if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { if (!totalsize || (int)elapsed <= 0 || transferred > to_download) {
fprintf(stderr, "--:--:-- ETA"); fprintf(stderr, "--:--:-- ETA");
} else { } else {
/* to_download / (transferred/elapsed) - elapsed: */ /* to_download / (transferred/elapsed) - elapsed: */
/* (long long helps to have working ETA even if !LFS) */ unsigned eta = to_download * elapsed / transferred - elapsed;
unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed;
unsigned secs = eta % 3600; unsigned secs = eta % 3600;
unsigned hours = eta / 3600; unsigned hours = eta / 3600;
fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60);