struct progress {
const char *title;
- int last_value;
- unsigned total;
+ uint64_t last_value;
+ uint64_t total;
unsigned last_percent;
unsigned delay;
- unsigned delayed_percent_threshold;
+ unsigned sparse;
struct throughput *throughput;
uint64_t start_ns;
};
return tpgrp < 0 || tpgrp == getpgid(0);
}
-static int display(struct progress *progress, unsigned n, const char *done)
+static int display(struct progress *progress, uint64_t n, const char *done)
{
const char *eol, *tp;
- if (progress->delay) {
- if (!progress_update || --progress->delay)
- return 0;
- if (progress->total) {
- unsigned percent = n * 100 / progress->total;
- if (percent > progress->delayed_percent_threshold) {
- /* inhibit this progress report entirely */
- clear_progress_signal();
- progress->delay = -1;
- progress->total = 0;
- return 0;
- }
- }
- }
+ if (progress->delay && (!progress_update || --progress->delay))
+ return 0;
progress->last_value = n;
tp = (progress->throughput) ? progress->throughput->display.buf : "";
if (percent != progress->last_percent || progress_update) {
progress->last_percent = percent;
if (is_foreground_fd(fileno(stderr)) || done) {
- fprintf(stderr, "%s: %3u%% (%u/%u)%s%s",
- progress->title, percent, n,
- progress->total, tp, eol);
+ fprintf(stderr, "%s: %3u%% (%"PRIuMAX"/%"PRIuMAX")%s%s",
+ progress->title, percent,
+ (uintmax_t)n, (uintmax_t)progress->total,
+ tp, eol);
fflush(stderr);
}
progress_update = 0;
}
} else if (progress_update) {
if (is_foreground_fd(fileno(stderr)) || done) {
- fprintf(stderr, "%s: %u%s%s",
- progress->title, n, tp, eol);
+ fprintf(stderr, "%s: %"PRIuMAX"%s%s",
+ progress->title, (uintmax_t)n, tp, eol);
fflush(stderr);
}
progress_update = 0;
return 0;
}
-static void throughput_string(struct strbuf *buf, off_t total,
+static void throughput_string(struct strbuf *buf, uint64_t total,
unsigned int rate)
{
strbuf_reset(buf);
strbuf_addstr(buf, "/s");
}
-void display_throughput(struct progress *progress, off_t total)
+void display_throughput(struct progress *progress, uint64_t total)
{
struct throughput *tp;
uint64_t now_ns;
display(progress, progress->last_value, NULL);
}
-int display_progress(struct progress *progress, unsigned n)
+int display_progress(struct progress *progress, uint64_t n)
{
return progress ? display(progress, n, NULL) : 0;
}
-static struct progress *start_progress_delay(const char *title, unsigned total,
- unsigned percent_threshold, unsigned delay)
+static struct progress *start_progress_delay(const char *title, uint64_t total,
+ unsigned delay, unsigned sparse)
{
struct progress *progress = malloc(sizeof(*progress));
if (!progress) {
progress->total = total;
progress->last_value = -1;
progress->last_percent = -1;
- progress->delayed_percent_threshold = percent_threshold;
progress->delay = delay;
+ progress->sparse = sparse;
progress->throughput = NULL;
progress->start_ns = getnanotime();
set_progress_signal();
return progress;
}
-struct progress *start_delayed_progress(const char *title, unsigned total)
+struct progress *start_delayed_progress(const char *title, uint64_t total)
{
- return start_progress_delay(title, total, 0, 2);
+ return start_progress_delay(title, total, 2, 0);
}
-struct progress *start_progress(const char *title, unsigned total)
+struct progress *start_progress(const char *title, uint64_t total)
{
return start_progress_delay(title, total, 0, 0);
}
+/*
+ * Here "sparse" means that the caller might use some sampling criteria to
+ * decide when to call display_progress() rather than calling it for every
+ * integer value in[0 .. total). In particular, the caller might not call
+ * display_progress() for the last value in the range.
+ *
+ * When "sparse" is set, stop_progress() will automatically force the done
+ * message to show 100%.
+ */
+struct progress *start_sparse_progress(const char *title, uint64_t total)
+{
+ return start_progress_delay(title, total, 0, 1);
+}
+
+struct progress *start_delayed_sparse_progress(const char *title,
+ uint64_t total)
+{
+ return start_progress_delay(title, total, 2, 1);
+}
+
+static void finish_if_sparse(struct progress *progress)
+{
+ if (progress &&
+ progress->sparse &&
+ progress->last_value != progress->total)
+ display_progress(progress, progress->total);
+}
+
void stop_progress(struct progress **p_progress)
{
+ finish_if_sparse(*p_progress);
+
stop_progress_msg(p_progress, _("done"));
}