1/* Download progress.
2   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3   2010, 2011 Free Software Foundation, Inc.
4
5This file is part of GNU Wget.
6
7GNU Wget is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
11
12GNU Wget is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20Additional permission under GNU GPL version 3 section 7
21
22If you modify this program, or any covered work, by linking or
23combining it with the OpenSSL project's OpenSSL library (or a
24modified version of that library), containing parts covered by the
25terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26grants you additional permission to convey the resulting work.
27Corresponding Source for a non-source form of such a combination
28shall include the source code for the parts of OpenSSL used as well
29as that of the covered work.  */
30
31#include "wget.h"
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <assert.h>
37#include <unistd.h>
38#include <signal.h>
39#include <wchar.h>
40#include <mbiter.h>
41
42#include "progress.h"
43#include "utils.h"
44#include "retr.h"
45
46struct progress_implementation {
47  const char *name;
48  bool interactive;
49  void *(*create) (const char *, wgint, wgint);
50  void (*update) (void *, wgint, double);
51  void (*draw) (void *);
52  void (*finish) (void *, double);
53  void (*set_params) (char *);
54};
55
56/* Necessary forward declarations. */
57
58static void *dot_create (const char *, wgint, wgint);
59static void dot_update (void *, wgint, double);
60static void dot_finish (void *, double);
61static void dot_draw (void *);
62static void dot_set_params (char *);
63
64static void *bar_create (const char *, wgint, wgint);
65static void bar_update (void *, wgint, double);
66static void bar_draw (void *);
67static void bar_finish (void *, double);
68static void bar_set_params (char *);
69
70static struct progress_implementation implementations[] = {
71  { "dot", 0, dot_create, dot_update, dot_draw, dot_finish, dot_set_params },
72  { "bar", 1, bar_create, bar_update, bar_draw, bar_finish, bar_set_params }
73};
74static struct progress_implementation *current_impl;
75static int current_impl_locked;
76
77/* Progress implementation used by default.  Can be overriden in
78   wgetrc or by the fallback one.  */
79
80#define DEFAULT_PROGRESS_IMPLEMENTATION "bar"
81
82/* Fallback progress implementation should be something that works
83   under all display types.  If you put something other than "dot"
84   here, remember that bar_set_params tries to switch to this if we're
85   not running on a TTY.  So changing this to "bar" could cause
86   infloop.  */
87
88#define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
89
90/* Return true if NAME names a valid progress bar implementation.  The
91   characters after the first : will be ignored.  */
92
93bool
94valid_progress_implementation_p (const char *name)
95{
96  size_t i;
97  struct progress_implementation *pi = implementations;
98  char *colon = strchr (name, ':');
99  size_t namelen = colon ? (size_t) (colon - name) : strlen (name);
100
101  for (i = 0; i < countof (implementations); i++, pi++)
102    if (!strncmp (pi->name, name, namelen))
103      return true;
104  return false;
105}
106
107/* Set the progress implementation to NAME.  */
108
109void
110set_progress_implementation (const char *name)
111{
112  size_t i, namelen;
113  struct progress_implementation *pi = implementations;
114  char *colon;
115
116  if (!name)
117    name = DEFAULT_PROGRESS_IMPLEMENTATION;
118
119  colon = strchr (name, ':');
120  namelen = colon ? (size_t) (colon - name) : strlen (name);
121
122  for (i = 0; i < countof (implementations); i++, pi++)
123    if (!strncmp (pi->name, name, namelen))
124      {
125        current_impl = pi;
126        current_impl_locked = 0;
127
128        if (colon)
129          /* We call pi->set_params even if colon is NULL because we
130             want to give the implementation a chance to set up some
131             things it needs to run.  */
132          ++colon;
133
134        if (pi->set_params)
135          pi->set_params (colon);
136        return;
137      }
138  abort ();
139}
140
141static int output_redirected;
142
143void
144progress_schedule_redirect (void)
145{
146  output_redirected = 1;
147}
148
149/* Create a progress gauge.  INITIAL is the number of bytes the
150   download starts from (zero if the download starts from scratch).
151   TOTAL is the expected total number of bytes in this download.  If
152   TOTAL is zero, it means that the download size is not known in
153   advance.  */
154
155void *
156progress_create (const char *f_download, wgint initial, wgint total)
157{
158  /* Check if the log status has changed under our feet. */
159  if (output_redirected)
160    {
161      if (!current_impl_locked)
162        set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
163      output_redirected = 0;
164    }
165
166  return current_impl->create (f_download, initial, total);
167}
168
169/* Return true if the progress gauge is "interactive", i.e. if it can
170   profit from being called regularly even in absence of data.  The
171   progress bar is interactive because it regularly updates the ETA
172   and current update.  */
173
174bool
175progress_interactive_p (void *progress _GL_UNUSED)
176{
177  return current_impl->interactive;
178}
179
180/* Inform the progress gauge of newly received bytes.  DLTIME is the
181   time since the beginning of the download.  */
182
183void
184progress_update (void *progress, wgint howmuch, double dltime)
185{
186  current_impl->update (progress, howmuch, dltime);
187  current_impl->draw (progress);
188}
189
190/* Tell the progress gauge to clean up.  Calling this will free the
191   PROGRESS object, the further use of which is not allowed.  */
192
193void
194progress_finish (void *progress, double dltime)
195{
196  current_impl->finish (progress, dltime);
197}
198
199/* Dot-printing. */
200
201struct dot_progress {
202  wgint initial_length;         /* how many bytes have been downloaded
203                                   previously. */
204  wgint total_length;           /* expected total byte count when the
205                                   download finishes */
206
207  int accumulated;              /* number of bytes accumulated after
208                                   the last printed dot */
209
210  double dltime;                /* download time so far */
211  int rows;                     /* number of rows printed so far */
212  int dots;                     /* number of dots printed in this row */
213
214  double last_timer_value;
215};
216
217/* Dot-progress backend for progress_create. */
218
219static void *
220dot_create (const char *f_download _GL_UNUSED, wgint initial, wgint total)
221{
222  struct dot_progress *dp = xnew0 (struct dot_progress);
223  dp->initial_length = initial;
224  dp->total_length   = total;
225
226  if (dp->initial_length)
227    {
228      int dot_bytes = opt.dot_bytes;
229      const wgint ROW_BYTES = opt.dot_bytes * opt.dots_in_line;
230
231      int remainder = dp->initial_length % ROW_BYTES;
232      wgint skipped = dp->initial_length - remainder;
233
234      if (skipped)
235        {
236          wgint skipped_k = skipped / 1024; /* skipped amount in K */
237          int skipped_k_len = numdigit (skipped_k);
238          if (skipped_k_len < 6)
239            skipped_k_len = 6;
240
241          /* Align the [ skipping ... ] line with the dots.  To do
242             that, insert the number of spaces equal to the number of
243             digits in the skipped amount in K.  */
244          logprintf (LOG_PROGRESS, _("\n%*s[ skipping %sK ]"),
245                     2 + skipped_k_len, "",
246                     number_to_static_string (skipped_k));
247        }
248
249      logprintf (LOG_PROGRESS, "\n%6sK",
250                 number_to_static_string (skipped / 1024));
251      for (; remainder >= dot_bytes; remainder -= dot_bytes)
252        {
253          if (dp->dots % opt.dot_spacing == 0)
254            logputs (LOG_PROGRESS, " ");
255          logputs (LOG_PROGRESS, ",");
256          ++dp->dots;
257        }
258      assert (dp->dots < opt.dots_in_line);
259
260      dp->accumulated = remainder;
261      dp->rows = skipped / ROW_BYTES;
262    }
263
264  return dp;
265}
266
267static const char *eta_to_human_short (int, bool);
268
269/* Prints the stats (percentage of completion, speed, ETA) for current
270   row.  DLTIME is the time spent downloading the data in current
271   row.
272
273   #### This function is somewhat uglified by the fact that current
274   row and last row have somewhat different stats requirements.  It
275   might be worthwhile to split it to two different functions.  */
276
277static void
278print_row_stats (struct dot_progress *dp, double dltime, bool last)
279{
280  const wgint ROW_BYTES = opt.dot_bytes * opt.dots_in_line;
281
282  /* bytes_displayed is the number of bytes indicated to the user by
283     dots printed so far, includes the initially "skipped" amount */
284  wgint bytes_displayed = dp->rows * ROW_BYTES + dp->dots * opt.dot_bytes;
285
286  if (last)
287    /* For last row also count bytes accumulated after last dot */
288    bytes_displayed += dp->accumulated;
289
290  if (dp->total_length)
291    {
292      /* Round to floor value to provide gauge how much data *has*
293         been retrieved.  12.8% will round to 12% because the 13% mark
294         has not yet been reached.  100% is only shown when done.  */
295      int percentage = 100.0 * bytes_displayed / dp->total_length;
296      logprintf (LOG_PROGRESS, "%3d%%", percentage);
297    }
298
299  {
300    static char names[] = {' ', 'K', 'M', 'G'};
301    int units;
302    double rate;
303    wgint bytes_this_row;
304    if (!last)
305      bytes_this_row = ROW_BYTES;
306    else
307      /* For last row also include bytes accumulated after last dot.  */
308      bytes_this_row = dp->dots * opt.dot_bytes + dp->accumulated;
309    /* Don't count the portion of the row belonging to initial_length */
310    if (dp->rows == dp->initial_length / ROW_BYTES)
311      bytes_this_row -= dp->initial_length % ROW_BYTES;
312    rate = calc_rate (bytes_this_row, dltime - dp->last_timer_value, &units);
313    logprintf (LOG_PROGRESS, " %4.*f%c",
314               rate >= 99.95 ? 0 : rate >= 9.995 ? 1 : 2,
315               rate, names[units]);
316    dp->last_timer_value = dltime;
317  }
318
319  if (!last)
320    {
321      /* Display ETA based on average speed.  Inspired by Vladi
322         Belperchinov-Shabanski's "wget-new-percentage" patch.  */
323      if (dp->total_length)
324        {
325          wgint bytes_remaining = dp->total_length - bytes_displayed;
326          /* The quantity downloaded in this download run. */
327          wgint bytes_sofar = bytes_displayed - dp->initial_length;
328          double eta = dltime * bytes_remaining / bytes_sofar;
329          if (eta < INT_MAX - 1)
330            logprintf (LOG_PROGRESS, " %s",
331                       eta_to_human_short ((int) (eta + 0.5), true));
332        }
333    }
334  else
335    {
336      /* When done, print the total download time */
337      if (dltime >= 10)
338        logprintf (LOG_PROGRESS, "=%s",
339                   eta_to_human_short ((int) (dltime + 0.5), true));
340      else
341        logprintf (LOG_PROGRESS, "=%ss", print_decimal (dltime));
342    }
343}
344
345/* Dot-progress backend for progress_update. */
346
347static void
348dot_update (void *progress, wgint howmuch, double dltime)
349{
350  struct dot_progress *dp = progress;
351  dp->accumulated += howmuch;
352  dp->dltime = dltime;
353}
354
355static void
356dot_draw (void *progress)
357{
358  struct dot_progress *dp = progress;
359  int dot_bytes = opt.dot_bytes;
360  wgint ROW_BYTES = opt.dot_bytes * opt.dots_in_line;
361
362  log_set_flush (false);
363
364  for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
365    {
366      if (dp->dots == 0)
367        logprintf (LOG_PROGRESS, "\n%6sK",
368                   number_to_static_string (dp->rows * ROW_BYTES / 1024));
369
370      if (dp->dots % opt.dot_spacing == 0)
371        logputs (LOG_PROGRESS, " ");
372      logputs (LOG_PROGRESS, ".");
373
374      ++dp->dots;
375      if (dp->dots >= opt.dots_in_line)
376        {
377          ++dp->rows;
378          dp->dots = 0;
379
380          print_row_stats (dp, dp->dltime, false);
381        }
382    }
383
384  log_set_flush (true);
385}
386
387/* Dot-progress backend for progress_finish. */
388
389static void
390dot_finish (void *progress, double dltime)
391{
392  struct dot_progress *dp = progress;
393  wgint ROW_BYTES = opt.dot_bytes * opt.dots_in_line;
394  int i;
395
396  log_set_flush (false);
397
398  if (dp->dots == 0)
399    logprintf (LOG_PROGRESS, "\n%6sK",
400               number_to_static_string (dp->rows * ROW_BYTES / 1024));
401  for (i = dp->dots; i < opt.dots_in_line; i++)
402    {
403      if (i % opt.dot_spacing == 0)
404        logputs (LOG_PROGRESS, " ");
405      logputs (LOG_PROGRESS, " ");
406    }
407
408  print_row_stats (dp, dltime, true);
409  logputs (LOG_VERBOSE, "\n\n");
410  log_set_flush (false);
411
412  xfree (dp);
413}
414
415/* This function interprets the progress "parameters".  For example,
416   if Wget is invoked with --progress=dot:mega, it will set the
417   "dot-style" to "mega".  Valid styles are default, binary, mega, and
418   giga.  */
419
420static void
421dot_set_params (char *params)
422{
423  if (!params || !*params)
424    params = opt.dot_style;
425
426  if (!params)
427    return;
428
429  /* We use this to set the retrieval style.  */
430  if (!strcasecmp (params, "default"))
431    {
432      /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
433         line.  */
434      opt.dot_bytes = 1024;
435      opt.dot_spacing = 10;
436      opt.dots_in_line = 50;
437    }
438  else if (!strcasecmp (params, "binary"))
439    {
440      /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
441         (384K) in a line.  */
442      opt.dot_bytes = 8192;
443      opt.dot_spacing = 16;
444      opt.dots_in_line = 48;
445    }
446  else if (!strcasecmp (params, "mega"))
447    {
448      /* "Mega" retrieval, for retrieving very long files; each dot is
449         64K, 8 dots in a cluster, 6 clusters (3M) in a line.  */
450      opt.dot_bytes = 65536L;
451      opt.dot_spacing = 8;
452      opt.dots_in_line = 48;
453    }
454  else if (!strcasecmp (params, "giga"))
455    {
456      /* "Giga" retrieval, for retrieving very very *very* long files;
457         each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
458         line.  */
459      opt.dot_bytes = (1L << 20);
460      opt.dot_spacing = 8;
461      opt.dots_in_line = 32;
462    }
463  else
464    fprintf (stderr,
465             _("Invalid dot style specification %s; leaving unchanged.\n"),
466             quote (params));
467}
468
469/* "Thermometer" (bar) progress. */
470
471/* Assumed screen width if we can't find the real value.  */
472#define DEFAULT_SCREEN_WIDTH 80
473
474/* Minimum screen width we'll try to work with.  If this is too small,
475   create_image will overflow the buffer.  */
476#define MINIMUM_SCREEN_WIDTH 45
477
478/* The last known screen width.  This can be updated by the code that
479   detects that SIGWINCH was received (but it's never updated from the
480   signal handler).  */
481static int screen_width;
482
483/* A flag that, when set, means SIGWINCH was received.  */
484static volatile sig_atomic_t received_sigwinch;
485
486/* Size of the download speed history ring. */
487#define DLSPEED_HISTORY_SIZE 20
488
489/* The minimum time length of a history sample.  By default, each
490   sample is at least 150ms long, which means that, over the course of
491   20 samples, "current" download speed spans at least 3s into the
492   past.  */
493#define DLSPEED_SAMPLE_MIN 0.15
494
495/* The time after which the download starts to be considered
496   "stalled", i.e. the current bandwidth is not printed and the recent
497   download speeds are scratched.  */
498#define STALL_START_TIME 5
499
500/* Time between screen refreshes will not be shorter than this, so
501   that Wget doesn't swamp the TTY with output.  */
502#define REFRESH_INTERVAL 0.2
503
504/* Don't refresh the ETA too often to avoid jerkiness in predictions.
505   This allows ETA to change approximately once per second.  */
506#define ETA_REFRESH_INTERVAL 0.99
507
508struct bar_progress {
509  const char *f_download;       /* Filename of the downloaded file */
510  wgint initial_length;         /* how many bytes have been downloaded
511                                   previously. */
512  wgint total_length;           /* expected total byte count when the
513                                   download finishes */
514  wgint count;                  /* bytes downloaded so far */
515
516  double last_screen_update;    /* time of the last screen update,
517                                   measured since the beginning of
518                                   download. */
519
520  double dltime;                /* download time so far */
521  int width;                    /* screen width we're using at the
522                                   time the progress gauge was
523                                   created.  this is different from
524                                   the screen_width global variable in
525                                   that the latter can be changed by a
526                                   signal. */
527  char *buffer;                 /* buffer where the bar "image" is
528                                   stored. */
529  int tick;                     /* counter used for drawing the
530                                   progress bar where the total size
531                                   is not known. */
532
533  /* The following variables (kept in a struct for namespace reasons)
534     keep track of recent download speeds.  See bar_update() for
535     details.  */
536  struct bar_progress_hist {
537    int pos;
538    double times[DLSPEED_HISTORY_SIZE];
539    wgint bytes[DLSPEED_HISTORY_SIZE];
540
541    /* The sum of times and bytes respectively, maintained for
542       efficiency. */
543    double total_time;
544    wgint total_bytes;
545  } hist;
546
547  double recent_start;          /* timestamp of beginning of current
548                                   position. */
549  wgint recent_bytes;           /* bytes downloaded so far. */
550
551  bool stalled;                 /* set when no data arrives for longer
552                                   than STALL_START_TIME, then reset
553                                   when new data arrives. */
554
555  /* create_image() uses these to make sure that ETA information
556     doesn't flicker. */
557  double last_eta_time;         /* time of the last update to download
558                                   speed and ETA, measured since the
559                                   beginning of download. */
560  int last_eta_value;
561};
562
563static void create_image (struct bar_progress *, double, bool);
564static void display_image (char *);
565
566static void *
567bar_create (const char *f_download, wgint initial, wgint total)
568{
569  struct bar_progress *bp = xnew0 (struct bar_progress);
570
571  /* In theory, our callers should take care of this pathological
572     case, but it can sometimes happen. */
573  if (initial > total)
574    total = initial;
575
576  bp->initial_length = initial;
577  bp->total_length   = total;
578  bp->f_download     = f_download;
579
580  /* Initialize screen_width if this hasn't been done or if it might
581     have changed, as indicated by receiving SIGWINCH.  */
582  if (!screen_width || received_sigwinch)
583    {
584      screen_width = determine_screen_width ();
585      if (!screen_width)
586        screen_width = DEFAULT_SCREEN_WIDTH;
587      else if (screen_width < MINIMUM_SCREEN_WIDTH)
588        screen_width = MINIMUM_SCREEN_WIDTH;
589      received_sigwinch = 0;
590    }
591
592  /* - 1 because we don't want to use the last screen column. */
593  bp->width = screen_width - 1;
594  /* + enough space for the terminating zero, and hopefully enough room
595   * for multibyte characters. */
596  bp->buffer = xmalloc (bp->width + 100);
597
598  logputs (LOG_VERBOSE, "\n");
599
600  create_image (bp, 0, false);
601  display_image (bp->buffer);
602
603  return bp;
604}
605
606static void update_speed_ring (struct bar_progress *, wgint, double);
607
608static void
609bar_update (void *progress, wgint howmuch, double dltime)
610{
611  struct bar_progress *bp = progress;
612
613  bp->dltime = dltime;
614  bp->count += howmuch;
615  if (bp->total_length > 0
616      && bp->count + bp->initial_length > bp->total_length)
617    /* We could be downloading more than total_length, e.g. when the
618       server sends an incorrect Content-Length header.  In that case,
619       adjust bp->total_length to the new reality, so that the code in
620       create_image() that depends on total size being smaller or
621       equal to the expected size doesn't abort.  */
622    bp->total_length = bp->initial_length + bp->count;
623
624  update_speed_ring (bp, howmuch, dltime);
625}
626
627static void
628bar_draw (void *progress)
629{
630  bool force_screen_update = false;
631  struct bar_progress *bp = progress;
632
633  /* If SIGWINCH (the window size change signal) been received,
634     determine the new screen size and update the screen.  */
635  if (received_sigwinch)
636    {
637      int old_width = screen_width;
638      screen_width = determine_screen_width ();
639      if (!screen_width)
640        screen_width = DEFAULT_SCREEN_WIDTH;
641      else if (screen_width < MINIMUM_SCREEN_WIDTH)
642        screen_width = MINIMUM_SCREEN_WIDTH;
643      if (screen_width != old_width)
644        {
645          bp->width = screen_width - 1;
646          bp->buffer = xrealloc (bp->buffer, bp->width + 100);
647          force_screen_update = true;
648        }
649      received_sigwinch = 0;
650    }
651
652  if (bp->dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
653    /* Don't update more often than five times per second. */
654    return;
655
656  create_image (bp, bp->dltime, false);
657  display_image (bp->buffer);
658  bp->last_screen_update = bp->dltime;
659}
660
661static void
662bar_finish (void *progress, double dltime)
663{
664  struct bar_progress *bp = progress;
665
666  if (bp->total_length > 0
667      && bp->count + bp->initial_length > bp->total_length)
668    /* See bar_update() for explanation. */
669    bp->total_length = bp->initial_length + bp->count;
670
671  create_image (bp, dltime, true);
672  display_image (bp->buffer);
673
674  logputs (LOG_VERBOSE, "\n");
675  logputs (LOG_PROGRESS, "\n");
676
677  xfree (bp->buffer);
678  xfree (bp);
679}
680
681/* This code attempts to maintain the notion of a "current" download
682   speed, over the course of no less than 3s.  (Shorter intervals
683   produce very erratic results.)
684
685   To do so, it samples the speed in 150ms intervals and stores the
686   recorded samples in a FIFO history ring.  The ring stores no more
687   than 20 intervals, hence the history covers the period of at least
688   three seconds and at most 20 reads into the past.  This method
689   should produce reasonable results for downloads ranging from very
690   slow to very fast.
691
692   The idea is that for fast downloads, we get the speed over exactly
693   the last three seconds.  For slow downloads (where a network read
694   takes more than 150ms to complete), we get the speed over a larger
695   time period, as large as it takes to complete thirty reads.  This
696   is good because slow downloads tend to fluctuate more and a
697   3-second average would be too erratic.  */
698
699static void
700update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
701{
702  struct bar_progress_hist *hist = &bp->hist;
703  double recent_age = dltime - bp->recent_start;
704
705  /* Update the download count. */
706  bp->recent_bytes += howmuch;
707
708  /* For very small time intervals, we return after having updated the
709     "recent" download count.  When its age reaches or exceeds minimum
710     sample time, it will be recorded in the history ring.  */
711  if (recent_age < DLSPEED_SAMPLE_MIN)
712    return;
713
714  if (howmuch == 0)
715    {
716      /* If we're not downloading anything, we might be stalling,
717         i.e. not downloading anything for an extended period of time.
718         Since 0-reads do not enter the history ring, recent_age
719         effectively measures the time since last read.  */
720      if (recent_age >= STALL_START_TIME)
721        {
722          /* If we're stalling, reset the ring contents because it's
723             stale and because it will make bar_update stop printing
724             the (bogus) current bandwidth.  */
725          bp->stalled = true;
726          xzero (*hist);
727          bp->recent_bytes = 0;
728        }
729      return;
730    }
731
732  /* We now have a non-zero amount of to store to the speed ring.  */
733
734  /* If the stall status was acquired, reset it. */
735  if (bp->stalled)
736    {
737      bp->stalled = false;
738      /* "recent_age" includes the entired stalled period, which
739         could be very long.  Don't update the speed ring with that
740         value because the current bandwidth would start too small.
741         Start with an arbitrary (but more reasonable) time value and
742         let it level out.  */
743      recent_age = 1;
744    }
745
746  /* Store "recent" bytes and download time to history ring at the
747     position POS.  */
748
749  /* To correctly maintain the totals, first invalidate existing data
750     (least recent in time) at this position. */
751  hist->total_time  -= hist->times[hist->pos];
752  hist->total_bytes -= hist->bytes[hist->pos];
753
754  /* Now store the new data and update the totals. */
755  hist->times[hist->pos] = recent_age;
756  hist->bytes[hist->pos] = bp->recent_bytes;
757  hist->total_time  += recent_age;
758  hist->total_bytes += bp->recent_bytes;
759
760  /* Start a new "recent" period. */
761  bp->recent_start = dltime;
762  bp->recent_bytes = 0;
763
764  /* Advance the current ring position. */
765  if (++hist->pos == DLSPEED_HISTORY_SIZE)
766    hist->pos = 0;
767
768#if 0
769  /* Sledgehammer check to verify that the totals are accurate. */
770  {
771    int i;
772    double sumt = 0, sumb = 0;
773    for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
774      {
775        sumt += hist->times[i];
776        sumb += hist->bytes[i];
777      }
778    assert (sumb == hist->total_bytes);
779    /* We can't use assert(sumt==hist->total_time) because some
780       precision is lost by adding and subtracting floating-point
781       numbers.  But during a download this precision should not be
782       detectable, i.e. no larger than 1ns.  */
783    double diff = sumt - hist->total_time;
784    if (diff < 0) diff = -diff;
785    assert (diff < 1e-9);
786  }
787#endif
788}
789
790#if USE_NLS_PROGRESS_BAR
791static int
792count_cols (const char *mbs)
793{
794  wchar_t wc;
795  int     bytes;
796  int     remaining = strlen(mbs);
797  int     cols = 0;
798  int     wccols;
799
800  while (*mbs != '\0')
801    {
802      bytes = mbtowc (&wc, mbs, remaining);
803      assert (bytes != 0);  /* Only happens when *mbs == '\0' */
804      if (bytes == -1)
805        {
806          /* Invalid sequence. We'll just have to fudge it. */
807          return cols + remaining;
808        }
809      mbs += bytes;
810      remaining -= bytes;
811      wccols = wcwidth(wc);
812      cols += (wccols == -1? 1 : wccols);
813    }
814  return cols;
815}
816
817static int
818cols_to_bytes (const char *mbs, const int cols, int *ncols)
819{
820  int p_cols = 0, bytes = 0;
821  mbchar_t mbc;
822  mbi_iterator_t iter;
823  mbi_init (iter, mbs, strlen(mbs));
824  while (p_cols < cols && mbi_avail (iter))
825    {
826      mbc = mbi_cur (iter);
827      p_cols += mb_width (mbc);
828      /* The multibyte character has exceeded the total number of columns we
829       * have available. The remaining bytes will be padded with a space. */
830      if (p_cols > cols)
831        {
832          p_cols -= mb_width (mbc);
833          break;
834        }
835      bytes += mb_len (mbc);
836      mbi_advance (iter);
837    }
838  *ncols = p_cols;
839  return bytes;
840}
841#else
842# define count_cols(mbs) ((int)(strlen(mbs)))
843# define cols_to_bytes(mbs, cols, *ncols) do {  \
844    *ncols = cols;                              \
845    bytes = cols;                               \
846}while (0)
847#endif
848
849static const char *
850get_eta (int *bcd)
851{
852  /* TRANSLATORS: "ETA" is English-centric, but this must
853     be short, ideally 3 chars.  Abbreviate if necessary.  */
854  static const char eta_str[] = N_("   eta %s");
855  static const char *eta_trans;
856  static int bytes_cols_diff;
857  if (eta_trans == NULL)
858    {
859      int nbytes;
860      int ncols;
861
862#if USE_NLS_PROGRESS_BAR
863      eta_trans = _(eta_str);
864#else
865      eta_trans = eta_str;
866#endif
867
868      /* Determine the number of bytes used in the translated string,
869       * versus the number of columns used. This is to figure out how
870       * many spaces to add at the end to pad to the full line width.
871       *
872       * We'll store the difference between the number of bytes and
873       * number of columns, so that removing this from the string length
874       * will reveal the total number of columns in the progress bar. */
875      nbytes = strlen (eta_trans);
876      ncols = count_cols (eta_trans);
877      bytes_cols_diff = nbytes - ncols;
878    }
879
880  if (bcd != NULL)
881    *bcd = bytes_cols_diff;
882
883  return eta_trans;
884}
885
886#define APPEND_LITERAL(s) do {                  \
887  memcpy (p, s, sizeof (s) - 1);                \
888  p += sizeof (s) - 1;                          \
889} while (0)
890
891/* Use move_to_end (s) to get S to point the end of the string (the
892   terminating \0).  This is faster than s+=strlen(s), but some people
893   are confused when they see strchr (s, '\0') in the code.  */
894#define move_to_end(s) s = strchr (s, '\0');
895
896#ifndef MAX
897# define MAX(a, b) ((a) >= (b) ? (a) : (b))
898#endif
899#ifndef MIN
900# define MIN(a, b) ((a) <= (b) ? (a) : (b))
901#endif
902
903static void
904create_image (struct bar_progress *bp, double dl_total_time, bool done)
905{
906  const int MAX_FILENAME_COLS = bp->width / 4;
907  char *p = bp->buffer;
908  wgint size = bp->initial_length + bp->count;
909
910  const char *size_grouped = with_thousand_seps (size);
911  int size_grouped_len = count_cols (size_grouped);
912  /* Difference between num cols and num bytes: */
913  int size_grouped_diff = strlen (size_grouped) - size_grouped_len;
914  int size_grouped_pad; /* Used to pad the field width for size_grouped. */
915
916  struct bar_progress_hist *hist = &bp->hist;
917  int orig_filename_cols = count_cols (bp->f_download);
918
919  /* The progress bar should look like this:
920     file xx% [=======>             ] nnn.nnK 12.34KB/s  eta 36m 51s
921
922     Calculate the geometry.  The idea is to assign as much room as
923     possible to the progress bar.  The other idea is to never let
924     things "jitter", i.e. pad elements that vary in size so that
925     their variance does not affect the placement of other elements.
926     It would be especially bad for the progress bar to be resized
927     randomly.
928
929     "file "           - Downloaded filename      - MAX_FILENAME_COLS chars + 1
930     "xx% " or "100%"  - percentage               - 4 chars
931     "[]"              - progress bar decorations - 2 chars
932     " nnn.nnK"        - downloaded bytes         - 7 chars + 1
933     " 12.5KB/s"       - download rate            - 8 chars + 1
934     "  eta 36m 51s"   - ETA                      - 14 chars
935
936     "=====>..."       - progress bar             - the rest
937  */
938
939#define PROGRESS_FILENAME_LEN  MAX_FILENAME_COLS + 1
940#define PROGRESS_PERCENT_LEN   4
941#define PROGRESS_DECORAT_LEN   2
942#define PROGRESS_FILESIZE_LEN  7 + 1
943#define PROGRESS_DWNLOAD_RATE  8 + 1
944#define PROGRESS_ETA_LEN       14
945
946  int progress_size = bp->width - (PROGRESS_FILENAME_LEN + PROGRESS_PERCENT_LEN +
947                                   PROGRESS_DECORAT_LEN + PROGRESS_FILESIZE_LEN +
948                                   PROGRESS_DWNLOAD_RATE + PROGRESS_ETA_LEN);
949
950  /* The difference between the number of bytes used,
951     and the number of columns used. */
952  int bytes_cols_diff = 0;
953
954  if (progress_size < 5)
955    progress_size = 0;
956
957  if (orig_filename_cols <= MAX_FILENAME_COLS)
958    {
959      int padding = MAX_FILENAME_COLS - orig_filename_cols;
960      sprintf (p, "%s ", bp->f_download);
961      p += orig_filename_cols + 1;
962      for (;padding;padding--)
963        *p++ = ' ';
964    }
965  else
966    {
967      int offset_cols;
968      int bytes_in_filename, offset_bytes, col;
969      int *cols_ret = &col;
970
971      if (((orig_filename_cols > MAX_FILENAME_COLS) && !opt.noscroll) && !done)
972        offset_cols = ((int) bp->tick) % (orig_filename_cols - MAX_FILENAME_COLS);
973      else
974        offset_cols = 0;
975      offset_bytes = cols_to_bytes (bp->f_download, offset_cols, cols_ret);
976      bytes_in_filename = cols_to_bytes (bp->f_download + offset_bytes, MAX_FILENAME_COLS, cols_ret);
977      memcpy (p, bp->f_download + offset_bytes, bytes_in_filename);
978      p += bytes_in_filename;
979      int padding = MAX_FILENAME_COLS - *cols_ret;
980      for (;padding;padding--)
981          *p++ = ' ';
982      *p++ = ' ';
983    }
984
985  /* "xx% " */
986  if (bp->total_length > 0)
987    {
988      int percentage = 100.0 * size / bp->total_length;
989      assert (percentage <= 100);
990
991      if (percentage < 100)
992        sprintf (p, "%3d%%", percentage);
993      else
994        strcpy (p, "100%");
995      p += 4;
996    }
997  else
998    APPEND_LITERAL ("    ");
999
1000  /* The progress bar: "[====>      ]" or "[++==>      ]". */
1001  if (progress_size && bp->total_length > 0)
1002    {
1003      /* Size of the initial portion. */
1004      int insz = (double)bp->initial_length / bp->total_length * progress_size;
1005
1006      /* Size of the downloaded portion. */
1007      int dlsz = (double)size / bp->total_length * progress_size;
1008
1009      char *begin;
1010      int i;
1011
1012      assert (dlsz <= progress_size);
1013      assert (insz <= dlsz);
1014
1015      *p++ = '[';
1016      begin = p;
1017
1018      /* Print the initial portion of the download with '+' chars, the
1019         rest with '=' and one '>'.  */
1020      for (i = 0; i < insz; i++)
1021        *p++ = '+';
1022      dlsz -= insz;
1023      if (dlsz > 0)
1024        {
1025          for (i = 0; i < dlsz - 1; i++)
1026            *p++ = '=';
1027          *p++ = '>';
1028        }
1029
1030      while (p - begin < progress_size)
1031        *p++ = ' ';
1032      *p++ = ']';
1033    }
1034  else if (progress_size)
1035    {
1036      /* If we can't draw a real progress bar, then at least show
1037         *something* to the user.  */
1038      int ind = bp->tick % (progress_size * 2 - 6);
1039      int i, pos;
1040
1041      /* Make the star move in two directions. */
1042      if (ind < progress_size - 2)
1043        pos = ind + 1;
1044      else
1045        pos = progress_size - (ind - progress_size + 5);
1046
1047      *p++ = '[';
1048      for (i = 0; i < progress_size; i++)
1049        {
1050          if      (i == pos - 1) *p++ = '<';
1051          else if (i == pos    ) *p++ = '=';
1052          else if (i == pos + 1) *p++ = '>';
1053          else
1054            *p++ = ' ';
1055        }
1056      *p++ = ']';
1057
1058    }
1059 ++bp->tick;
1060
1061  /* " 234.56M" */
1062  const char * down_size = human_readable (size, 1000, 2);
1063  int cols_diff = 7 - count_cols (down_size);
1064  while (cols_diff > 0)
1065  {
1066    *p++=' ';
1067    cols_diff--;
1068  }
1069  sprintf (p, " %s", down_size);
1070  move_to_end (p);
1071  /* Pad with spaces to 7 chars for the size_grouped field;
1072   * couldn't use the field width specifier in sprintf, because
1073   * it counts in bytes, not characters. */
1074  for (size_grouped_pad = PROGRESS_FILESIZE_LEN - 7;
1075       size_grouped_pad > 0;
1076       --size_grouped_pad)
1077    {
1078      *p++ = ' ';
1079    }
1080
1081  /* " 12.52Kb/s or 12.52KB/s" */
1082  if (hist->total_time > 0 && hist->total_bytes)
1083    {
1084      static const char *short_units[] = { " B/s", "KB/s", "MB/s", "GB/s" };
1085      static const char *short_units_bits[] = { " b/s", "Kb/s", "Mb/s", "Gb/s" };
1086      int units = 0;
1087      /* Calculate the download speed using the history ring and
1088         recent data that hasn't made it to the ring yet.  */
1089      wgint dlquant = hist->total_bytes + bp->recent_bytes;
1090      double dltime = hist->total_time + (dl_total_time - bp->recent_start);
1091      double dlspeed = calc_rate (dlquant, dltime, &units);
1092      sprintf (p, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
1093               dlspeed,  !opt.report_bps ? short_units[units] : short_units_bits[units]);
1094      move_to_end (p);
1095    }
1096  else
1097    APPEND_LITERAL (" --.-KB/s");
1098
1099  if (!done)
1100    {
1101      /* "  eta ..m ..s"; wait for three seconds before displaying the ETA.
1102         That's because the ETA value needs a while to become
1103         reliable.  */
1104      if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3)
1105        {
1106          int eta;
1107
1108          /* Don't change the value of ETA more than approximately once
1109             per second; doing so would cause flashing without providing
1110             any value to the user. */
1111          if (bp->total_length != size
1112              && bp->last_eta_value != 0
1113              && dl_total_time - bp->last_eta_time < ETA_REFRESH_INTERVAL)
1114            eta = bp->last_eta_value;
1115          else
1116            {
1117              /* Calculate ETA using the average download speed to predict
1118                 the future speed.  If you want to use a speed averaged
1119                 over a more recent period, replace dl_total_time with
1120                 hist->total_time and bp->count with hist->total_bytes.
1121                 I found that doing that results in a very jerky and
1122                 ultimately unreliable ETA.  */
1123              wgint bytes_remaining = bp->total_length - size;
1124              double eta_ = dl_total_time * bytes_remaining / bp->count;
1125              if (eta_ >= INT_MAX - 1)
1126                goto skip_eta;
1127              eta = (int) (eta_ + 0.5);
1128              bp->last_eta_value = eta;
1129              bp->last_eta_time = dl_total_time;
1130            }
1131
1132          sprintf (p, get_eta(&bytes_cols_diff),
1133                   eta_to_human_short (eta, false));
1134          move_to_end (p);
1135        }
1136      else if (bp->total_length > 0)
1137        {
1138        skip_eta:
1139          APPEND_LITERAL ("             ");
1140        }
1141    }
1142  else
1143    {
1144      /* When the download is done, print the elapsed time.  */
1145      int nbytes;
1146      int ncols;
1147
1148      /* Note to translators: this should not take up more room than
1149         available here.  Abbreviate if necessary.  */
1150      strcpy (p, _("   in "));
1151      nbytes = strlen (p);
1152      ncols  = count_cols (p);
1153      bytes_cols_diff = nbytes - ncols;
1154      p += nbytes;
1155      if (dl_total_time >= 10)
1156        strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
1157      else
1158        sprintf (p, "%ss", print_decimal (dl_total_time));
1159      move_to_end (p);
1160    }
1161
1162  while (p - bp->buffer - bytes_cols_diff - size_grouped_diff < bp->width)
1163    *p++ = ' ';
1164  *p = '\0';
1165}
1166
1167/* Print the contents of the buffer as a one-line ASCII "image" so
1168   that it can be overwritten next time.  */
1169
1170static void
1171display_image (char *buf)
1172{
1173  bool old = log_set_save_context (false);
1174  logputs (LOG_PROGRESS, "\r");
1175  logputs (LOG_PROGRESS, buf);
1176  log_set_save_context (old);
1177}
1178
1179static void
1180bar_set_params (char *params)
1181{
1182  char *term = getenv ("TERM");
1183
1184  if (params)
1185    {
1186      char *param = strtok (params, ":");
1187      do
1188        {
1189          if (0 == strcmp (param, "force"))
1190            current_impl_locked = 1;
1191          else if (0 == strcmp (param, "noscroll"))
1192            opt.noscroll = true;
1193        } while ((param = strtok (NULL, ":")) != NULL);
1194    }
1195
1196  if ((opt.lfilename
1197#ifdef HAVE_ISATTY
1198       /* The progress bar doesn't make sense if the output is not a
1199          TTY -- when logging to file, it is better to review the
1200          dots.  */
1201       || !isatty (fileno (stderr))
1202#endif
1203       /* Normally we don't depend on terminal type because the
1204          progress bar only uses ^M to move the cursor to the
1205          beginning of line, which works even on dumb terminals.  But
1206          Jamie Zawinski reports that ^M and ^H tricks don't work in
1207          Emacs shell buffers, and only make a mess.  */
1208       || (term && 0 == strcmp (term, "emacs"))
1209       )
1210      && !current_impl_locked)
1211    {
1212      /* We're not printing to a TTY, so revert to the fallback
1213         display.  #### We're recursively calling
1214         set_progress_implementation here, which is slightly kludgy.
1215         It would be nicer if we provided that function a return value
1216         indicating a failure of some sort.  */
1217      set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
1218      return;
1219    }
1220}
1221
1222#ifdef SIGWINCH
1223void
1224progress_handle_sigwinch (int sig _GL_UNUSED)
1225{
1226  received_sigwinch = 1;
1227  signal (SIGWINCH, progress_handle_sigwinch);
1228}
1229#endif
1230
1231/* Provide a short human-readable rendition of the ETA.  This is like
1232   secs_to_human_time in main.c, except the output doesn't include
1233   fractions (which would look silly in by nature imprecise ETA) and
1234   takes less room.  If the time is measured in hours, hours and
1235   minutes (but not seconds) are shown; if measured in days, then days
1236   and hours are shown.  This ensures brevity while still displaying
1237   as much as possible.
1238
1239   If CONDENSED is true, the separator between minutes and seconds
1240   (and hours and minutes, etc.) is not included, shortening the
1241   display by one additional character.  This is used for dot
1242   progress.
1243
1244   The display never occupies more than 7 characters of screen
1245   space.  */
1246
1247static const char *
1248eta_to_human_short (int secs, bool condensed)
1249{
1250  static char buf[10];          /* 8 should be enough, but just in case */
1251  static int last = -1;
1252  const char *space = condensed ? "" : " ";
1253
1254  /* Trivial optimization.  create_image can call us every 200 msecs
1255     (see bar_update) for fast downloads, but ETA will only change
1256     once per 900 msecs.  */
1257  if (secs == last)
1258    return buf;
1259  last = secs;
1260
1261  if (secs < 100)
1262    sprintf (buf, "%ds", secs);
1263  else if (secs < 100 * 60)
1264    sprintf (buf, "%dm%s%ds", secs / 60, space, secs % 60);
1265  else if (secs < 48 * 3600)
1266    sprintf (buf, "%dh%s%dm", secs / 3600, space, (secs / 60) % 60);
1267  else if (secs < 100 * 86400)
1268    sprintf (buf, "%dd%s%dh", secs / 86400, space, (secs / 3600) % 24);
1269  else
1270    /* even (2^31-1)/86400 doesn't overflow BUF. */
1271    sprintf (buf, "%dd", secs / 86400);
1272
1273  return buf;
1274}
1275