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