52
52
struct progress_implementation {
54
void *(*create) PARAMS ((long, long));
55
void (*update) PARAMS ((void *, long, double));
55
void *(*create) PARAMS ((wgint, wgint));
56
void (*update) PARAMS ((void *, wgint, double));
56
57
void (*finish) PARAMS ((void *, double));
57
58
void (*set_params) PARAMS ((const char *));
60
61
/* Necessary forward declarations. */
62
static void *dot_create PARAMS ((long, long));
63
static void dot_update PARAMS ((void *, long, double));
63
static void *dot_create PARAMS ((wgint, wgint));
64
static void dot_update PARAMS ((void *, wgint, double));
64
65
static void dot_finish PARAMS ((void *, double));
65
66
static void dot_set_params PARAMS ((const char *));
67
static void *bar_create PARAMS ((long, long));
68
static void bar_update PARAMS ((void *, long, double));
68
static void *bar_create PARAMS ((wgint, wgint));
69
static void bar_update PARAMS ((void *, wgint, double));
69
70
static void bar_finish PARAMS ((void *, double));
70
71
static void bar_set_params PARAMS ((const char *));
72
73
static struct progress_implementation implementations[] = {
73
{ "dot", dot_create, dot_update, dot_finish, dot_set_params },
74
{ "bar", bar_create, bar_update, bar_finish, bar_set_params }
74
{ "dot", 0, dot_create, dot_update, dot_finish, dot_set_params },
75
{ "bar", 1, bar_create, bar_update, bar_finish, bar_set_params }
76
77
static struct progress_implementation *current_impl;
77
78
static int current_impl_locked;
168
169
return current_impl->create (initial, total);
172
/* Return non-zero if the progress gauge is "interactive", i.e. if it
173
can profit from being called regularly even in absence of data.
174
The progress bar is interactive because it regularly updates the
175
ETA and current update. */
178
progress_interactive_p (void *progress)
180
return current_impl->interactive;
171
183
/* Inform the progress gauge of newly received bytes. DLTIME is the
172
184
time in milliseconds since the beginning of the download. */
175
progress_update (void *progress, long howmuch, double dltime)
187
progress_update (void *progress, wgint howmuch, double dltime)
177
189
current_impl->update (progress, howmuch, dltime);
204
216
/* Dot-progress backend for progress_create. */
207
dot_create (long initial, long total)
219
dot_create (wgint initial, wgint total)
209
struct dot_progress *dp = xmalloc (sizeof (struct dot_progress));
211
memset (dp, 0, sizeof (*dp));
221
struct dot_progress *dp = xnew0 (struct dot_progress);
213
222
dp->initial_length = initial;
214
223
dp->total_length = total;
216
225
if (dp->initial_length)
218
227
int dot_bytes = opt.dot_bytes;
219
long row_bytes = opt.dot_bytes * opt.dots_in_line;
228
wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
221
230
int remainder = (int) (dp->initial_length % row_bytes);
222
long skipped = dp->initial_length - remainder;
231
wgint skipped = dp->initial_length - remainder;
235
244
2 + skipped_k_len, "", skipped_k);
238
logprintf (LOG_VERBOSE, "\n%5ldK", skipped / 1024);
247
logprintf (LOG_VERBOSE, "\n%5ldK", (long) (skipped / 1024));
239
248
for (; remainder >= dot_bytes; remainder -= dot_bytes)
241
250
if (dp->dots % opt.dot_spacing == 0)
256
print_percentage (long bytes, long expected)
265
print_percentage (wgint bytes, wgint expected)
258
267
int percentage = (int)(100.0 * bytes / expected);
259
268
logprintf (LOG_VERBOSE, "%3d%%", percentage);
263
print_download_speed (struct dot_progress *dp, long bytes, double dltime)
272
print_download_speed (struct dot_progress *dp, wgint bytes, double dltime)
265
274
logprintf (LOG_VERBOSE, " %s",
266
275
retr_rate (bytes, dltime - dp->last_timer_value, 1));
270
279
/* Dot-progress backend for progress_update. */
273
dot_update (void *progress, long howmuch, double dltime)
282
dot_update (void *progress, wgint howmuch, double dltime)
275
284
struct dot_progress *dp = progress;
276
285
int dot_bytes = opt.dot_bytes;
277
long row_bytes = opt.dot_bytes * opt.dots_in_line;
286
wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
279
288
log_set_flush (0);
282
291
for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
284
293
if (dp->dots == 0)
285
logprintf (LOG_VERBOSE, "\n%5ldK", dp->rows * row_bytes / 1024);
294
logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
287
296
if (dp->dots % opt.dot_spacing == 0)
288
297
logputs (LOG_VERBOSE, " ");
315
324
struct dot_progress *dp = progress;
316
325
int dot_bytes = opt.dot_bytes;
317
long row_bytes = opt.dot_bytes * opt.dots_in_line;
326
wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
320
329
log_set_flush (0);
322
331
if (dp->dots == 0)
323
logprintf (LOG_VERBOSE, "\n%5ldK", dp->rows * row_bytes / 1024);
332
logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
324
333
for (i = dp->dots; i < opt.dots_in_line; i++)
326
335
if (i % opt.dot_spacing == 0)
339
long row_qty = dp->dots * dot_bytes + dp->accumulated;
348
wgint row_qty = dp->dots * dot_bytes + dp->accumulated;
340
349
if (dp->rows == dp->initial_length / row_bytes)
341
350
row_qty -= dp->initial_length % row_bytes;
342
351
print_download_speed (dp, row_qty, dltime);
411
420
create_image will overflow the buffer. */
412
421
#define MINIMUM_SCREEN_WIDTH 45
414
static int screen_width = DEFAULT_SCREEN_WIDTH;
423
/* The last known screen width. This can be updated by the code that
424
detects that SIGWINCH was received (but it's never updated from the
426
static int screen_width;
428
/* A flag that, when set, means SIGWINCH was received. */
429
static volatile sig_atomic_t received_sigwinch;
416
431
/* Size of the download speed history ring. */
417
432
#define DLSPEED_HISTORY_SIZE 20
423
438
#define DLSPEED_SAMPLE_MIN 150
440
/* The time after which the download starts to be considered
441
"stalled", i.e. the current bandwidth is not printed and the recent
442
download speeds are scratched. */
443
#define STALL_START_TIME 5000
425
445
struct bar_progress {
426
long initial_length; /* how many bytes have been downloaded
446
wgint initial_length; /* how many bytes have been downloaded
428
long total_length; /* expected total byte count when the
448
wgint total_length; /* expected total byte count when the
429
449
download finishes */
430
long count; /* bytes downloaded so far */
450
wgint count; /* bytes downloaded so far */
432
452
double last_screen_update; /* time of the last screen update,
433
453
measured since the beginning of
451
471
struct bar_progress_hist {
453
long times[DLSPEED_HISTORY_SIZE];
454
long bytes[DLSPEED_HISTORY_SIZE];
473
wgint times[DLSPEED_HISTORY_SIZE];
474
wgint bytes[DLSPEED_HISTORY_SIZE];
456
476
/* The sum of times and bytes respectively, maintained for
462
482
double recent_start; /* timestamp of beginning of current
464
long recent_bytes; /* bytes downloaded so far. */
484
wgint recent_bytes; /* bytes downloaded so far. */
486
int stalled; /* set when no data arrives for longer
487
than STALL_START_TIME, then reset
488
when new data arrives. */
466
490
/* create_image() uses these to make sure that ETA information
468
492
double last_eta_time; /* time of the last update to download
469
493
speed and ETA, measured since the
470
494
beginning of download. */
495
wgint last_eta_value;
474
498
static void create_image PARAMS ((struct bar_progress *, double));
475
499
static void display_image PARAMS ((char *));
478
bar_create (long initial, long total)
502
bar_create (wgint initial, wgint total)
480
struct bar_progress *bp = xmalloc (sizeof (struct bar_progress));
482
memset (bp, 0, sizeof (*bp));
504
struct bar_progress *bp = xnew0 (struct bar_progress);
484
506
/* In theory, our callers should take care of this pathological
485
507
case, but it can sometimes happen. */
489
511
bp->initial_length = initial;
490
512
bp->total_length = total;
514
/* Initialize screen_width if this hasn't been done or if it might
515
have changed, as indicated by receiving SIGWINCH. */
516
if (!screen_width || received_sigwinch)
518
screen_width = determine_screen_width ();
520
screen_width = DEFAULT_SCREEN_WIDTH;
521
else if (screen_width < MINIMUM_SCREEN_WIDTH)
522
screen_width = MINIMUM_SCREEN_WIDTH;
523
received_sigwinch = 0;
492
526
/* - 1 because we don't want to use the last screen column. */
493
527
bp->width = screen_width - 1;
494
528
/* + 1 for the terminating zero. */
497
531
logputs (LOG_VERBOSE, "\n");
499
create_image (bp, 0);
533
create_image (bp, 0.0);
500
534
display_image (bp->buffer);
505
static void update_speed_ring PARAMS ((struct bar_progress *, long, double));
539
static void update_speed_ring PARAMS ((struct bar_progress *, wgint, double));
508
bar_update (void *progress, long howmuch, double dltime)
542
bar_update (void *progress, wgint howmuch, double dltime)
510
544
struct bar_progress *bp = progress;
511
545
int force_screen_update = 0;
523
557
update_speed_ring (bp, howmuch, dltime);
525
if (screen_width - 1 != bp->width)
559
/* If SIGWINCH (the window size change signal) been received,
560
determine the new screen size and update the screen. */
561
if (received_sigwinch)
527
bp->width = screen_width - 1;
528
bp->buffer = xrealloc (bp->buffer, bp->width + 1);
529
force_screen_update = 1;
563
int old_width = screen_width;
564
screen_width = determine_screen_width ();
566
screen_width = DEFAULT_SCREEN_WIDTH;
567
else if (screen_width < MINIMUM_SCREEN_WIDTH)
568
screen_width = MINIMUM_SCREEN_WIDTH;
569
if (screen_width != old_width)
571
bp->width = screen_width - 1;
572
bp->buffer = xrealloc (bp->buffer, bp->width + 1);
573
force_screen_update = 1;
575
received_sigwinch = 0;
532
578
if (dltime - bp->last_screen_update < 200 && !force_screen_update)
576
622
3-second average would be too erratic. */
579
update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
625
update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
581
627
struct bar_progress_hist *hist = &bp->hist;
582
628
double recent_age = dltime - bp->recent_start;
590
636
if (recent_age < DLSPEED_SAMPLE_MIN)
641
/* If we're not downloading anything, we might be stalling,
642
i.e. not downloading anything for an extended period of time.
643
Since 0-reads do not enter the history ring, recent_age
644
effectively measures the time since last read. */
645
if (recent_age >= STALL_START_TIME)
647
/* If we're stalling, reset the ring contents because it's
648
stale and because it will make bar_update stop printing
649
the (bogus) current bandwidth. */
652
bp->recent_bytes = 0;
657
/* We now have a non-zero amount of to store to the speed ring. */
659
/* If the stall status was acquired, reset it. */
663
/* "recent_age" includes the the entired stalled period, which
664
could be very long. Don't update the speed ring with that
665
value because the current bandwidth would start too small.
666
Start with an arbitrary (but more reasonable) time value and
593
671
/* Store "recent" bytes and download time to history ring at the
641
719
create_image (struct bar_progress *bp, double dl_total_time)
643
721
char *p = bp->buffer;
644
long size = bp->initial_length + bp->count;
722
wgint size = bp->initial_length + bp->count;
646
char *size_legible = legible (size);
724
char *size_legible = with_thousand_seps (size);
647
725
int size_legible_len = strlen (size_legible);
649
727
struct bar_progress_hist *hist = &bp->hist;
752
830
/* " 234,567,890" */
753
sprintf (p, " %-11s", legible (size));
831
sprintf (p, " %-11s", with_thousand_seps (size));
756
834
/* " 1012.45K/s" */
757
835
if (hist->total_time && hist->total_bytes)
759
static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
837
static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
761
839
/* Calculate the download speed using the history ring and
762
840
recent data that hasn't made it to the ring yet. */
763
long dlquant = hist->total_bytes + bp->recent_bytes;
841
wgint dlquant = hist->total_bytes + bp->recent_bytes;
764
842
double dltime = hist->total_time + (dl_total_time - bp->recent_start);
765
843
double dlspeed = calc_rate (dlquant, dltime, &units);
766
844
sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
772
850
/* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.
773
851
That's because the ETA value needs a while to become
775
if (bp->total_length > 0 && dl_total_time > 3000)
853
if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
778
856
int eta_hrs, eta_min, eta_sec;
780
858
/* Don't change the value of ETA more than approximately once
793
871
I found that doing that results in a very jerky and
794
872
ultimately unreliable ETA. */
795
873
double time_sofar = (double)dl_total_time / 1000;
796
long bytes_remaining = bp->total_length - size;
797
eta = (long) (time_sofar * bytes_remaining / bp->count);
874
wgint bytes_remaining = bp->total_length - size;
875
eta = (wgint) (time_sofar * bytes_remaining / bp->count);
798
876
bp->last_eta_value = eta;
799
877
bp->last_eta_time = dl_total_time;
882
957
set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
886
sw = determine_screen_width ();
887
if (sw && sw >= MINIMUM_SCREEN_WIDTH)
893
964
progress_handle_sigwinch (int sig)
895
int sw = determine_screen_width ();
896
if (sw && sw >= MINIMUM_SCREEN_WIDTH)
966
received_sigwinch = 1;
898
967
signal (SIGWINCH, progress_handle_sigwinch);