2 Copyright (C) 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables. You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL". If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. */
38 #endif /* HAVE_STRING_H */
52 struct progress_implementation {
54 void *(*create) PARAMS ((long, long));
55 void (*update) PARAMS ((void *, long, double));
56 void (*finish) PARAMS ((void *, double));
57 void (*set_params) PARAMS ((const char *));
60 /* Necessary forward declarations. */
62 static void *dot_create PARAMS ((long, long));
63 static void dot_update PARAMS ((void *, long, double));
64 static void dot_finish PARAMS ((void *, double));
65 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));
69 static void bar_finish PARAMS ((void *, double));
70 static void bar_set_params PARAMS ((const char *));
72 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 }
76 static struct progress_implementation *current_impl;
77 static int current_impl_locked;
79 /* Progress implementation used by default. Can be overriden in
80 wgetrc or by the fallback one. */
82 #define DEFAULT_PROGRESS_IMPLEMENTATION "bar"
84 /* Fallnback progress implementation should be something that works
85 under all display types. If you put something other than "dot"
86 here, remember that bar_set_params tries to switch to this if we're
87 not running on a TTY. So changing this to "bar" could cause
90 #define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
92 /* Return non-zero if NAME names a valid progress bar implementation.
93 The characters after the first : will be ignored. */
96 valid_progress_implementation_p (const char *name)
99 struct progress_implementation *pi = implementations;
100 char *colon = strchr (name, ':');
101 int namelen = colon ? colon - name : strlen (name);
103 for (i = 0; i < countof (implementations); i++, pi++)
104 if (!strncmp (pi->name, name, namelen))
109 /* Set the progress implementation to NAME. */
112 set_progress_implementation (const char *name)
115 struct progress_implementation *pi = implementations;
119 name = DEFAULT_PROGRESS_IMPLEMENTATION;
121 colon = strchr (name, ':');
122 namelen = colon ? colon - name : strlen (name);
124 for (i = 0; i < countof (implementations); i++, pi++)
125 if (!strncmp (pi->name, name, namelen))
128 current_impl_locked = 0;
131 /* We call pi->set_params even if colon is NULL because we
132 want to give the implementation a chance to set up some
133 things it needs to run. */
137 pi->set_params (colon);
143 static int output_redirected;
146 progress_schedule_redirect (void)
148 output_redirected = 1;
151 /* Create a progress gauge. INITIAL is the number of bytes the
152 download starts from (zero if the download starts from scratch).
153 TOTAL is the expected total number of bytes in this download. If
154 TOTAL is zero, it means that the download size is not known in
158 progress_create (long initial, long total)
160 /* Check if the log status has changed under our feet. */
161 if (output_redirected)
163 if (!current_impl_locked)
164 set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
165 output_redirected = 0;
168 return current_impl->create (initial, total);
171 /* Inform the progress gauge of newly received bytes. DLTIME is the
172 time in milliseconds since the beginning of the download. */
175 progress_update (void *progress, long howmuch, double dltime)
177 current_impl->update (progress, howmuch, dltime);
180 /* Tell the progress gauge to clean up. Calling this will free the
181 PROGRESS object, the further use of which is not allowed. */
184 progress_finish (void *progress, double dltime)
186 current_impl->finish (progress, dltime);
191 struct dot_progress {
192 long initial_length; /* how many bytes have been downloaded
194 long total_length; /* expected total byte count when the
199 int rows; /* number of rows printed so far */
200 int dots; /* number of dots printed in this row */
201 double last_timer_value;
204 /* Dot-progress backend for progress_create. */
207 dot_create (long initial, long total)
209 struct dot_progress *dp = xnew0 (struct dot_progress);
210 dp->initial_length = initial;
211 dp->total_length = total;
213 if (dp->initial_length)
215 int dot_bytes = opt.dot_bytes;
216 long row_bytes = opt.dot_bytes * opt.dots_in_line;
218 int remainder = (int) (dp->initial_length % row_bytes);
219 long skipped = dp->initial_length - remainder;
223 int skipped_k = (int) (skipped / 1024); /* skipped amount in K */
224 int skipped_k_len = numdigit (skipped_k);
225 if (skipped_k_len < 5)
228 /* Align the [ skipping ... ] line with the dots. To do
229 that, insert the number of spaces equal to the number of
230 digits in the skipped amount in K. */
231 logprintf (LOG_VERBOSE, _("\n%*s[ skipping %dK ]"),
232 2 + skipped_k_len, "", skipped_k);
235 logprintf (LOG_VERBOSE, "\n%5ldK", skipped / 1024);
236 for (; remainder >= dot_bytes; remainder -= dot_bytes)
238 if (dp->dots % opt.dot_spacing == 0)
239 logputs (LOG_VERBOSE, " ");
240 logputs (LOG_VERBOSE, ",");
243 assert (dp->dots < opt.dots_in_line);
245 dp->accumulated = remainder;
246 dp->rows = skipped / row_bytes;
253 print_percentage (long bytes, long expected)
255 int percentage = (int)(100.0 * bytes / expected);
256 logprintf (LOG_VERBOSE, "%3d%%", percentage);
260 print_download_speed (struct dot_progress *dp, long bytes, double dltime)
262 logprintf (LOG_VERBOSE, " %s",
263 retr_rate (bytes, dltime - dp->last_timer_value, 1));
264 dp->last_timer_value = dltime;
267 /* Dot-progress backend for progress_update. */
270 dot_update (void *progress, long howmuch, double dltime)
272 struct dot_progress *dp = progress;
273 int dot_bytes = opt.dot_bytes;
274 long row_bytes = opt.dot_bytes * opt.dots_in_line;
278 dp->accumulated += howmuch;
279 for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
282 logprintf (LOG_VERBOSE, "\n%5ldK", dp->rows * row_bytes / 1024);
284 if (dp->dots % opt.dot_spacing == 0)
285 logputs (LOG_VERBOSE, " ");
286 logputs (LOG_VERBOSE, ".");
289 if (dp->dots >= opt.dots_in_line)
291 long row_qty = row_bytes;
292 if (dp->rows == dp->initial_length / row_bytes)
293 row_qty -= dp->initial_length % row_bytes;
298 if (dp->total_length)
299 print_percentage (dp->rows * row_bytes, dp->total_length);
300 print_download_speed (dp, row_qty, dltime);
307 /* Dot-progress backend for progress_finish. */
310 dot_finish (void *progress, double dltime)
312 struct dot_progress *dp = progress;
313 int dot_bytes = opt.dot_bytes;
314 long row_bytes = opt.dot_bytes * opt.dots_in_line;
320 logprintf (LOG_VERBOSE, "\n%5ldK", dp->rows * row_bytes / 1024);
321 for (i = dp->dots; i < opt.dots_in_line; i++)
323 if (i % opt.dot_spacing == 0)
324 logputs (LOG_VERBOSE, " ");
325 logputs (LOG_VERBOSE, " ");
327 if (dp->total_length)
329 print_percentage (dp->rows * row_bytes
330 + dp->dots * dot_bytes
336 long row_qty = dp->dots * dot_bytes + dp->accumulated;
337 if (dp->rows == dp->initial_length / row_bytes)
338 row_qty -= dp->initial_length % row_bytes;
339 print_download_speed (dp, row_qty, dltime);
342 logputs (LOG_VERBOSE, "\n\n");
348 /* This function interprets the progress "parameters". For example,
349 if Wget is invoked with --progress=dot:mega, it will set the
350 "dot-style" to "mega". Valid styles are default, binary, mega, and
354 dot_set_params (const char *params)
356 if (!params || !*params)
357 params = opt.dot_style;
362 /* We use this to set the retrieval style. */
363 if (!strcasecmp (params, "default"))
365 /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
367 opt.dot_bytes = 1024;
368 opt.dot_spacing = 10;
369 opt.dots_in_line = 50;
371 else if (!strcasecmp (params, "binary"))
373 /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
375 opt.dot_bytes = 8192;
376 opt.dot_spacing = 16;
377 opt.dots_in_line = 48;
379 else if (!strcasecmp (params, "mega"))
381 /* "Mega" retrieval, for retrieving very long files; each dot is
382 64K, 8 dots in a cluster, 6 clusters (3M) in a line. */
383 opt.dot_bytes = 65536L;
385 opt.dots_in_line = 48;
387 else if (!strcasecmp (params, "giga"))
389 /* "Giga" retrieval, for retrieving very very *very* long files;
390 each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
392 opt.dot_bytes = (1L << 20);
394 opt.dots_in_line = 32;
398 _("Invalid dot style specification `%s'; leaving unchanged.\n"),
402 /* "Thermometer" (bar) progress. */
404 /* Assumed screen width if we can't find the real value. */
405 #define DEFAULT_SCREEN_WIDTH 80
407 /* Minimum screen width we'll try to work with. If this is too small,
408 create_image will overflow the buffer. */
409 #define MINIMUM_SCREEN_WIDTH 45
411 /* The last known screen width. This can be updated by the code that
412 detects that SIGWINCH was received (but it's never updated from the
414 static int screen_width;
416 /* A flag that, when set, means SIGWINCH was received. */
417 static volatile sig_atomic_t received_sigwinch;
419 /* Size of the download speed history ring. */
420 #define DLSPEED_HISTORY_SIZE 20
422 /* The minimum time length of a history sample. By default, each
423 sample is at least 150ms long, which means that, over the course of
424 20 samples, "current" download speed spans at least 3s into the
426 #define DLSPEED_SAMPLE_MIN 150
428 struct bar_progress {
429 long initial_length; /* how many bytes have been downloaded
431 long total_length; /* expected total byte count when the
433 long count; /* bytes downloaded so far */
435 double last_screen_update; /* time of the last screen update,
436 measured since the beginning of
439 int width; /* screen width we're using at the
440 time the progress gauge was
441 created. this is different from
442 the screen_width global variable in
443 that the latter can be changed by a
445 char *buffer; /* buffer where the bar "image" is
447 int tick; /* counter used for drawing the
448 progress bar where the total size
451 /* The following variables (kept in a struct for namespace reasons)
452 keep track of recent download speeds. See bar_update() for
454 struct bar_progress_hist {
456 long times[DLSPEED_HISTORY_SIZE];
457 long bytes[DLSPEED_HISTORY_SIZE];
459 /* The sum of times and bytes respectively, maintained for
465 double recent_start; /* timestamp of beginning of current
467 long recent_bytes; /* bytes downloaded so far. */
469 /* create_image() uses these to make sure that ETA information
471 double last_eta_time; /* time of the last update to download
472 speed and ETA, measured since the
473 beginning of download. */
477 static void create_image PARAMS ((struct bar_progress *, double));
478 static void display_image PARAMS ((char *));
481 bar_create (long initial, long total)
483 struct bar_progress *bp = xnew0 (struct bar_progress);
485 /* In theory, our callers should take care of this pathological
486 case, but it can sometimes happen. */
490 bp->initial_length = initial;
491 bp->total_length = total;
493 /* Initialize screen_width if this hasn't been done or if it might
494 have changed, as indicated by receiving SIGWINCH. */
495 if (!screen_width || received_sigwinch)
497 screen_width = determine_screen_width ();
499 screen_width = DEFAULT_SCREEN_WIDTH;
500 else if (screen_width < MINIMUM_SCREEN_WIDTH)
501 screen_width = MINIMUM_SCREEN_WIDTH;
502 received_sigwinch = 0;
505 /* - 1 because we don't want to use the last screen column. */
506 bp->width = screen_width - 1;
507 /* + 1 for the terminating zero. */
508 bp->buffer = xmalloc (bp->width + 1);
510 logputs (LOG_VERBOSE, "\n");
512 create_image (bp, 0);
513 display_image (bp->buffer);
518 static void update_speed_ring PARAMS ((struct bar_progress *, long, double));
521 bar_update (void *progress, long howmuch, double dltime)
523 struct bar_progress *bp = progress;
524 int force_screen_update = 0;
526 bp->count += howmuch;
527 if (bp->total_length > 0
528 && bp->count + bp->initial_length > bp->total_length)
529 /* We could be downloading more than total_length, e.g. when the
530 server sends an incorrect Content-Length header. In that case,
531 adjust bp->total_length to the new reality, so that the code in
532 create_image() that depends on total size being smaller or
533 equal to the expected size doesn't abort. */
534 bp->total_length = bp->initial_length + bp->count;
536 update_speed_ring (bp, howmuch, dltime);
538 /* If SIGWINCH (the window size change signal) been received,
539 determine the new screen size and update the screen. */
540 if (received_sigwinch)
542 int old_width = screen_width;
543 screen_width = determine_screen_width ();
545 screen_width = DEFAULT_SCREEN_WIDTH;
546 else if (screen_width < MINIMUM_SCREEN_WIDTH)
547 screen_width = MINIMUM_SCREEN_WIDTH;
548 if (screen_width != old_width)
550 bp->width = screen_width - 1;
551 bp->buffer = xrealloc (bp->buffer, bp->width + 1);
552 force_screen_update = 1;
554 received_sigwinch = 0;
557 if (dltime - bp->last_screen_update < 200 && !force_screen_update)
558 /* Don't update more often than five times per second. */
561 create_image (bp, dltime);
562 display_image (bp->buffer);
563 bp->last_screen_update = dltime;
567 bar_finish (void *progress, double dltime)
569 struct bar_progress *bp = progress;
571 if (bp->total_length > 0
572 && bp->count + bp->initial_length > bp->total_length)
573 /* See bar_update() for explanation. */
574 bp->total_length = bp->initial_length + bp->count;
576 create_image (bp, dltime);
577 display_image (bp->buffer);
579 logputs (LOG_VERBOSE, "\n\n");
585 /* This code attempts to maintain the notion of a "current" download
586 speed, over the course of no less than 3s. (Shorter intervals
587 produce very erratic results.)
589 To do so, it samples the speed in 150ms intervals and stores the
590 recorded samples in a FIFO history ring. The ring stores no more
591 than 20 intervals, hence the history covers the period of at least
592 three seconds and at most 20 reads into the past. This method
593 should produce reasonable results for downloads ranging from very
596 The idea is that for fast downloads, we get the speed over exactly
597 the last three seconds. For slow downloads (where a network read
598 takes more than 150ms to complete), we get the speed over a larger
599 time period, as large as it takes to complete thirty reads. This
600 is good because slow downloads tend to fluctuate more and a
601 3-second average would be too erratic. */
604 update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
606 struct bar_progress_hist *hist = &bp->hist;
607 double recent_age = dltime - bp->recent_start;
609 /* Update the download count. */
610 bp->recent_bytes += howmuch;
612 /* For very small time intervals, we return after having updated the
613 "recent" download count. When its age reaches or exceeds minimum
614 sample time, it will be recorded in the history ring. */
615 if (recent_age < DLSPEED_SAMPLE_MIN)
618 /* Store "recent" bytes and download time to history ring at the
621 /* To correctly maintain the totals, first invalidate existing data
622 (least recent in time) at this position. */
623 hist->total_time -= hist->times[hist->pos];
624 hist->total_bytes -= hist->bytes[hist->pos];
626 /* Now store the new data and update the totals. */
627 hist->times[hist->pos] = recent_age;
628 hist->bytes[hist->pos] = bp->recent_bytes;
629 hist->total_time += recent_age;
630 hist->total_bytes += bp->recent_bytes;
632 /* Start a new "recent" period. */
633 bp->recent_start = dltime;
634 bp->recent_bytes = 0;
636 /* Advance the current ring position. */
637 if (++hist->pos == DLSPEED_HISTORY_SIZE)
641 /* Sledgehammer check to verify that the totals are accurate. */
644 double sumt = 0, sumb = 0;
645 for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
647 sumt += hist->times[i];
648 sumb += hist->bytes[i];
650 assert (sumt == hist->total_time);
651 assert (sumb == hist->total_bytes);
656 #define APPEND_LITERAL(s) do { \
657 memcpy (p, s, sizeof (s) - 1); \
658 p += sizeof (s) - 1; \
662 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
666 create_image (struct bar_progress *bp, double dl_total_time)
668 char *p = bp->buffer;
669 long size = bp->initial_length + bp->count;
671 char *size_legible = legible (size);
672 int size_legible_len = strlen (size_legible);
674 struct bar_progress_hist *hist = &bp->hist;
676 /* The progress bar should look like this:
677 xx% [=======> ] nn,nnn 12.34K/s ETA 00:00
679 Calculate the geometry. The idea is to assign as much room as
680 possible to the progress bar. The other idea is to never let
681 things "jitter", i.e. pad elements that vary in size so that
682 their variance does not affect the placement of other elements.
683 It would be especially bad for the progress bar to be resized
686 "xx% " or "100%" - percentage - 4 chars
687 "[]" - progress bar decorations - 2 chars
688 " nnn,nnn,nnn" - downloaded bytes - 12 chars or very rarely more
689 " 1012.56K/s" - dl rate - 11 chars
690 " ETA xx:xx:xx" - ETA - 13 chars
692 "=====>..." - progress bar - the rest
694 int dlbytes_size = 1 + MAX (size_legible_len, 11);
695 int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);
697 if (progress_size < 5)
701 if (bp->total_length > 0)
703 int percentage = (int)(100.0 * size / bp->total_length);
705 assert (percentage <= 100);
707 if (percentage < 100)
708 sprintf (p, "%2d%% ", percentage);
714 APPEND_LITERAL (" ");
716 /* The progress bar: "[====> ]" or "[++==> ]". */
717 if (progress_size && bp->total_length > 0)
719 /* Size of the initial portion. */
720 int insz = (double)bp->initial_length / bp->total_length * progress_size;
722 /* Size of the downloaded portion. */
723 int dlsz = (double)size / bp->total_length * progress_size;
728 assert (dlsz <= progress_size);
729 assert (insz <= dlsz);
734 /* Print the initial portion of the download with '+' chars, the
735 rest with '=' and one '>'. */
736 for (i = 0; i < insz; i++)
741 for (i = 0; i < dlsz - 1; i++)
746 while (p - begin < progress_size)
750 else if (progress_size)
752 /* If we can't draw a real progress bar, then at least show
753 *something* to the user. */
754 int ind = bp->tick % (progress_size * 2 - 6);
757 /* Make the star move in two directions. */
758 if (ind < progress_size - 2)
761 pos = progress_size - (ind - progress_size + 5);
764 for (i = 0; i < progress_size; i++)
766 if (i == pos - 1) *p++ = '<';
767 else if (i == pos ) *p++ = '=';
768 else if (i == pos + 1) *p++ = '>';
778 sprintf (p, " %-11s", legible (size));
782 if (hist->total_time && hist->total_bytes)
784 static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
786 /* Calculate the download speed using the history ring and
787 recent data that hasn't made it to the ring yet. */
788 long dlquant = hist->total_bytes + bp->recent_bytes;
789 double dltime = hist->total_time + (dl_total_time - bp->recent_start);
790 double dlspeed = calc_rate (dlquant, dltime, &units);
791 sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
795 APPEND_LITERAL (" --.--K/s");
797 /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.
798 That's because the ETA value needs a while to become
800 if (bp->total_length > 0 && dl_total_time > 3000)
803 int eta_hrs, eta_min, eta_sec;
805 /* Don't change the value of ETA more than approximately once
806 per second; doing so would cause flashing without providing
807 any value to the user. */
808 if (bp->total_length != size
809 && bp->last_eta_value != 0
810 && dl_total_time - bp->last_eta_time < 900)
811 eta = bp->last_eta_value;
814 /* Calculate ETA using the average download speed to predict
815 the future speed. If you want to use a speed averaged
816 over a more recent period, replace dl_total_time with
817 hist->total_time and bp->count with hist->total_bytes.
818 I found that doing that results in a very jerky and
819 ultimately unreliable ETA. */
820 double time_sofar = (double)dl_total_time / 1000;
821 long bytes_remaining = bp->total_length - size;
822 eta = (long) (time_sofar * bytes_remaining / bp->count);
823 bp->last_eta_value = eta;
824 bp->last_eta_time = dl_total_time;
827 eta_hrs = eta / 3600, eta %= 3600;
828 eta_min = eta / 60, eta %= 60;
836 /* Hours not printed: pad with three spaces. */
837 APPEND_LITERAL (" ");
838 sprintf (p, " ETA %02d:%02d", eta_min, eta_sec);
843 /* Hours printed with one digit: pad with one space. */
845 sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec);
849 else if (bp->total_length > 0)
852 APPEND_LITERAL (" ");
855 assert (p - bp->buffer <= bp->width);
857 while (p < bp->buffer + bp->width)
862 /* Print the contents of the buffer as a one-line ASCII "image" so
863 that it can be overwritten next time. */
866 display_image (char *buf)
868 int old = log_set_save_context (0);
869 logputs (LOG_VERBOSE, "\r");
870 logputs (LOG_VERBOSE, buf);
871 log_set_save_context (old);
875 bar_set_params (const char *params)
877 char *term = getenv ("TERM");
880 && 0 == strcmp (params, "force"))
881 current_impl_locked = 1;
885 /* The progress bar doesn't make sense if the output is not a
886 TTY -- when logging to file, it is better to review the
888 || !isatty (fileno (stderr))
892 /* Normally we don't depend on terminal type because the
893 progress bar only uses ^M to move the cursor to the
894 beginning of line, which works even on dumb terminals. But
895 Jamie Zawinski reports that ^M and ^H tricks don't work in
896 Emacs shell buffers, and only make a mess. */
897 || (term && 0 == strcmp (term, "emacs"))
899 && !current_impl_locked)
901 /* We're not printing to a TTY, so revert to the fallback
902 display. #### We're recursively calling
903 set_progress_implementation here, which is slightly kludgy.
904 It would be nicer if we provided that function a return value
905 indicating a failure of some sort. */
906 set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
913 progress_handle_sigwinch (int sig)
915 received_sigwinch = 1;
916 signal (SIGWINCH, progress_handle_sigwinch);