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