]> sjero.net Git - wget/blob - src/progress.c
[svn] Don't cast return type of malloc/realloc. Assume ANSI C signal handlers.
[wget] / src / progress.c
1 /* Download progress.
2    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
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.
10
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.
15
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.
19
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.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <signal.h>
40
41 #include "wget.h"
42 #include "progress.h"
43 #include "utils.h"
44 #include "retr.h"
45
46 struct progress_implementation {
47   const char *name;
48   int interactive;
49   void *(*create) (wgint, wgint);
50   void (*update) (void *, wgint, double);
51   void (*finish) (void *, double);
52   void (*set_params) (const char *);
53 };
54
55 /* Necessary forward declarations. */
56
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 *);
61
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 *);
66
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 }
70 };
71 static struct progress_implementation *current_impl;
72 static int current_impl_locked;
73
74 /* Progress implementation used by default.  Can be overriden in
75    wgetrc or by the fallback one.  */
76
77 #define DEFAULT_PROGRESS_IMPLEMENTATION "bar"
78
79 /* Fallnback 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
83    infloop.  */
84
85 #define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
86
87 /* Return non-zero if NAME names a valid progress bar implementation.
88    The characters after the first : will be ignored.  */
89
90 int
91 valid_progress_implementation_p (const char *name)
92 {
93   int i;
94   struct progress_implementation *pi = implementations;
95   char *colon = strchr (name, ':');
96   int namelen = colon ? colon - name : strlen (name);
97
98   for (i = 0; i < countof (implementations); i++, pi++)
99     if (!strncmp (pi->name, name, namelen))
100       return 1;
101   return 0;
102 }
103
104 /* Set the progress implementation to NAME.  */
105
106 void
107 set_progress_implementation (const char *name)
108 {
109   int i, namelen;
110   struct progress_implementation *pi = implementations;
111   char *colon;
112
113   if (!name)
114     name = DEFAULT_PROGRESS_IMPLEMENTATION;
115
116   colon = strchr (name, ':');
117   namelen = colon ? colon - name : strlen (name);
118
119   for (i = 0; i < countof (implementations); i++, pi++)
120     if (!strncmp (pi->name, name, namelen))
121       {
122         current_impl = pi;
123         current_impl_locked = 0;
124
125         if (colon)
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.  */
129           ++colon;
130
131         if (pi->set_params)
132           pi->set_params (colon);
133         return;
134       }
135   abort ();
136 }
137
138 static int output_redirected;
139
140 void
141 progress_schedule_redirect (void)
142 {
143   output_redirected = 1;
144 }
145
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
150    advance.  */
151
152 void *
153 progress_create (wgint initial, wgint total)
154 {
155   /* Check if the log status has changed under our feet. */
156   if (output_redirected)
157     {
158       if (!current_impl_locked)
159         set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
160       output_redirected = 0;
161     }
162
163   return current_impl->create (initial, total);
164 }
165
166 /* Return non-zero if the progress gauge is "interactive", i.e. if it
167    can profit from being called regularly even in absence of data.
168    The progress bar is interactive because it regularly updates the
169    ETA and current update.  */
170
171 int
172 progress_interactive_p (void *progress)
173 {
174   return current_impl->interactive;
175 }
176
177 /* Inform the progress gauge of newly received bytes.  DLTIME is the
178    time in milliseconds since the beginning of the download.  */
179
180 void
181 progress_update (void *progress, wgint howmuch, double dltime)
182 {
183   current_impl->update (progress, howmuch, dltime);
184 }
185
186 /* Tell the progress gauge to clean up.  Calling this will free the
187    PROGRESS object, the further use of which is not allowed.  */
188
189 void
190 progress_finish (void *progress, double dltime)
191 {
192   current_impl->finish (progress, dltime);
193 }
194 \f
195 /* Dot-printing. */
196
197 struct dot_progress {
198   wgint initial_length;         /* how many bytes have been downloaded
199                                    previously. */
200   wgint total_length;           /* expected total byte count when the
201                                    download finishes */
202
203   int accumulated;
204
205   int rows;                     /* number of rows printed so far */
206   int dots;                     /* number of dots printed in this row */
207   double last_timer_value;
208 };
209
210 /* Dot-progress backend for progress_create. */
211
212 static void *
213 dot_create (wgint initial, wgint total)
214 {
215   struct dot_progress *dp = xnew0 (struct dot_progress);
216   dp->initial_length = initial;
217   dp->total_length   = total;
218
219   if (dp->initial_length)
220     {
221       int dot_bytes = opt.dot_bytes;
222       wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
223
224       int remainder = (int) (dp->initial_length % row_bytes);
225       wgint skipped = dp->initial_length - remainder;
226
227       if (skipped)
228         {
229           int skipped_k = (int) (skipped / 1024); /* skipped amount in K */
230           int skipped_k_len = numdigit (skipped_k);
231           if (skipped_k_len < 5)
232             skipped_k_len = 5;
233
234           /* Align the [ skipping ... ] line with the dots.  To do
235              that, insert the number of spaces equal to the number of
236              digits in the skipped amount in K.  */
237           logprintf (LOG_VERBOSE, _("\n%*s[ skipping %dK ]"),
238                      2 + skipped_k_len, "", skipped_k);
239         }
240
241       logprintf (LOG_VERBOSE, "\n%5ldK", (long) (skipped / 1024));
242       for (; remainder >= dot_bytes; remainder -= dot_bytes)
243         {
244           if (dp->dots % opt.dot_spacing == 0)
245             logputs (LOG_VERBOSE, " ");
246           logputs (LOG_VERBOSE, ",");
247           ++dp->dots;
248         }
249       assert (dp->dots < opt.dots_in_line);
250
251       dp->accumulated = remainder;
252       dp->rows = skipped / row_bytes;
253     }
254
255   return dp;
256 }
257
258 static void
259 print_percentage (wgint bytes, wgint expected)
260 {
261   int percentage = (int)(100.0 * bytes / expected);
262   logprintf (LOG_VERBOSE, "%3d%%", percentage);
263 }
264
265 static void
266 print_download_speed (struct dot_progress *dp, wgint bytes, double dltime)
267 {
268   logprintf (LOG_VERBOSE, " %s",
269              retr_rate (bytes, dltime - dp->last_timer_value, 1));
270   dp->last_timer_value = dltime;
271 }
272
273 /* Dot-progress backend for progress_update. */
274
275 static void
276 dot_update (void *progress, wgint howmuch, double dltime)
277 {
278   struct dot_progress *dp = progress;
279   int dot_bytes = opt.dot_bytes;
280   wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
281
282   log_set_flush (0);
283
284   dp->accumulated += howmuch;
285   for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
286     {
287       if (dp->dots == 0)
288         logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
289
290       if (dp->dots % opt.dot_spacing == 0)
291         logputs (LOG_VERBOSE, " ");
292       logputs (LOG_VERBOSE, ".");
293
294       ++dp->dots;
295       if (dp->dots >= opt.dots_in_line)
296         {
297           wgint row_qty = row_bytes;
298           if (dp->rows == dp->initial_length / row_bytes)
299             row_qty -= dp->initial_length % row_bytes;
300
301           ++dp->rows;
302           dp->dots = 0;
303
304           if (dp->total_length)
305             print_percentage (dp->rows * row_bytes, dp->total_length);
306           print_download_speed (dp, row_qty, dltime);
307         }
308     }
309
310   log_set_flush (1);
311 }
312
313 /* Dot-progress backend for progress_finish. */
314
315 static void
316 dot_finish (void *progress, double dltime)
317 {
318   struct dot_progress *dp = progress;
319   int dot_bytes = opt.dot_bytes;
320   wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
321   int i;
322
323   log_set_flush (0);
324
325   if (dp->dots == 0)
326     logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
327   for (i = dp->dots; i < opt.dots_in_line; i++)
328     {
329       if (i % opt.dot_spacing == 0)
330         logputs (LOG_VERBOSE, " ");
331       logputs (LOG_VERBOSE, " ");
332     }
333   if (dp->total_length)
334     {
335       print_percentage (dp->rows * row_bytes
336                         + dp->dots * dot_bytes
337                         + dp->accumulated,
338                         dp->total_length);
339     }
340
341   {
342     wgint row_qty = dp->dots * dot_bytes + dp->accumulated;
343     if (dp->rows == dp->initial_length / row_bytes)
344       row_qty -= dp->initial_length % row_bytes;
345     print_download_speed (dp, row_qty, dltime);
346   }
347
348   logputs (LOG_VERBOSE, "\n\n");
349   log_set_flush (0);
350
351   xfree (dp);
352 }
353
354 /* This function interprets the progress "parameters".  For example,
355    if Wget is invoked with --progress=dot:mega, it will set the
356    "dot-style" to "mega".  Valid styles are default, binary, mega, and
357    giga.  */
358
359 static void
360 dot_set_params (const char *params)
361 {
362   if (!params || !*params)
363     params = opt.dot_style;
364
365   if (!params)
366     return;
367
368   /* We use this to set the retrieval style.  */
369   if (!strcasecmp (params, "default"))
370     {
371       /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
372          line.  */
373       opt.dot_bytes = 1024;
374       opt.dot_spacing = 10;
375       opt.dots_in_line = 50;
376     }
377   else if (!strcasecmp (params, "binary"))
378     {
379       /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
380          (384K) in a line.  */
381       opt.dot_bytes = 8192;
382       opt.dot_spacing = 16;
383       opt.dots_in_line = 48;
384     }
385   else if (!strcasecmp (params, "mega"))
386     {
387       /* "Mega" retrieval, for retrieving very long files; each dot is
388          64K, 8 dots in a cluster, 6 clusters (3M) in a line.  */
389       opt.dot_bytes = 65536L;
390       opt.dot_spacing = 8;
391       opt.dots_in_line = 48;
392     }
393   else if (!strcasecmp (params, "giga"))
394     {
395       /* "Giga" retrieval, for retrieving very very *very* long files;
396          each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
397          line.  */
398       opt.dot_bytes = (1L << 20);
399       opt.dot_spacing = 8;
400       opt.dots_in_line = 32;
401     }
402   else
403     fprintf (stderr,
404              _("Invalid dot style specification `%s'; leaving unchanged.\n"),
405              params);
406 }
407 \f
408 /* "Thermometer" (bar) progress. */
409
410 /* Assumed screen width if we can't find the real value.  */
411 #define DEFAULT_SCREEN_WIDTH 80
412
413 /* Minimum screen width we'll try to work with.  If this is too small,
414    create_image will overflow the buffer.  */
415 #define MINIMUM_SCREEN_WIDTH 45
416
417 /* The last known screen width.  This can be updated by the code that
418    detects that SIGWINCH was received (but it's never updated from the
419    signal handler).  */
420 static int screen_width;
421
422 /* A flag that, when set, means SIGWINCH was received.  */
423 static volatile sig_atomic_t received_sigwinch;
424
425 /* Size of the download speed history ring. */
426 #define DLSPEED_HISTORY_SIZE 20
427
428 /* The minimum time length of a history sample.  By default, each
429    sample is at least 150ms long, which means that, over the course of
430    20 samples, "current" download speed spans at least 3s into the
431    past.  */
432 #define DLSPEED_SAMPLE_MIN 150
433
434 /* The time after which the download starts to be considered
435    "stalled", i.e. the current bandwidth is not printed and the recent
436    download speeds are scratched.  */
437 #define STALL_START_TIME 5000
438
439 struct bar_progress {
440   wgint initial_length;         /* how many bytes have been downloaded
441                                    previously. */
442   wgint total_length;           /* expected total byte count when the
443                                    download finishes */
444   wgint count;                  /* bytes downloaded so far */
445
446   double last_screen_update;    /* time of the last screen update,
447                                    measured since the beginning of
448                                    download. */
449
450   int width;                    /* screen width we're using at the
451                                    time the progress gauge was
452                                    created.  this is different from
453                                    the screen_width global variable in
454                                    that the latter can be changed by a
455                                    signal. */
456   char *buffer;                 /* buffer where the bar "image" is
457                                    stored. */
458   int tick;                     /* counter used for drawing the
459                                    progress bar where the total size
460                                    is not known. */
461
462   /* The following variables (kept in a struct for namespace reasons)
463      keep track of recent download speeds.  See bar_update() for
464      details.  */
465   struct bar_progress_hist {
466     int pos;
467     wgint times[DLSPEED_HISTORY_SIZE];
468     wgint bytes[DLSPEED_HISTORY_SIZE];
469
470     /* The sum of times and bytes respectively, maintained for
471        efficiency. */
472     wgint total_time;
473     wgint total_bytes;
474   } hist;
475
476   double recent_start;          /* timestamp of beginning of current
477                                    position. */
478   wgint recent_bytes;           /* bytes downloaded so far. */
479
480   int stalled;                  /* set when no data arrives for longer
481                                    than STALL_START_TIME, then reset
482                                    when new data arrives. */
483
484   /* create_image() uses these to make sure that ETA information
485      doesn't flicker. */
486   double last_eta_time;         /* time of the last update to download
487                                    speed and ETA, measured since the
488                                    beginning of download. */
489   wgint last_eta_value;
490 };
491
492 static void create_image (struct bar_progress *, double);
493 static void display_image (char *);
494
495 static void *
496 bar_create (wgint initial, wgint total)
497 {
498   struct bar_progress *bp = xnew0 (struct bar_progress);
499
500   /* In theory, our callers should take care of this pathological
501      case, but it can sometimes happen. */
502   if (initial > total)
503     total = initial;
504
505   bp->initial_length = initial;
506   bp->total_length   = total;
507
508   /* Initialize screen_width if this hasn't been done or if it might
509      have changed, as indicated by receiving SIGWINCH.  */
510   if (!screen_width || received_sigwinch)
511     {
512       screen_width = determine_screen_width ();
513       if (!screen_width)
514         screen_width = DEFAULT_SCREEN_WIDTH;
515       else if (screen_width < MINIMUM_SCREEN_WIDTH)
516         screen_width = MINIMUM_SCREEN_WIDTH;
517       received_sigwinch = 0;
518     }
519
520   /* - 1 because we don't want to use the last screen column. */
521   bp->width = screen_width - 1;
522   /* + 1 for the terminating zero. */
523   bp->buffer = xmalloc (bp->width + 1);
524
525   logputs (LOG_VERBOSE, "\n");
526
527   create_image (bp, 0);
528   display_image (bp->buffer);
529
530   return bp;
531 }
532
533 static void update_speed_ring (struct bar_progress *, wgint, double);
534
535 static void
536 bar_update (void *progress, wgint howmuch, double dltime)
537 {
538   struct bar_progress *bp = progress;
539   int force_screen_update = 0;
540
541   bp->count += howmuch;
542   if (bp->total_length > 0
543       && bp->count + bp->initial_length > bp->total_length)
544     /* We could be downloading more than total_length, e.g. when the
545        server sends an incorrect Content-Length header.  In that case,
546        adjust bp->total_length to the new reality, so that the code in
547        create_image() that depends on total size being smaller or
548        equal to the expected size doesn't abort.  */
549     bp->total_length = bp->initial_length + bp->count;
550
551   update_speed_ring (bp, howmuch, dltime);
552
553   /* If SIGWINCH (the window size change signal) been received,
554      determine the new screen size and update the screen.  */
555   if (received_sigwinch)
556     {
557       int old_width = screen_width;
558       screen_width = determine_screen_width ();
559       if (!screen_width)
560         screen_width = DEFAULT_SCREEN_WIDTH;
561       else if (screen_width < MINIMUM_SCREEN_WIDTH)
562         screen_width = MINIMUM_SCREEN_WIDTH;
563       if (screen_width != old_width)
564         {
565           bp->width = screen_width - 1;
566           bp->buffer = xrealloc (bp->buffer, bp->width + 1);
567           force_screen_update = 1;
568         }
569       received_sigwinch = 0;
570     }
571
572   if (dltime - bp->last_screen_update < 200 && !force_screen_update)
573     /* Don't update more often than five times per second. */
574     return;
575
576   create_image (bp, dltime);
577   display_image (bp->buffer);
578   bp->last_screen_update = dltime;
579 }
580
581 static void
582 bar_finish (void *progress, double dltime)
583 {
584   struct bar_progress *bp = progress;
585
586   if (bp->total_length > 0
587       && bp->count + bp->initial_length > bp->total_length)
588     /* See bar_update() for explanation. */
589     bp->total_length = bp->initial_length + bp->count;
590
591   create_image (bp, dltime);
592   display_image (bp->buffer);
593
594   logputs (LOG_VERBOSE, "\n\n");
595
596   xfree (bp->buffer);
597   xfree (bp);
598 }
599
600 /* This code attempts to maintain the notion of a "current" download
601    speed, over the course of no less than 3s.  (Shorter intervals
602    produce very erratic results.)
603
604    To do so, it samples the speed in 150ms intervals and stores the
605    recorded samples in a FIFO history ring.  The ring stores no more
606    than 20 intervals, hence the history covers the period of at least
607    three seconds and at most 20 reads into the past.  This method
608    should produce reasonable results for downloads ranging from very
609    slow to very fast.
610
611    The idea is that for fast downloads, we get the speed over exactly
612    the last three seconds.  For slow downloads (where a network read
613    takes more than 150ms to complete), we get the speed over a larger
614    time period, as large as it takes to complete thirty reads.  This
615    is good because slow downloads tend to fluctuate more and a
616    3-second average would be too erratic.  */
617
618 static void
619 update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
620 {
621   struct bar_progress_hist *hist = &bp->hist;
622   double recent_age = dltime - bp->recent_start;
623
624   /* Update the download count. */
625   bp->recent_bytes += howmuch;
626
627   /* For very small time intervals, we return after having updated the
628      "recent" download count.  When its age reaches or exceeds minimum
629      sample time, it will be recorded in the history ring.  */
630   if (recent_age < DLSPEED_SAMPLE_MIN)
631     return;
632
633   if (howmuch == 0)
634     {
635       /* If we're not downloading anything, we might be stalling,
636          i.e. not downloading anything for an extended period of time.
637          Since 0-reads do not enter the history ring, recent_age
638          effectively measures the time since last read.  */
639       if (recent_age >= STALL_START_TIME)
640         {
641           /* If we're stalling, reset the ring contents because it's
642              stale and because it will make bar_update stop printing
643              the (bogus) current bandwidth.  */
644           bp->stalled = 1;
645           xzero (*hist);
646           bp->recent_bytes = 0;
647         }
648       return;
649     }
650
651   /* We now have a non-zero amount of to store to the speed ring.  */
652
653   /* If the stall status was acquired, reset it. */
654   if (bp->stalled)
655     {
656       bp->stalled = 0;
657       /* "recent_age" includes the the entired stalled period, which
658          could be very long.  Don't update the speed ring with that
659          value because the current bandwidth would start too small.
660          Start with an arbitrary (but more reasonable) time value and
661          let it level out.  */
662       recent_age = 1000;
663     }
664
665   /* Store "recent" bytes and download time to history ring at the
666      position POS.  */
667
668   /* To correctly maintain the totals, first invalidate existing data
669      (least recent in time) at this position. */
670   hist->total_time  -= hist->times[hist->pos];
671   hist->total_bytes -= hist->bytes[hist->pos];
672
673   /* Now store the new data and update the totals. */
674   hist->times[hist->pos] = recent_age;
675   hist->bytes[hist->pos] = bp->recent_bytes;
676   hist->total_time  += recent_age;
677   hist->total_bytes += bp->recent_bytes;
678
679   /* Start a new "recent" period. */
680   bp->recent_start = dltime;
681   bp->recent_bytes = 0;
682
683   /* Advance the current ring position. */
684   if (++hist->pos == DLSPEED_HISTORY_SIZE)
685     hist->pos = 0;
686
687 #if 0
688   /* Sledgehammer check to verify that the totals are accurate. */
689   {
690     int i;
691     double sumt = 0, sumb = 0;
692     for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
693       {
694         sumt += hist->times[i];
695         sumb += hist->bytes[i];
696       }
697     assert (sumt == hist->total_time);
698     assert (sumb == hist->total_bytes);
699   }
700 #endif
701 }
702
703 #define APPEND_LITERAL(s) do {                  \
704   memcpy (p, s, sizeof (s) - 1);                \
705   p += sizeof (s) - 1;                          \
706 } while (0)
707
708 #ifndef MAX
709 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
710 #endif
711
712 static void
713 create_image (struct bar_progress *bp, double dl_total_time)
714 {
715   char *p = bp->buffer;
716   wgint size = bp->initial_length + bp->count;
717
718   char *size_legible = with_thousand_seps (size);
719   int size_legible_len = strlen (size_legible);
720
721   struct bar_progress_hist *hist = &bp->hist;
722
723   /* The progress bar should look like this:
724      xx% [=======>             ] nn,nnn 12.34K/s ETA 00:00
725
726      Calculate the geometry.  The idea is to assign as much room as
727      possible to the progress bar.  The other idea is to never let
728      things "jitter", i.e. pad elements that vary in size so that
729      their variance does not affect the placement of other elements.
730      It would be especially bad for the progress bar to be resized
731      randomly.
732
733      "xx% " or "100%"  - percentage               - 4 chars
734      "[]"              - progress bar decorations - 2 chars
735      " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more
736      " 1012.56K/s"     - dl rate                  - 11 chars
737      " ETA xx:xx:xx"   - ETA                      - 13 chars
738
739      "=====>..."       - progress bar             - the rest
740   */
741   int dlbytes_size = 1 + MAX (size_legible_len, 11);
742   int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);
743
744   if (progress_size < 5)
745     progress_size = 0;
746
747   /* "xx% " */
748   if (bp->total_length > 0)
749     {
750       int percentage = (int)(100.0 * size / bp->total_length);
751
752       assert (percentage <= 100);
753
754       if (percentage < 100)
755         sprintf (p, "%2d%% ", percentage);
756       else
757         strcpy (p, "100%");
758       p += 4;
759     }
760   else
761     APPEND_LITERAL ("    ");
762
763   /* The progress bar: "[====>      ]" or "[++==>      ]". */
764   if (progress_size && bp->total_length > 0)
765     {
766       /* Size of the initial portion. */
767       int insz = (double)bp->initial_length / bp->total_length * progress_size;
768
769       /* Size of the downloaded portion. */
770       int dlsz = (double)size / bp->total_length * progress_size;
771
772       char *begin;
773       int i;
774
775       assert (dlsz <= progress_size);
776       assert (insz <= dlsz);
777
778       *p++ = '[';
779       begin = p;
780
781       /* Print the initial portion of the download with '+' chars, the
782          rest with '=' and one '>'.  */
783       for (i = 0; i < insz; i++)
784         *p++ = '+';
785       dlsz -= insz;
786       if (dlsz > 0)
787         {
788           for (i = 0; i < dlsz - 1; i++)
789             *p++ = '=';
790           *p++ = '>';
791         }
792
793       while (p - begin < progress_size)
794         *p++ = ' ';
795       *p++ = ']';
796     }
797   else if (progress_size)
798     {
799       /* If we can't draw a real progress bar, then at least show
800          *something* to the user.  */
801       int ind = bp->tick % (progress_size * 2 - 6);
802       int i, pos;
803
804       /* Make the star move in two directions. */
805       if (ind < progress_size - 2)
806         pos = ind + 1;
807       else
808         pos = progress_size - (ind - progress_size + 5);
809
810       *p++ = '[';
811       for (i = 0; i < progress_size; i++)
812         {
813           if      (i == pos - 1) *p++ = '<';
814           else if (i == pos    ) *p++ = '=';
815           else if (i == pos + 1) *p++ = '>';
816           else
817             *p++ = ' ';
818         }
819       *p++ = ']';
820
821       ++bp->tick;
822     }
823
824   /* " 234,567,890" */
825   sprintf (p, " %-11s", with_thousand_seps (size));
826   p += strlen (p);
827
828   /* " 1012.45K/s" */
829   if (hist->total_time && hist->total_bytes)
830     {
831       static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
832       int units = 0;
833       /* Calculate the download speed using the history ring and
834          recent data that hasn't made it to the ring yet.  */
835       wgint dlquant = hist->total_bytes + bp->recent_bytes;
836       double dltime = hist->total_time + (dl_total_time - bp->recent_start);
837       double dlspeed = calc_rate (dlquant, dltime, &units);
838       sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
839       p += strlen (p);
840     }
841   else
842     APPEND_LITERAL ("   --.--K/s");
843
844   /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.
845      That's because the ETA value needs a while to become
846      reliable.  */
847   if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
848     {
849       wgint eta;
850       int eta_hrs, eta_min, eta_sec;
851
852       /* Don't change the value of ETA more than approximately once
853          per second; doing so would cause flashing without providing
854          any value to the user. */
855       if (bp->total_length != size
856           && bp->last_eta_value != 0
857           && dl_total_time - bp->last_eta_time < 900)
858         eta = bp->last_eta_value;
859       else
860         {
861           /* Calculate ETA using the average download speed to predict
862              the future speed.  If you want to use a speed averaged
863              over a more recent period, replace dl_total_time with
864              hist->total_time and bp->count with hist->total_bytes.
865              I found that doing that results in a very jerky and
866              ultimately unreliable ETA.  */
867           double time_sofar = (double)dl_total_time / 1000;
868           wgint bytes_remaining = bp->total_length - size;
869           eta = (wgint) (time_sofar * bytes_remaining / bp->count);
870           bp->last_eta_value = eta;
871           bp->last_eta_time = dl_total_time;
872         }
873
874       eta_hrs = eta / 3600, eta %= 3600;
875       eta_min = eta / 60,   eta %= 60;
876       eta_sec = eta;
877
878       if (eta_hrs > 99)
879         goto no_eta;
880
881       if (eta_hrs == 0)
882         {
883           /* Hours not printed: pad with three spaces. */
884           APPEND_LITERAL ("   ");
885           sprintf (p, " ETA %02d:%02d", eta_min, eta_sec);
886         }
887       else
888         {
889           if (eta_hrs < 10)
890             /* Hours printed with one digit: pad with one space. */
891             *p++ = ' ';
892           sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec);
893         }
894       p += strlen (p);
895     }
896   else if (bp->total_length > 0)
897     {
898     no_eta:
899       APPEND_LITERAL ("             ");
900     }
901
902   assert (p - bp->buffer <= bp->width);
903
904   while (p < bp->buffer + bp->width)
905     *p++ = ' ';
906   *p = '\0';
907 }
908
909 /* Print the contents of the buffer as a one-line ASCII "image" so
910    that it can be overwritten next time.  */
911
912 static void
913 display_image (char *buf)
914 {
915   int old = log_set_save_context (0);
916   logputs (LOG_VERBOSE, "\r");
917   logputs (LOG_VERBOSE, buf);
918   log_set_save_context (old);
919 }
920
921 static void
922 bar_set_params (const char *params)
923 {
924   char *term = getenv ("TERM");
925
926   if (params
927       && 0 == strcmp (params, "force"))
928     current_impl_locked = 1;
929
930   if ((opt.lfilename
931 #ifdef HAVE_ISATTY
932        /* The progress bar doesn't make sense if the output is not a
933           TTY -- when logging to file, it is better to review the
934           dots.  */
935        || !isatty (fileno (stderr))
936 #endif
937        /* Normally we don't depend on terminal type because the
938           progress bar only uses ^M to move the cursor to the
939           beginning of line, which works even on dumb terminals.  But
940           Jamie Zawinski reports that ^M and ^H tricks don't work in
941           Emacs shell buffers, and only make a mess.  */
942        || (term && 0 == strcmp (term, "emacs"))
943        )
944       && !current_impl_locked)
945     {
946       /* We're not printing to a TTY, so revert to the fallback
947          display.  #### We're recursively calling
948          set_progress_implementation here, which is slightly kludgy.
949          It would be nicer if we provided that function a return value
950          indicating a failure of some sort.  */
951       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
952       return;
953     }
954 }
955
956 #ifdef SIGWINCH
957 void
958 progress_handle_sigwinch (int sig)
959 {
960   received_sigwinch = 1;
961   signal (SIGWINCH, progress_handle_sigwinch);
962 }
963 #endif