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. */
46 struct progress_implementation {
49 void *(*create) (wgint, wgint);
50 void (*update) (void *, wgint, double);
51 void (*finish) (void *, double);
52 void (*set_params) (const char *);
55 /* Necessary forward declarations. */
57 static void *dot_create (wgint, wgint);
58 static void dot_update (void *, wgint, double);
59 static void dot_finish (void *, double);
60 static void dot_set_params (const char *);
62 static void *bar_create (wgint, wgint);
63 static void bar_update (void *, wgint, double);
64 static void bar_finish (void *, double);
65 static void bar_set_params (const char *);
67 static struct progress_implementation implementations[] = {
68 { "dot", 0, dot_create, dot_update, dot_finish, dot_set_params },
69 { "bar", 1, bar_create, bar_update, bar_finish, bar_set_params }
71 static struct progress_implementation *current_impl;
72 static int current_impl_locked;
74 /* Progress implementation used by default. Can be overriden in
75 wgetrc or by the fallback one. */
77 #define DEFAULT_PROGRESS_IMPLEMENTATION "bar"
79 /* Fallback progress implementation should be something that works
80 under all display types. If you put something other than "dot"
81 here, remember that bar_set_params tries to switch to this if we're
82 not running on a TTY. So changing this to "bar" could cause
85 #define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
87 /* Return true if NAME names a valid progress bar implementation. The
88 characters after the first : will be ignored. */
91 valid_progress_implementation_p (const char *name)
94 struct progress_implementation *pi = implementations;
95 char *colon = strchr (name, ':');
96 int namelen = colon ? colon - name : strlen (name);
98 for (i = 0; i < countof (implementations); i++, pi++)
99 if (!strncmp (pi->name, name, namelen))
104 /* Set the progress implementation to NAME. */
107 set_progress_implementation (const char *name)
110 struct progress_implementation *pi = implementations;
114 name = DEFAULT_PROGRESS_IMPLEMENTATION;
116 colon = strchr (name, ':');
117 namelen = colon ? colon - name : strlen (name);
119 for (i = 0; i < countof (implementations); i++, pi++)
120 if (!strncmp (pi->name, name, namelen))
123 current_impl_locked = 0;
126 /* We call pi->set_params even if colon is NULL because we
127 want to give the implementation a chance to set up some
128 things it needs to run. */
132 pi->set_params (colon);
138 static int output_redirected;
141 progress_schedule_redirect (void)
143 output_redirected = 1;
146 /* Create a progress gauge. INITIAL is the number of bytes the
147 download starts from (zero if the download starts from scratch).
148 TOTAL is the expected total number of bytes in this download. If
149 TOTAL is zero, it means that the download size is not known in
153 progress_create (wgint initial, wgint total)
155 /* Check if the log status has changed under our feet. */
156 if (output_redirected)
158 if (!current_impl_locked)
159 set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
160 output_redirected = 0;
163 return current_impl->create (initial, total);
166 /* Return true if the progress gauge is "interactive", i.e. if it can
167 profit from being called regularly even in absence of data. The
168 progress bar is interactive because it regularly updates the ETA
169 and current update. */
172 progress_interactive_p (void *progress)
174 return current_impl->interactive;
177 /* Inform the progress gauge of newly received bytes. DLTIME is the
178 time in milliseconds since the beginning of the download. */
181 progress_update (void *progress, wgint howmuch, double dltime)
183 current_impl->update (progress, howmuch, dltime);
186 /* Tell the progress gauge to clean up. Calling this will free the
187 PROGRESS object, the further use of which is not allowed. */
190 progress_finish (void *progress, double dltime)
192 current_impl->finish (progress, dltime);
197 struct dot_progress {
198 wgint initial_length; /* how many bytes have been downloaded
200 wgint total_length; /* expected total byte count when the
203 int accumulated; /* number of bytes accumulated after
204 the last printed dot */
206 int rows; /* number of rows printed so far */
207 int dots; /* number of dots printed in this row */
208 double last_timer_value;
211 /* Dot-progress backend for progress_create. */
214 dot_create (wgint initial, wgint total)
216 struct dot_progress *dp = xnew0 (struct dot_progress);
217 dp->initial_length = initial;
218 dp->total_length = total;
220 if (dp->initial_length)
222 int dot_bytes = opt.dot_bytes;
223 wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
225 int remainder = dp->initial_length % row_bytes;
226 wgint skipped = dp->initial_length - remainder;
230 int skipped_k = skipped / 1024; /* skipped amount in K */
231 int skipped_k_len = numdigit (skipped_k);
232 if (skipped_k_len < 5)
235 /* Align the [ skipping ... ] line with the dots. To do
236 that, insert the number of spaces equal to the number of
237 digits in the skipped amount in K. */
238 logprintf (LOG_VERBOSE, _("\n%*s[ skipping %dK ]"),
239 2 + skipped_k_len, "", skipped_k);
242 logprintf (LOG_VERBOSE, "\n%5ldK", (long) (skipped / 1024));
243 for (; remainder >= dot_bytes; remainder -= dot_bytes)
245 if (dp->dots % opt.dot_spacing == 0)
246 logputs (LOG_VERBOSE, " ");
247 logputs (LOG_VERBOSE, ",");
250 assert (dp->dots < opt.dots_in_line);
252 dp->accumulated = remainder;
253 dp->rows = skipped / row_bytes;
260 print_percentage (wgint bytes, wgint expected)
262 /* Round to the floor value in order to gauge how much data *has*
263 been retrieved. 12.8% will round to 12% because the 13% mark has
264 not yet been reached. 100% is only shown when done. */
265 int percentage = 100.0 * bytes / expected;
266 logprintf (LOG_VERBOSE, "%3d%%", percentage);
270 print_download_speed (struct dot_progress *dp, wgint bytes, double dltime)
272 logprintf (LOG_VERBOSE, " %7s",
273 retr_rate (bytes, dltime - dp->last_timer_value));
274 dp->last_timer_value = dltime;
277 /* Dot-progress backend for progress_update. */
280 dot_update (void *progress, wgint howmuch, double dltime)
282 struct dot_progress *dp = progress;
283 int dot_bytes = opt.dot_bytes;
284 wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
286 log_set_flush (false);
288 dp->accumulated += howmuch;
289 for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
292 logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
294 if (dp->dots % opt.dot_spacing == 0)
295 logputs (LOG_VERBOSE, " ");
296 logputs (LOG_VERBOSE, ".");
299 if (dp->dots >= opt.dots_in_line)
301 wgint row_qty = row_bytes;
302 if (dp->rows == dp->initial_length / row_bytes)
303 row_qty -= dp->initial_length % row_bytes;
308 if (dp->total_length)
309 print_percentage (dp->rows * row_bytes, dp->total_length);
310 print_download_speed (dp, row_qty, dltime);
314 log_set_flush (true);
317 /* Dot-progress backend for progress_finish. */
320 dot_finish (void *progress, double dltime)
322 struct dot_progress *dp = progress;
323 int dot_bytes = opt.dot_bytes;
324 wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
327 log_set_flush (false);
330 logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
331 for (i = dp->dots; i < opt.dots_in_line; i++)
333 if (i % opt.dot_spacing == 0)
334 logputs (LOG_VERBOSE, " ");
335 logputs (LOG_VERBOSE, " ");
337 if (dp->total_length)
339 print_percentage (dp->rows * row_bytes
340 + dp->dots * dot_bytes
346 wgint row_qty = dp->dots * dot_bytes + dp->accumulated;
347 if (dp->rows == dp->initial_length / row_bytes)
348 row_qty -= dp->initial_length % row_bytes;
349 print_download_speed (dp, row_qty, dltime);
352 logputs (LOG_VERBOSE, "\n\n");
353 log_set_flush (false);
358 /* This function interprets the progress "parameters". For example,
359 if Wget is invoked with --progress=dot:mega, it will set the
360 "dot-style" to "mega". Valid styles are default, binary, mega, and
364 dot_set_params (const char *params)
366 if (!params || !*params)
367 params = opt.dot_style;
372 /* We use this to set the retrieval style. */
373 if (!strcasecmp (params, "default"))
375 /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
377 opt.dot_bytes = 1024;
378 opt.dot_spacing = 10;
379 opt.dots_in_line = 50;
381 else if (!strcasecmp (params, "binary"))
383 /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
385 opt.dot_bytes = 8192;
386 opt.dot_spacing = 16;
387 opt.dots_in_line = 48;
389 else if (!strcasecmp (params, "mega"))
391 /* "Mega" retrieval, for retrieving very long files; each dot is
392 64K, 8 dots in a cluster, 6 clusters (3M) in a line. */
393 opt.dot_bytes = 65536L;
395 opt.dots_in_line = 48;
397 else if (!strcasecmp (params, "giga"))
399 /* "Giga" retrieval, for retrieving very very *very* long files;
400 each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
402 opt.dot_bytes = (1L << 20);
404 opt.dots_in_line = 32;
408 _("Invalid dot style specification `%s'; leaving unchanged.\n"),
412 /* "Thermometer" (bar) progress. */
414 /* Assumed screen width if we can't find the real value. */
415 #define DEFAULT_SCREEN_WIDTH 80
417 /* Minimum screen width we'll try to work with. If this is too small,
418 create_image will overflow the buffer. */
419 #define MINIMUM_SCREEN_WIDTH 45
421 /* The last known screen width. This can be updated by the code that
422 detects that SIGWINCH was received (but it's never updated from the
424 static int screen_width;
426 /* A flag that, when set, means SIGWINCH was received. */
427 static volatile sig_atomic_t received_sigwinch;
429 /* Size of the download speed history ring. */
430 #define DLSPEED_HISTORY_SIZE 20
432 /* The minimum time length of a history sample. By default, each
433 sample is at least 150ms long, which means that, over the course of
434 20 samples, "current" download speed spans at least 3s into the
436 #define DLSPEED_SAMPLE_MIN 150
438 /* The time after which the download starts to be considered
439 "stalled", i.e. the current bandwidth is not printed and the recent
440 download speeds are scratched. */
441 #define STALL_START_TIME 5000
443 struct bar_progress {
444 wgint initial_length; /* how many bytes have been downloaded
446 wgint total_length; /* expected total byte count when the
448 wgint count; /* bytes downloaded so far */
450 double last_screen_update; /* time of the last screen update,
451 measured since the beginning of
454 int width; /* screen width we're using at the
455 time the progress gauge was
456 created. this is different from
457 the screen_width global variable in
458 that the latter can be changed by a
460 char *buffer; /* buffer where the bar "image" is
462 int tick; /* counter used for drawing the
463 progress bar where the total size
466 /* The following variables (kept in a struct for namespace reasons)
467 keep track of recent download speeds. See bar_update() for
469 struct bar_progress_hist {
471 wgint times[DLSPEED_HISTORY_SIZE];
472 wgint bytes[DLSPEED_HISTORY_SIZE];
474 /* The sum of times and bytes respectively, maintained for
480 double recent_start; /* timestamp of beginning of current
482 wgint recent_bytes; /* bytes downloaded so far. */
484 bool stalled; /* set when no data arrives for longer
485 than STALL_START_TIME, then reset
486 when new data arrives. */
488 /* create_image() uses these to make sure that ETA information
490 double last_eta_time; /* time of the last update to download
491 speed and ETA, measured since the
492 beginning of download. */
496 static void create_image (struct bar_progress *, double, bool);
497 static void display_image (char *);
500 bar_create (wgint initial, wgint total)
502 struct bar_progress *bp = xnew0 (struct bar_progress);
504 /* In theory, our callers should take care of this pathological
505 case, but it can sometimes happen. */
509 bp->initial_length = initial;
510 bp->total_length = total;
512 /* Initialize screen_width if this hasn't been done or if it might
513 have changed, as indicated by receiving SIGWINCH. */
514 if (!screen_width || received_sigwinch)
516 screen_width = determine_screen_width ();
518 screen_width = DEFAULT_SCREEN_WIDTH;
519 else if (screen_width < MINIMUM_SCREEN_WIDTH)
520 screen_width = MINIMUM_SCREEN_WIDTH;
521 received_sigwinch = 0;
524 /* - 1 because we don't want to use the last screen column. */
525 bp->width = screen_width - 1;
526 /* + 1 for the terminating zero. */
527 bp->buffer = xmalloc (bp->width + 1);
529 logputs (LOG_VERBOSE, "\n");
531 create_image (bp, 0, false);
532 display_image (bp->buffer);
537 static void update_speed_ring (struct bar_progress *, wgint, double);
540 bar_update (void *progress, wgint howmuch, double dltime)
542 struct bar_progress *bp = progress;
543 bool force_screen_update = false;
545 bp->count += howmuch;
546 if (bp->total_length > 0
547 && bp->count + bp->initial_length > bp->total_length)
548 /* We could be downloading more than total_length, e.g. when the
549 server sends an incorrect Content-Length header. In that case,
550 adjust bp->total_length to the new reality, so that the code in
551 create_image() that depends on total size being smaller or
552 equal to the expected size doesn't abort. */
553 bp->total_length = bp->initial_length + bp->count;
555 update_speed_ring (bp, howmuch, dltime);
557 /* If SIGWINCH (the window size change signal) been received,
558 determine the new screen size and update the screen. */
559 if (received_sigwinch)
561 int old_width = screen_width;
562 screen_width = determine_screen_width ();
564 screen_width = DEFAULT_SCREEN_WIDTH;
565 else if (screen_width < MINIMUM_SCREEN_WIDTH)
566 screen_width = MINIMUM_SCREEN_WIDTH;
567 if (screen_width != old_width)
569 bp->width = screen_width - 1;
570 bp->buffer = xrealloc (bp->buffer, bp->width + 1);
571 force_screen_update = true;
573 received_sigwinch = 0;
576 if (dltime - bp->last_screen_update < 200 && !force_screen_update)
577 /* Don't update more often than five times per second. */
580 create_image (bp, dltime, false);
581 display_image (bp->buffer);
582 bp->last_screen_update = dltime;
586 bar_finish (void *progress, double dltime)
588 struct bar_progress *bp = progress;
590 if (bp->total_length > 0
591 && bp->count + bp->initial_length > bp->total_length)
592 /* See bar_update() for explanation. */
593 bp->total_length = bp->initial_length + bp->count;
595 create_image (bp, dltime, true);
596 display_image (bp->buffer);
598 logputs (LOG_VERBOSE, "\n\n");
604 /* This code attempts to maintain the notion of a "current" download
605 speed, over the course of no less than 3s. (Shorter intervals
606 produce very erratic results.)
608 To do so, it samples the speed in 150ms intervals and stores the
609 recorded samples in a FIFO history ring. The ring stores no more
610 than 20 intervals, hence the history covers the period of at least
611 three seconds and at most 20 reads into the past. This method
612 should produce reasonable results for downloads ranging from very
615 The idea is that for fast downloads, we get the speed over exactly
616 the last three seconds. For slow downloads (where a network read
617 takes more than 150ms to complete), we get the speed over a larger
618 time period, as large as it takes to complete thirty reads. This
619 is good because slow downloads tend to fluctuate more and a
620 3-second average would be too erratic. */
623 update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
625 struct bar_progress_hist *hist = &bp->hist;
626 double recent_age = dltime - bp->recent_start;
628 /* Update the download count. */
629 bp->recent_bytes += howmuch;
631 /* For very small time intervals, we return after having updated the
632 "recent" download count. When its age reaches or exceeds minimum
633 sample time, it will be recorded in the history ring. */
634 if (recent_age < DLSPEED_SAMPLE_MIN)
639 /* If we're not downloading anything, we might be stalling,
640 i.e. not downloading anything for an extended period of time.
641 Since 0-reads do not enter the history ring, recent_age
642 effectively measures the time since last read. */
643 if (recent_age >= STALL_START_TIME)
645 /* If we're stalling, reset the ring contents because it's
646 stale and because it will make bar_update stop printing
647 the (bogus) current bandwidth. */
650 bp->recent_bytes = 0;
655 /* We now have a non-zero amount of to store to the speed ring. */
657 /* If the stall status was acquired, reset it. */
661 /* "recent_age" includes the the entired stalled period, which
662 could be very long. Don't update the speed ring with that
663 value because the current bandwidth would start too small.
664 Start with an arbitrary (but more reasonable) time value and
669 /* Store "recent" bytes and download time to history ring at the
672 /* To correctly maintain the totals, first invalidate existing data
673 (least recent in time) at this position. */
674 hist->total_time -= hist->times[hist->pos];
675 hist->total_bytes -= hist->bytes[hist->pos];
677 /* Now store the new data and update the totals. */
678 hist->times[hist->pos] = recent_age;
679 hist->bytes[hist->pos] = bp->recent_bytes;
680 hist->total_time += recent_age;
681 hist->total_bytes += bp->recent_bytes;
683 /* Start a new "recent" period. */
684 bp->recent_start = dltime;
685 bp->recent_bytes = 0;
687 /* Advance the current ring position. */
688 if (++hist->pos == DLSPEED_HISTORY_SIZE)
692 /* Sledgehammer check to verify that the totals are accurate. */
695 double sumt = 0, sumb = 0;
696 for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
698 sumt += hist->times[i];
699 sumb += hist->bytes[i];
701 assert (sumt == hist->total_time);
702 assert (sumb == hist->total_bytes);
707 static const char *eta_to_human_short (int);
709 #define APPEND_LITERAL(s) do { \
710 memcpy (p, s, sizeof (s) - 1); \
711 p += sizeof (s) - 1; \
714 /* Use move_to_end (s) to get S to point the end of the string (the
715 terminating \0). This is faster than s+=strlen(s), but some people
716 are confused when they see strchr (s, '\0') in the code. */
717 #define move_to_end(s) s = strchr (s, '\0');
720 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
724 create_image (struct bar_progress *bp, double dl_total_time, bool done)
726 char *p = bp->buffer;
727 wgint size = bp->initial_length + bp->count;
729 const char *size_grouped = with_thousand_seps (size);
730 int size_grouped_len = strlen (size_grouped);
732 struct bar_progress_hist *hist = &bp->hist;
734 /* The progress bar should look like this:
735 xx% [=======> ] nn,nnn 12.34K/s eta 36m 51s
737 Calculate the geometry. The idea is to assign as much room as
738 possible to the progress bar. The other idea is to never let
739 things "jitter", i.e. pad elements that vary in size so that
740 their variance does not affect the placement of other elements.
741 It would be especially bad for the progress bar to be resized
744 "xx% " or "100%" - percentage - 4 chars
745 "[]" - progress bar decorations - 2 chars
746 " nnn,nnn,nnn" - downloaded bytes - 12 chars or very rarely more
747 " 1012.56K/s" - dl rate - 11 chars
748 " eta 36m 51s" - ETA - 13 chars
750 "=====>..." - progress bar - the rest
752 int dlbytes_size = 1 + MAX (size_grouped_len, 11);
753 int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);
755 if (progress_size < 5)
759 if (bp->total_length > 0)
761 int percentage = 100.0 * size / bp->total_length;
762 assert (percentage <= 100);
764 if (percentage < 100)
765 sprintf (p, "%2d%% ", percentage);
771 APPEND_LITERAL (" ");
773 /* The progress bar: "[====> ]" or "[++==> ]". */
774 if (progress_size && bp->total_length > 0)
776 /* Size of the initial portion. */
777 int insz = (double)bp->initial_length / bp->total_length * progress_size;
779 /* Size of the downloaded portion. */
780 int dlsz = (double)size / bp->total_length * progress_size;
785 assert (dlsz <= progress_size);
786 assert (insz <= dlsz);
791 /* Print the initial portion of the download with '+' chars, the
792 rest with '=' and one '>'. */
793 for (i = 0; i < insz; i++)
798 for (i = 0; i < dlsz - 1; i++)
803 while (p - begin < progress_size)
807 else if (progress_size)
809 /* If we can't draw a real progress bar, then at least show
810 *something* to the user. */
811 int ind = bp->tick % (progress_size * 2 - 6);
814 /* Make the star move in two directions. */
815 if (ind < progress_size - 2)
818 pos = progress_size - (ind - progress_size + 5);
821 for (i = 0; i < progress_size; i++)
823 if (i == pos - 1) *p++ = '<';
824 else if (i == pos ) *p++ = '=';
825 else if (i == pos + 1) *p++ = '>';
835 sprintf (p, " %-11s", size_grouped);
839 if (hist->total_time && hist->total_bytes)
841 static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
843 /* Calculate the download speed using the history ring and
844 recent data that hasn't made it to the ring yet. */
845 wgint dlquant = hist->total_bytes + bp->recent_bytes;
846 double dltime = hist->total_time + (dl_total_time - bp->recent_start);
847 double dlspeed = calc_rate (dlquant, dltime, &units);
848 sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
852 APPEND_LITERAL (" --.--K/s");
856 /* " eta ..m ..s"; wait for three seconds before displaying the ETA.
857 That's because the ETA value needs a while to become
859 if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
863 /* Don't change the value of ETA more than approximately once
864 per second; doing so would cause flashing without providing
865 any value to the user. */
866 if (bp->total_length != size
867 && bp->last_eta_value != 0
868 && dl_total_time - bp->last_eta_time < 900)
869 eta = bp->last_eta_value;
872 /* Calculate ETA using the average download speed to predict
873 the future speed. If you want to use a speed averaged
874 over a more recent period, replace dl_total_time with
875 hist->total_time and bp->count with hist->total_bytes.
876 I found that doing that results in a very jerky and
877 ultimately unreliable ETA. */
878 double time_sofar = (double) dl_total_time / 1000;
879 wgint bytes_remaining = bp->total_length - size;
880 eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5);
881 bp->last_eta_value = eta;
882 bp->last_eta_time = dl_total_time;
885 /* Translation note: "ETA" is English-centric, but this must
886 be short, ideally 3 chars. Abbreviate if necessary. */
887 sprintf (p, _(" eta %s"), eta_to_human_short (eta));
890 else if (bp->total_length > 0)
892 APPEND_LITERAL (" ");
897 /* When the download is done, print the elapsed time. */
898 double secs = dl_total_time / 1000;
899 /* Note to translators: this should not take up more room than
900 available here. Abbreviate if necessary. */
901 strcpy (p, _(" in "));
902 move_to_end (p); /* not p+=6, think translations! */
904 strcpy (p, eta_to_human_short ((int) (secs + 0.5)));
906 /* For very quick downloads show more exact timing information. */
908 secs < 0.001 ? 0 : /* 0s instead of 0.000s */
909 secs < 0.01 ? 3 : /* 0.00x */
910 secs < 0.1 ? 2 : /* 0.0x */
911 1, /* 0.x, 1.x, ..., 9.x */
916 assert (p - bp->buffer <= bp->width);
918 while (p < bp->buffer + bp->width)
923 /* Print the contents of the buffer as a one-line ASCII "image" so
924 that it can be overwritten next time. */
927 display_image (char *buf)
929 bool old = log_set_save_context (false);
930 logputs (LOG_VERBOSE, "\r");
931 logputs (LOG_VERBOSE, buf);
932 log_set_save_context (old);
936 bar_set_params (const char *params)
938 char *term = getenv ("TERM");
941 && 0 == strcmp (params, "force"))
942 current_impl_locked = 1;
946 /* The progress bar doesn't make sense if the output is not a
947 TTY -- when logging to file, it is better to review the
949 || !isatty (fileno (stderr))
951 /* Normally we don't depend on terminal type because the
952 progress bar only uses ^M to move the cursor to the
953 beginning of line, which works even on dumb terminals. But
954 Jamie Zawinski reports that ^M and ^H tricks don't work in
955 Emacs shell buffers, and only make a mess. */
956 || (term && 0 == strcmp (term, "emacs"))
958 && !current_impl_locked)
960 /* We're not printing to a TTY, so revert to the fallback
961 display. #### We're recursively calling
962 set_progress_implementation here, which is slightly kludgy.
963 It would be nicer if we provided that function a return value
964 indicating a failure of some sort. */
965 set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
972 progress_handle_sigwinch (int sig)
974 received_sigwinch = 1;
975 signal (SIGWINCH, progress_handle_sigwinch);
979 /* Provide a short human-readable rendition of the ETA. This is like
980 secs_to_human_time in main.c, except the output doesn't include
981 fractions (which would look silly in by nature imprecise ETA) and
982 takes less room. If the time is measured in hours, hours and
983 minutes (but not seconds) are shown; if measured in days, then days
984 and hours are shown. This ensures brevity while still displaying
987 If SEP is false, the separator between minutes and seconds (and
988 hours and minutes, etc.) is not included, shortening the display by
989 one additional character. This is used for dot progress.
991 The display never occupies more than 7 characters of screen
995 eta_to_human_short (int secs)
997 static char buf[10]; /* 8 should be enough, but just in case */
998 static int last = -1;
1000 /* Trivial optimization. create_image can call us every 200 msecs
1001 (see bar_update) for fast downloads, but ETA will only change
1002 once per 900 msecs. */
1008 sprintf (buf, "%ds", secs);
1009 else if (secs < 100 * 60)
1010 sprintf (buf, "%dm %ds", secs / 60, secs % 60);
1011 else if (secs < 100 * 3600)
1012 sprintf (buf, "%dh %dm", secs / 3600, (secs / 60) % 60);
1013 else if (secs < 100 * 86400)
1014 sprintf (buf, "%dd %dh", secs / 86400, (secs / 3600) % 60);
1016 /* even (2^31-1)/86400 doesn't overflow BUF. */
1017 sprintf (buf, "%dd", secs / 86400);