diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-10 14:25:51 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-10 14:25:51 +0100 |
| commit | 805aa9fec923109e90c87eda2f116ee2fa5fe962 (patch) | |
| tree | 1896eafafe3acd5febd244f69c12932f1bfb63ec /libbb | |
| parent | 9213a55bf0cc833d024975865a96a762b7a90b62 (diff) | |
| download | busybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.tar.gz busybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.tar.bz2 busybox-w32-805aa9fec923109e90c87eda2f116ee2fa5fe962.zip | |
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>
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/progress.c | 54 |
1 files changed, 31 insertions, 23 deletions
diff --git a/libbb/progress.c b/libbb/progress.c index 40608b047..ced04ac32 100644 --- a/libbb/progress.c +++ b/libbb/progress.c | |||
| @@ -62,35 +62,45 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p) | |||
| 62 | 62 | ||
| 63 | void FAST_FUNC bb_progress_update(bb_progress_t *p, | 63 | void FAST_FUNC bb_progress_update(bb_progress_t *p, |
| 64 | const char *curfile, | 64 | const char *curfile, |
| 65 | off_t beg_range, | 65 | uoff_t beg_range, |
| 66 | off_t transferred, | 66 | uoff_t transferred, |
| 67 | off_t totalsize) | 67 | uoff_t totalsize) |
| 68 | { | 68 | { |
| 69 | uoff_t beg_and_transferred; | 69 | uoff_t beg_and_transferred; |
| 70 | unsigned since_last_update, elapsed; | 70 | unsigned since_last_update, elapsed; |
| 71 | unsigned ratio; | 71 | unsigned ratio; |
| 72 | int barlength, i; | 72 | int barlength; |
| 73 | int kiloscale; | ||
| 73 | 74 | ||
| 74 | /* totalsize == 0 if it is unknown */ | 75 | /* totalsize == 0 if it is unknown */ |
| 75 | 76 | ||
| 77 | beg_and_transferred = beg_range + transferred; | ||
| 78 | |||
| 76 | elapsed = monotonic_sec(); | 79 | elapsed = monotonic_sec(); |
| 77 | since_last_update = elapsed - p->lastupdate_sec; | 80 | since_last_update = elapsed - p->lastupdate_sec; |
| 78 | /* Do not update on every call | 81 | /* Do not update on every call |
| 79 | * (we can be called on every network read!) */ | 82 | * (we can be called on every network read!) */ |
| 80 | if (since_last_update == 0 && !totalsize) | 83 | if (since_last_update == 0 && beg_and_transferred < totalsize) |
| 81 | return; | 84 | return; |
| 82 | 85 | ||
| 83 | beg_and_transferred = beg_range + transferred; | 86 | /* Scale sizes down if they are close to overflowing. |
| 84 | ratio = 100; | 87 | * If off_t is only 32 bits, this allows calculations |
| 85 | if (beg_and_transferred < totalsize) { | 88 | * like (100 * transferred / totalsize) without risking overflow. |
| 86 | /* Do not update on every call | 89 | * Introduced error is < 0.1% |
| 87 | * (we can be called on every network read!) */ | 90 | */ |
| 88 | if (since_last_update == 0) | 91 | kiloscale = 0; |
| 89 | return; | 92 | if (totalsize >= (1 << 20)) { |
| 90 | /* long long helps to have it working even if !LFS */ | 93 | totalsize >>= 10; |
| 91 | ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; | 94 | beg_range >>= 10; |
| 95 | transferred >>= 10; | ||
| 96 | beg_and_transferred >>= 10; | ||
| 97 | kiloscale++; | ||
| 92 | } | 98 | } |
| 93 | 99 | ||
| 100 | if (beg_and_transferred >= totalsize) | ||
| 101 | beg_and_transferred = totalsize; | ||
| 102 | |||
| 103 | ratio = 100 * beg_and_transferred / totalsize; | ||
| 94 | #if ENABLE_UNICODE_SUPPORT | 104 | #if ENABLE_UNICODE_SUPPORT |
| 95 | init_unicode(); | 105 | init_unicode(); |
| 96 | { | 106 | { |
| @@ -106,21 +116,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, | |||
| 106 | if (barlength > 0) { | 116 | if (barlength > 0) { |
| 107 | /* god bless gcc for variable arrays :) */ | 117 | /* god bless gcc for variable arrays :) */ |
| 108 | char buf[barlength + 1]; | 118 | char buf[barlength + 1]; |
| 109 | unsigned stars = (unsigned)barlength * ratio / (unsigned)100; | 119 | unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; |
| 110 | memset(buf, ' ', barlength); | 120 | memset(buf, ' ', barlength); |
| 111 | buf[barlength] = '\0'; | 121 | buf[barlength] = '\0'; |
| 112 | memset(buf, '*', stars); | 122 | memset(buf, '*', stars); |
| 113 | fprintf(stderr, "|%s|", buf); | 123 | fprintf(stderr, "|%s|", buf); |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | i = 0; | ||
| 117 | while (beg_and_transferred >= 100000) { | 126 | while (beg_and_transferred >= 100000) { |
| 118 | i++; | 127 | kiloscale++; |
| 119 | beg_and_transferred >>= 10; | 128 | beg_and_transferred >>= 10; |
| 120 | } | 129 | } |
| 121 | /* see http://en.wikipedia.org/wiki/Tera */ | 130 | /* see http://en.wikipedia.org/wiki/Tera */ |
| 122 | fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); | 131 | fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); |
| 123 | #define beg_and_transferred dont_use_beg_and_transferred_below | 132 | #define beg_and_transferred dont_use_beg_and_transferred_below() |
| 124 | 133 | ||
| 125 | if (transferred > p->lastsize) { | 134 | if (transferred > p->lastsize) { |
| 126 | p->lastupdate_sec = elapsed; | 135 | p->lastupdate_sec = elapsed; |
| @@ -137,13 +146,12 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, | |||
| 137 | if (since_last_update >= STALLTIME) { | 146 | if (since_last_update >= STALLTIME) { |
| 138 | fprintf(stderr, " - stalled -"); | 147 | fprintf(stderr, " - stalled -"); |
| 139 | } else { | 148 | } else { |
| 140 | off_t to_download = totalsize - beg_range; | 149 | uoff_t to_download = totalsize - beg_range; |
| 141 | if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { | 150 | if (!totalsize || (int)elapsed <= 0 || transferred > to_download) { |
| 142 | fprintf(stderr, "--:--:-- ETA"); | 151 | fprintf(stderr, "--:--:-- ETA"); |
| 143 | } else { | 152 | } else { |
| 144 | /* to_download / (transferred/elapsed) - elapsed: */ | 153 | /* to_download / (transferred/elapsed) - elapsed: */ |
| 145 | /* (long long helps to have working ETA even if !LFS) */ | 154 | unsigned eta = to_download * elapsed / transferred - elapsed; |
| 146 | unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed; | ||
| 147 | unsigned secs = eta % 3600; | 155 | unsigned secs = eta % 3600; |
| 148 | unsigned hours = eta / 3600; | 156 | unsigned hours = eta / 3600; |
| 149 | fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); | 157 | fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); |
