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 static int screen_width = DEFAULT_SCREEN_WIDTH;
413 /* Size of the download speed history ring. */
414 #define DLSPEED_HISTORY_SIZE 20
416 /* The minimum time length of a history sample. By default, each
417 sample is at least 150ms long, which means that, over the course of
418 20 samples, "current" download speed spans at least 3s into the
420 #define DLSPEED_SAMPLE_MIN 150
422 struct bar_progress {
423 long initial_length; /* how many bytes have been downloaded
425 long total_length; /* expected total byte count when the
427 long count; /* bytes downloaded so far */
429 double last_screen_update; /* time of the last screen update,
430 measured since the beginning of
433 int width; /* screen width we're using at the
434 time the progress gauge was
435 created. this is different from
436 the screen_width global variable in
437 that the latter can be changed by a
439 char *buffer; /* buffer where the bar "image" is
441 int tick; /* counter used for drawing the
442 progress bar where the total size
445 /* The following variables (kept in a struct for namespace reasons)
446 keep track of recent download speeds. See bar_update() for
448 struct bar_progress_hist {
450 long times[DLSPEED_HISTORY_SIZE];
451 long bytes[DLSPEED_HISTORY_SIZE];
453 /* The sum of times and bytes respectively, maintained for
459 double recent_start; /* timestamp of beginning of current
461 long recent_bytes; /* bytes downloaded so far. */
463 /* create_image() uses these to make sure that ETA information
465 double last_eta_time; /* time of the last update to download
466 speed and ETA, measured since the
467 beginning of download. */
471 static void create_image PARAMS ((struct bar_progress *, double));
472 static void display_image PARAMS ((char *));
475 bar_create (long initial, long total)
477 struct bar_progress *bp = xnew0 (struct bar_progress);
479 /* In theory, our callers should take care of this pathological
480 case, but it can sometimes happen. */
484 bp->initial_length = initial;
485 bp->total_length = total;
487 /* - 1 because we don't want to use the last screen column. */
488 bp->width = screen_width - 1;
489 /* + 1 for the terminating zero. */
490 bp->buffer = xmalloc (bp->width + 1);
492 logputs (LOG_VERBOSE, "\n");
494 create_image (bp, 0);
495 display_image (bp->buffer);
500 static void update_speed_ring PARAMS ((struct bar_progress *, long, double));
503 bar_update (void *progress, long howmuch, double dltime)
505 struct bar_progress *bp = progress;
506 int force_screen_update = 0;
508 bp->count += howmuch;
509 if (bp->total_length > 0
510 && bp->count + bp->initial_length > bp->total_length)
511 /* We could be downloading more than total_length, e.g. when the
512 server sends an incorrect Content-Length header. In that case,
513 adjust bp->total_length to the new reality, so that the code in
514 create_image() that depends on total size being smaller or
515 equal to the expected size doesn't abort. */
516 bp->total_length = bp->initial_length + bp->count;
518 update_speed_ring (bp, howmuch, dltime);
520 if (screen_width - 1 != bp->width)
522 bp->width = screen_width - 1;
523 bp->buffer = xrealloc (bp->buffer, bp->width + 1);
524 force_screen_update = 1;
527 if (dltime - bp->last_screen_update < 200 && !force_screen_update)
528 /* Don't update more often than five times per second. */
531 create_image (bp, dltime);
532 display_image (bp->buffer);
533 bp->last_screen_update = dltime;
537 bar_finish (void *progress, double dltime)
539 struct bar_progress *bp = progress;
541 if (bp->total_length > 0
542 && bp->count + bp->initial_length > bp->total_length)
543 /* See bar_update() for explanation. */
544 bp->total_length = bp->initial_length + bp->count;
546 create_image (bp, dltime);
547 display_image (bp->buffer);
549 logputs (LOG_VERBOSE, "\n\n");
555 /* This code attempts to maintain the notion of a "current" download
556 speed, over the course of no less than 3s. (Shorter intervals
557 produce very erratic results.)
559 To do so, it samples the speed in 150ms intervals and stores the
560 recorded samples in a FIFO history ring. The ring stores no more
561 than 20 intervals, hence the history covers the period of at least
562 three seconds and at most 20 reads into the past. This method
563 should produce reasonable results for downloads ranging from very
566 The idea is that for fast downloads, we get the speed over exactly
567 the last three seconds. For slow downloads (where a network read
568 takes more than 150ms to complete), we get the speed over a larger
569 time period, as large as it takes to complete thirty reads. This
570 is good because slow downloads tend to fluctuate more and a
571 3-second average would be too erratic. */
574 update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
576 struct bar_progress_hist *hist = &bp->hist;
577 double recent_age = dltime - bp->recent_start;
579 /* Update the download count. */
580 bp->recent_bytes += howmuch;
582 /* For very small time intervals, we return after having updated the
583 "recent" download count. When its age reaches or exceeds minimum
584 sample time, it will be recorded in the history ring. */
585 if (recent_age < DLSPEED_SAMPLE_MIN)
588 /* Store "recent" bytes and download time to history ring at the
591 /* To correctly maintain the totals, first invalidate existing data
592 (least recent in time) at this position. */
593 hist->total_time -= hist->times[hist->pos];
594 hist->total_bytes -= hist->bytes[hist->pos];
596 /* Now store the new data and update the totals. */
597 hist->times[hist->pos] = recent_age;
598 hist->bytes[hist->pos] = bp->recent_bytes;
599 hist->total_time += recent_age;
600 hist->total_bytes += bp->recent_bytes;
602 /* Start a new "recent" period. */
603 bp->recent_start = dltime;
604 bp->recent_bytes = 0;
606 /* Advance the current ring position. */
607 if (++hist->pos == DLSPEED_HISTORY_SIZE)
611 /* Sledgehammer check to verify that the totals are accurate. */
614 double sumt = 0, sumb = 0;
615 for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
617 sumt += hist->times[i];
618 sumb += hist->bytes[i];
620 assert (sumt == hist->total_time);
621 assert (sumb == hist->total_bytes);
626 #define APPEND_LITERAL(s) do { \
627 memcpy (p, s, sizeof (s) - 1); \
628 p += sizeof (s) - 1; \
632 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
636 create_image (struct bar_progress *bp, double dl_total_time)
638 char *p = bp->buffer;
639 long size = bp->initial_length + bp->count;
641 char *size_legible = legible (size);
642 int size_legible_len = strlen (size_legible);
644 struct bar_progress_hist *hist = &bp->hist;
646 /* The progress bar should look like this:
647 xx% [=======> ] nn,nnn 12.34K/s ETA 00:00
649 Calculate the geometry. The idea is to assign as much room as
650 possible to the progress bar. The other idea is to never let
651 things "jitter", i.e. pad elements that vary in size so that
652 their variance does not affect the placement of other elements.
653 It would be especially bad for the progress bar to be resized
656 "xx% " or "100%" - percentage - 4 chars
657 "[]" - progress bar decorations - 2 chars
658 " nnn,nnn,nnn" - downloaded bytes - 12 chars or very rarely more
659 " 1012.56K/s" - dl rate - 11 chars
660 " ETA xx:xx:xx" - ETA - 13 chars
662 "=====>..." - progress bar - the rest
664 int dlbytes_size = 1 + MAX (size_legible_len, 11);
665 int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);
667 if (progress_size < 5)
671 if (bp->total_length > 0)
673 int percentage = (int)(100.0 * size / bp->total_length);
675 assert (percentage <= 100);
677 if (percentage < 100)
678 sprintf (p, "%2d%% ", percentage);
684 APPEND_LITERAL (" ");
686 /* The progress bar: "[====> ]" or "[++==> ]". */
687 if (progress_size && bp->total_length > 0)
689 /* Size of the initial portion. */
690 int insz = (double)bp->initial_length / bp->total_length * progress_size;
692 /* Size of the downloaded portion. */
693 int dlsz = (double)size / bp->total_length * progress_size;
698 assert (dlsz <= progress_size);
699 assert (insz <= dlsz);
704 /* Print the initial portion of the download with '+' chars, the
705 rest with '=' and one '>'. */
706 for (i = 0; i < insz; i++)
711 for (i = 0; i < dlsz - 1; i++)
716 while (p - begin < progress_size)
720 else if (progress_size)
722 /* If we can't draw a real progress bar, then at least show
723 *something* to the user. */
724 int ind = bp->tick % (progress_size * 2 - 6);
727 /* Make the star move in two directions. */
728 if (ind < progress_size - 2)
731 pos = progress_size - (ind - progress_size + 5);
734 for (i = 0; i < progress_size; i++)
736 if (i == pos - 1) *p++ = '<';
737 else if (i == pos ) *p++ = '=';
738 else if (i == pos + 1) *p++ = '>';
748 sprintf (p, " %-11s", legible (size));
752 if (hist->total_time && hist->total_bytes)
754 static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
756 /* Calculate the download speed using the history ring and
757 recent data that hasn't made it to the ring yet. */
758 long dlquant = hist->total_bytes + bp->recent_bytes;
759 double dltime = hist->total_time + (dl_total_time - bp->recent_start);
760 double dlspeed = calc_rate (dlquant, dltime, &units);
761 sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
765 APPEND_LITERAL (" --.--K/s");
767 /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.
768 That's because the ETA value needs a while to become
770 if (bp->total_length > 0 && dl_total_time > 3000)
773 int eta_hrs, eta_min, eta_sec;
775 /* Don't change the value of ETA more than approximately once
776 per second; doing so would cause flashing without providing
777 any value to the user. */
778 if (bp->total_length != size
779 && bp->last_eta_value != 0
780 && dl_total_time - bp->last_eta_time < 900)
781 eta = bp->last_eta_value;
784 /* Calculate ETA using the average download speed to predict
785 the future speed. If you want to use a speed averaged
786 over a more recent period, replace dl_total_time with
787 hist->total_time and bp->count with hist->total_bytes.
788 I found that doing that results in a very jerky and
789 ultimately unreliable ETA. */
790 double time_sofar = (double)dl_total_time / 1000;
791 long bytes_remaining = bp->total_length - size;
792 eta = (long) (time_sofar * bytes_remaining / bp->count);
793 bp->last_eta_value = eta;
794 bp->last_eta_time = dl_total_time;
797 eta_hrs = eta / 3600, eta %= 3600;
798 eta_min = eta / 60, eta %= 60;
806 /* Hours not printed: pad with three spaces. */
807 APPEND_LITERAL (" ");
808 sprintf (p, " ETA %02d:%02d", eta_min, eta_sec);
813 /* Hours printed with one digit: pad with one space. */
815 sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec);
819 else if (bp->total_length > 0)
822 APPEND_LITERAL (" ");
825 assert (p - bp->buffer <= bp->width);
827 while (p < bp->buffer + bp->width)
832 /* Print the contents of the buffer as a one-line ASCII "image" so
833 that it can be overwritten next time. */
836 display_image (char *buf)
838 int old = log_set_save_context (0);
839 logputs (LOG_VERBOSE, "\r");
840 logputs (LOG_VERBOSE, buf);
841 log_set_save_context (old);
845 bar_set_params (const char *params)
848 char *term = getenv ("TERM");
851 && 0 == strcmp (params, "force"))
852 current_impl_locked = 1;
856 /* The progress bar doesn't make sense if the output is not a
857 TTY -- when logging to file, it is better to review the
859 || !isatty (fileno (stderr))
863 /* Normally we don't depend on terminal type because the
864 progress bar only uses ^M to move the cursor to the
865 beginning of line, which works even on dumb terminals. But
866 Jamie Zawinski reports that ^M and ^H tricks don't work in
867 Emacs shell buffers, and only make a mess. */
868 || (term && 0 == strcmp (term, "emacs"))
870 && !current_impl_locked)
872 /* We're not printing to a TTY, so revert to the fallback
873 display. #### We're recursively calling
874 set_progress_implementation here, which is slightly kludgy.
875 It would be nicer if we provided that function a return value
876 indicating a failure of some sort. */
877 set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
881 sw = determine_screen_width ();
882 if (sw && sw >= MINIMUM_SCREEN_WIDTH)
888 progress_handle_sigwinch (int sig)
890 int sw = determine_screen_width ();
891 if (sw && sw >= MINIMUM_SCREEN_WIDTH)
893 signal (SIGWINCH, progress_handle_sigwinch);