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