]> sjero.net Git - wget/blobdiff - src/progress.c
Fix compiler warnings
[wget] / src / progress.c
index 77053e7b9524133d78de8d180ac106f5984c0b74..6cb22d70ecb53304c6b2c71b9755d03ffa14f0ff 100644 (file)
@@ -1,11 +1,12 @@
 /* Download progress.
 /* Download progress.
-   Copyright (C) 2001-2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,31 +15,31 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software Foundation, Inc.,
-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 
-In addition, as a special exception, the Free Software Foundation
-gives permission to link the code of its release of Wget with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables.  You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL".  If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so.  If you do not wish to do
-so, delete this exception statement from your version.  */
+Additional permission under GNU GPL version 3 section 7
 
 
-#include <config.h>
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
+
+#include "wget.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #include <signal.h>
 #include <signal.h>
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
 
 
-#include "wget.h"
 #include "progress.h"
 #include "utils.h"
 #include "retr.h"
 #include "progress.h"
 #include "utils.h"
 #include "retr.h"
@@ -46,27 +47,30 @@ so, delete this exception statement from your version.  */
 struct progress_implementation {
   const char *name;
   bool interactive;
 struct progress_implementation {
   const char *name;
   bool interactive;
-  void *(*create) (wgint, wgint);
+  void *(*create) (const char *, wgint, wgint);
   void (*update) (void *, wgint, double);
   void (*update) (void *, wgint, double);
+  void (*draw) (void *);
   void (*finish) (void *, double);
   void (*set_params) (const char *);
 };
 
 /* Necessary forward declarations. */
 
   void (*finish) (void *, double);
   void (*set_params) (const char *);
 };
 
 /* Necessary forward declarations. */
 
-static void *dot_create (wgint, wgint);
+static void *dot_create (const char *, wgint, wgint);
 static void dot_update (void *, wgint, double);
 static void dot_finish (void *, double);
 static void dot_update (void *, wgint, double);
 static void dot_finish (void *, double);
+static void dot_draw (void *);
 static void dot_set_params (const char *);
 
 static void dot_set_params (const char *);
 
-static void *bar_create (wgint, wgint);
+static void *bar_create (const char *, wgint, wgint);
 static void bar_update (void *, wgint, double);
 static void bar_update (void *, wgint, double);
+static void bar_draw (void *);
 static void bar_finish (void *, double);
 static void bar_set_params (const char *);
 
 static struct progress_implementation implementations[] = {
 static void bar_finish (void *, double);
 static void bar_set_params (const char *);
 
 static struct progress_implementation implementations[] = {
-  { "dot", 0, dot_create, dot_update, dot_finish, dot_set_params },
-  { "bar", 1, bar_create, bar_update, bar_finish, bar_set_params }
+  { "dot", 0, dot_create, dot_update, dot_draw, dot_finish, dot_set_params },
+  { "bar", 1, bar_create, bar_update, bar_draw, bar_finish, bar_set_params }
 };
 static struct progress_implementation *current_impl;
 static int current_impl_locked;
 };
 static struct progress_implementation *current_impl;
 static int current_impl_locked;
@@ -90,10 +94,10 @@ static int current_impl_locked;
 bool
 valid_progress_implementation_p (const char *name)
 {
 bool
 valid_progress_implementation_p (const char *name)
 {
-  int i;
+  size_t i;
   struct progress_implementation *pi = implementations;
   char *colon = strchr (name, ':');
   struct progress_implementation *pi = implementations;
   char *colon = strchr (name, ':');
-  int namelen = colon ? colon - name : strlen (name);
+  size_t namelen = colon ? (size_t) (colon - name) : strlen (name);
 
   for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
 
   for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
@@ -106,7 +110,7 @@ valid_progress_implementation_p (const char *name)
 void
 set_progress_implementation (const char *name)
 {
 void
 set_progress_implementation (const char *name)
 {
-  int i, namelen;
+  size_t i, namelen;
   struct progress_implementation *pi = implementations;
   const char *colon;
 
   struct progress_implementation *pi = implementations;
   const char *colon;
 
@@ -114,23 +118,23 @@ set_progress_implementation (const char *name)
     name = DEFAULT_PROGRESS_IMPLEMENTATION;
 
   colon = strchr (name, ':');
     name = DEFAULT_PROGRESS_IMPLEMENTATION;
 
   colon = strchr (name, ':');
-  namelen = colon ? colon - name : strlen (name);
+  namelen = colon ? (size_t) (colon - name) : strlen (name);
 
   for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
       {
 
   for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
       {
-       current_impl = pi;
-       current_impl_locked = 0;
-
-       if (colon)
-         /* We call pi->set_params even if colon is NULL because we
-            want to give the implementation a chance to set up some
-            things it needs to run.  */
-         ++colon;
-
-       if (pi->set_params)
-         pi->set_params (colon);
-       return;
+        current_impl = pi;
+        current_impl_locked = 0;
+
+        if (colon)
+          /* We call pi->set_params even if colon is NULL because we
+             want to give the implementation a chance to set up some
+             things it needs to run.  */
+          ++colon;
+
+        if (pi->set_params)
+          pi->set_params (colon);
+        return;
       }
   abort ();
 }
       }
   abort ();
 }
@@ -150,17 +154,17 @@ progress_schedule_redirect (void)
    advance.  */
 
 void *
    advance.  */
 
 void *
-progress_create (wgint initial, wgint total)
+progress_create (const char *f_download, wgint initial, wgint total)
 {
   /* Check if the log status has changed under our feet. */
   if (output_redirected)
     {
       if (!current_impl_locked)
 {
   /* Check if the log status has changed under our feet. */
   if (output_redirected)
     {
       if (!current_impl_locked)
-       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
+        set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
       output_redirected = 0;
     }
 
       output_redirected = 0;
     }
 
-  return current_impl->create (initial, total);
+  return current_impl->create (f_download, initial, total);
 }
 
 /* Return true if the progress gauge is "interactive", i.e. if it can
 }
 
 /* Return true if the progress gauge is "interactive", i.e. if it can
@@ -169,7 +173,7 @@ progress_create (wgint initial, wgint total)
    and current update.  */
 
 bool
    and current update.  */
 
 bool
-progress_interactive_p (void *progress)
+progress_interactive_p (void *progress _GL_UNUSED)
 {
   return current_impl->interactive;
 }
 {
   return current_impl->interactive;
 }
@@ -181,6 +185,7 @@ void
 progress_update (void *progress, wgint howmuch, double dltime)
 {
   current_impl->update (progress, howmuch, dltime);
 progress_update (void *progress, wgint howmuch, double dltime)
 {
   current_impl->update (progress, howmuch, dltime);
+  current_impl->draw (progress);
 }
 
 /* Tell the progress gauge to clean up.  Calling this will free the
 }
 
 /* Tell the progress gauge to clean up.  Calling this will free the
@@ -195,16 +200,17 @@ progress_finish (void *progress, double dltime)
 /* Dot-printing. */
 
 struct dot_progress {
 /* Dot-printing. */
 
 struct dot_progress {
-  wgint initial_length;                /* how many bytes have been downloaded
-                                  previously. */
-  wgint total_length;          /* expected total byte count when the
-                                  download finishes */
+  wgint initial_length;         /* how many bytes have been downloaded
+                                   previously. */
+  wgint total_length;           /* expected total byte count when the
+                                   download finishes */
 
 
-  int accumulated;             /* number of bytes accumulated after
-                                  the last printed dot */
+  int accumulated;              /* number of bytes accumulated after
+                                   the last printed dot */
 
 
-  int rows;                    /* number of rows printed so far */
-  int dots;                    /* number of dots printed in this row */
+  double dltime;                /* download time so far */
+  int rows;                     /* number of rows printed so far */
+  int dots;                     /* number of dots printed in this row */
 
   double last_timer_value;
 };
 
   double last_timer_value;
 };
@@ -212,7 +218,7 @@ struct dot_progress {
 /* Dot-progress backend for progress_create. */
 
 static void *
 /* Dot-progress backend for progress_create. */
 
 static void *
-dot_create (wgint initial, wgint total)
+dot_create (const char *f_download _GL_UNUSED, wgint initial, wgint total)
 {
   struct dot_progress *dp = xnew0 (struct dot_progress);
   dp->initial_length = initial;
 {
   struct dot_progress *dp = xnew0 (struct dot_progress);
   dp->initial_length = initial;
@@ -227,29 +233,29 @@ dot_create (wgint initial, wgint total)
       wgint skipped = dp->initial_length - remainder;
 
       if (skipped)
       wgint skipped = dp->initial_length - remainder;
 
       if (skipped)
-       {
-         wgint skipped_k = skipped / 1024; /* skipped amount in K */
-         int skipped_k_len = numdigit (skipped_k);
-         if (skipped_k_len < 6)
-           skipped_k_len = 6;
-
-         /* Align the [ skipping ... ] line with the dots.  To do
-            that, insert the number of spaces equal to the number of
-            digits in the skipped amount in K.  */
-         logprintf (LOG_VERBOSE, _("\n%*s[ skipping %sK ]"),
-                    2 + skipped_k_len, "",
-                    number_to_static_string (skipped_k));
-       }
-
-      logprintf (LOG_VERBOSE, "\n%6sK",
-                number_to_static_string (skipped / 1024));
+        {
+          wgint skipped_k = skipped / 1024; /* skipped amount in K */
+          int skipped_k_len = numdigit (skipped_k);
+          if (skipped_k_len < 6)
+            skipped_k_len = 6;
+
+          /* Align the [ skipping ... ] line with the dots.  To do
+             that, insert the number of spaces equal to the number of
+             digits in the skipped amount in K.  */
+          logprintf (LOG_PROGRESS, _("\n%*s[ skipping %sK ]"),
+                     2 + skipped_k_len, "",
+                     number_to_static_string (skipped_k));
+        }
+
+      logprintf (LOG_PROGRESS, "\n%6sK",
+                 number_to_static_string (skipped / 1024));
       for (; remainder >= dot_bytes; remainder -= dot_bytes)
       for (; remainder >= dot_bytes; remainder -= dot_bytes)
-       {
-         if (dp->dots % opt.dot_spacing == 0)
-           logputs (LOG_VERBOSE, " ");
-         logputs (LOG_VERBOSE, ",");
-         ++dp->dots;
-       }
+        {
+          if (dp->dots % opt.dot_spacing == 0)
+            logputs (LOG_PROGRESS, " ");
+          logputs (LOG_PROGRESS, ",");
+          ++dp->dots;
+        }
       assert (dp->dots < opt.dots_in_line);
 
       dp->accumulated = remainder;
       assert (dp->dots < opt.dots_in_line);
 
       dp->accumulated = remainder;
@@ -285,10 +291,10 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
   if (dp->total_length)
     {
       /* Round to floor value to provide gauge how much data *has*
   if (dp->total_length)
     {
       /* Round to floor value to provide gauge how much data *has*
-        been retrieved.  12.8% will round to 12% because the 13% mark
-        has not yet been reached.  100% is only shown when done.  */
+         been retrieved.  12.8% will round to 12% because the 13% mark
+         has not yet been reached.  100% is only shown when done.  */
       int percentage = 100.0 * bytes_displayed / dp->total_length;
       int percentage = 100.0 * bytes_displayed / dp->total_length;
-      logprintf (LOG_VERBOSE, "%3d%%", percentage);
+      logprintf (LOG_PROGRESS, "%3d%%", percentage);
     }
 
   {
     }
 
   {
@@ -305,33 +311,35 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
     if (dp->rows == dp->initial_length / ROW_BYTES)
       bytes_this_row -= dp->initial_length % ROW_BYTES;
     rate = calc_rate (bytes_this_row, dltime - dp->last_timer_value, &units);
     if (dp->rows == dp->initial_length / ROW_BYTES)
       bytes_this_row -= dp->initial_length % ROW_BYTES;
     rate = calc_rate (bytes_this_row, dltime - dp->last_timer_value, &units);
-    logprintf (LOG_VERBOSE, " %4.*f%c",
-              rate >= 99.95 ? 0 : rate >= 9.995 ? 1 : 2,
-              rate, names[units]);
+    logprintf (LOG_PROGRESS, " %4.*f%c",
+               rate >= 99.95 ? 0 : rate >= 9.995 ? 1 : 2,
+               rate, names[units]);
     dp->last_timer_value = dltime;
   }
 
   if (!last)
     {
       /* Display ETA based on average speed.  Inspired by Vladi
     dp->last_timer_value = dltime;
   }
 
   if (!last)
     {
       /* Display ETA based on average speed.  Inspired by Vladi
-        Belperchinov-Shabanski's "wget-new-percentage" patch.  */
+         Belperchinov-Shabanski's "wget-new-percentage" patch.  */
       if (dp->total_length)
       if (dp->total_length)
-       {
-         wgint bytes_remaining = dp->total_length - bytes_displayed;
-         /* The quantity downloaded in this download run. */
-         wgint bytes_sofar = bytes_displayed - dp->initial_length;
-         int eta = (int) (dltime * bytes_remaining / bytes_sofar + 0.5);
-         logprintf (LOG_VERBOSE, " %s", eta_to_human_short (eta, true));
-       }
+        {
+          wgint bytes_remaining = dp->total_length - bytes_displayed;
+          /* The quantity downloaded in this download run. */
+          wgint bytes_sofar = bytes_displayed - dp->initial_length;
+          double eta = dltime * bytes_remaining / bytes_sofar;
+          if (eta < INT_MAX - 1)
+            logprintf (LOG_PROGRESS, " %s",
+                       eta_to_human_short ((int) (eta + 0.5), true));
+        }
     }
   else
     {
       /* When done, print the total download time */
       if (dltime >= 10)
     }
   else
     {
       /* When done, print the total download time */
       if (dltime >= 10)
-       logprintf (LOG_VERBOSE, "=%s",
-                  eta_to_human_short ((int) (dltime + 0.5), true));
+        logprintf (LOG_PROGRESS, "=%s",
+                   eta_to_human_short ((int) (dltime + 0.5), true));
       else
       else
-       logprintf (LOG_VERBOSE, "=%ss", print_decimal (dltime));
+        logprintf (LOG_PROGRESS, "=%ss", print_decimal (dltime));
     }
 }
 
     }
 }
 
@@ -339,6 +347,14 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
 
 static void
 dot_update (void *progress, wgint howmuch, double dltime)
 
 static void
 dot_update (void *progress, wgint howmuch, double dltime)
+{
+  struct dot_progress *dp = progress;
+  dp->accumulated += howmuch;
+  dp->dltime = dltime;
+}
+
+static void
+dot_draw (void *progress)
 {
   struct dot_progress *dp = progress;
   int dot_bytes = opt.dot_bytes;
 {
   struct dot_progress *dp = progress;
   int dot_bytes = opt.dot_bytes;
@@ -346,25 +362,24 @@ dot_update (void *progress, wgint howmuch, double dltime)
 
   log_set_flush (false);
 
 
   log_set_flush (false);
 
-  dp->accumulated += howmuch;
   for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
     {
       if (dp->dots == 0)
   for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
     {
       if (dp->dots == 0)
-       logprintf (LOG_VERBOSE, "\n%6sK",
-                  number_to_static_string (dp->rows * ROW_BYTES / 1024));
+        logprintf (LOG_PROGRESS, "\n%6sK",
+                   number_to_static_string (dp->rows * ROW_BYTES / 1024));
 
       if (dp->dots % opt.dot_spacing == 0)
 
       if (dp->dots % opt.dot_spacing == 0)
-       logputs (LOG_VERBOSE, " ");
-      logputs (LOG_VERBOSE, ".");
+        logputs (LOG_PROGRESS, " ");
+      logputs (LOG_PROGRESS, ".");
 
       ++dp->dots;
       if (dp->dots >= opt.dots_in_line)
 
       ++dp->dots;
       if (dp->dots >= opt.dots_in_line)
-       {
-         ++dp->rows;
-         dp->dots = 0;
+        {
+          ++dp->rows;
+          dp->dots = 0;
 
 
-         print_row_stats (dp, dltime, false);
-       }
+          print_row_stats (dp, dp->dltime, false);
+        }
     }
 
   log_set_flush (true);
     }
 
   log_set_flush (true);
@@ -382,13 +397,13 @@ dot_finish (void *progress, double dltime)
   log_set_flush (false);
 
   if (dp->dots == 0)
   log_set_flush (false);
 
   if (dp->dots == 0)
-    logprintf (LOG_VERBOSE, "\n%6sK",
-              number_to_static_string (dp->rows * ROW_BYTES / 1024));
+    logprintf (LOG_PROGRESS, "\n%6sK",
+               number_to_static_string (dp->rows * ROW_BYTES / 1024));
   for (i = dp->dots; i < opt.dots_in_line; i++)
     {
       if (i % opt.dot_spacing == 0)
   for (i = dp->dots; i < opt.dots_in_line; i++)
     {
       if (i % opt.dot_spacing == 0)
-       logputs (LOG_VERBOSE, " ");
-      logputs (LOG_VERBOSE, " ");
+        logputs (LOG_PROGRESS, " ");
+      logputs (LOG_PROGRESS, " ");
     }
 
   print_row_stats (dp, dltime, true);
     }
 
   print_row_stats (dp, dltime, true);
@@ -416,7 +431,7 @@ dot_set_params (const char *params)
   if (!strcasecmp (params, "default"))
     {
       /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
   if (!strcasecmp (params, "default"))
     {
       /* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
-        line.  */
+         line.  */
       opt.dot_bytes = 1024;
       opt.dot_spacing = 10;
       opt.dots_in_line = 50;
       opt.dot_bytes = 1024;
       opt.dot_spacing = 10;
       opt.dots_in_line = 50;
@@ -424,7 +439,7 @@ dot_set_params (const char *params)
   else if (!strcasecmp (params, "binary"))
     {
       /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
   else if (!strcasecmp (params, "binary"))
     {
       /* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
-        (384K) in a line.  */
+         (384K) in a line.  */
       opt.dot_bytes = 8192;
       opt.dot_spacing = 16;
       opt.dots_in_line = 48;
       opt.dot_bytes = 8192;
       opt.dot_spacing = 16;
       opt.dots_in_line = 48;
@@ -432,7 +447,7 @@ dot_set_params (const char *params)
   else if (!strcasecmp (params, "mega"))
     {
       /* "Mega" retrieval, for retrieving very long files; each dot is
   else if (!strcasecmp (params, "mega"))
     {
       /* "Mega" retrieval, for retrieving very long files; each dot is
-        64K, 8 dots in a cluster, 6 clusters (3M) in a line.  */
+         64K, 8 dots in a cluster, 6 clusters (3M) in a line.  */
       opt.dot_bytes = 65536L;
       opt.dot_spacing = 8;
       opt.dots_in_line = 48;
       opt.dot_bytes = 65536L;
       opt.dot_spacing = 8;
       opt.dots_in_line = 48;
@@ -440,16 +455,16 @@ dot_set_params (const char *params)
   else if (!strcasecmp (params, "giga"))
     {
       /* "Giga" retrieval, for retrieving very very *very* long files;
   else if (!strcasecmp (params, "giga"))
     {
       /* "Giga" retrieval, for retrieving very very *very* long files;
-        each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
-        line.  */
+         each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
+         line.  */
       opt.dot_bytes = (1L << 20);
       opt.dot_spacing = 8;
       opt.dots_in_line = 32;
     }
   else
     fprintf (stderr,
       opt.dot_bytes = (1L << 20);
       opt.dot_spacing = 8;
       opt.dots_in_line = 32;
     }
   else
     fprintf (stderr,
-            _("Invalid dot style specification `%s'; leaving unchanged.\n"),
-            params);
+             _("Invalid dot style specification %s; leaving unchanged.\n"),
+             quote (params));
 }
 \f
 /* "Thermometer" (bar) progress. */
 }
 \f
 /* "Thermometer" (bar) progress. */
@@ -492,27 +507,29 @@ static volatile sig_atomic_t received_sigwinch;
 #define ETA_REFRESH_INTERVAL 0.99
 
 struct bar_progress {
 #define ETA_REFRESH_INTERVAL 0.99
 
 struct bar_progress {
-  wgint initial_length;                /* how many bytes have been downloaded
-                                  previously. */
-  wgint total_length;          /* expected total byte count when the
-                                  download finishes */
-  wgint count;                 /* bytes downloaded so far */
-
-  double last_screen_update;   /* time of the last screen update,
-                                  measured since the beginning of
-                                  download. */
-
-  int width;                   /* screen width we're using at the
-                                  time the progress gauge was
-                                  created.  this is different from
-                                  the screen_width global variable in
-                                  that the latter can be changed by a
-                                  signal. */
-  char *buffer;                        /* buffer where the bar "image" is
-                                  stored. */
-  int tick;                    /* counter used for drawing the
-                                  progress bar where the total size
-                                  is not known. */
+  const char *f_download;       /* Filename of the downloaded file */
+  wgint initial_length;         /* how many bytes have been downloaded
+                                   previously. */
+  wgint total_length;           /* expected total byte count when the
+                                   download finishes */
+  wgint count;                  /* bytes downloaded so far */
+
+  double last_screen_update;    /* time of the last screen update,
+                                   measured since the beginning of
+                                   download. */
+
+  double dltime;                /* download time so far */
+  int width;                    /* screen width we're using at the
+                                   time the progress gauge was
+                                   created.  this is different from
+                                   the screen_width global variable in
+                                   that the latter can be changed by a
+                                   signal. */
+  char *buffer;                 /* buffer where the bar "image" is
+                                   stored. */
+  int tick;                     /* counter used for drawing the
+                                   progress bar where the total size
+                                   is not known. */
 
   /* The following variables (kept in a struct for namespace reasons)
      keep track of recent download speeds.  See bar_update() for
 
   /* The following variables (kept in a struct for namespace reasons)
      keep track of recent download speeds.  See bar_update() for
@@ -528,19 +545,19 @@ struct bar_progress {
     wgint total_bytes;
   } hist;
 
     wgint total_bytes;
   } hist;
 
-  double recent_start;         /* timestamp of beginning of current
-                                  position. */
-  wgint recent_bytes;          /* bytes downloaded so far. */
+  double recent_start;          /* timestamp of beginning of current
+                                   position. */
+  wgint recent_bytes;           /* bytes downloaded so far. */
 
 
-  bool stalled;                        /* set when no data arrives for longer
-                                  than STALL_START_TIME, then reset
-                                  when new data arrives. */
+  bool stalled;                 /* set when no data arrives for longer
+                                   than STALL_START_TIME, then reset
+                                   when new data arrives. */
 
   /* create_image() uses these to make sure that ETA information
      doesn't flicker. */
 
   /* create_image() uses these to make sure that ETA information
      doesn't flicker. */
-  double last_eta_time;                /* time of the last update to download
-                                  speed and ETA, measured since the
-                                  beginning of download. */
+  double last_eta_time;         /* time of the last update to download
+                                   speed and ETA, measured since the
+                                   beginning of download. */
   int last_eta_value;
 };
 
   int last_eta_value;
 };
 
@@ -548,7 +565,7 @@ static void create_image (struct bar_progress *, double, bool);
 static void display_image (char *);
 
 static void *
 static void display_image (char *);
 
 static void *
-bar_create (wgint initial, wgint total)
+bar_create (const char *f_download, wgint initial, wgint total)
 {
   struct bar_progress *bp = xnew0 (struct bar_progress);
 
 {
   struct bar_progress *bp = xnew0 (struct bar_progress);
 
@@ -559,6 +576,7 @@ bar_create (wgint initial, wgint total)
 
   bp->initial_length = initial;
   bp->total_length   = total;
 
   bp->initial_length = initial;
   bp->total_length   = total;
+  bp->f_download     = f_download;
 
   /* Initialize screen_width if this hasn't been done or if it might
      have changed, as indicated by receiving SIGWINCH.  */
 
   /* Initialize screen_width if this hasn't been done or if it might
      have changed, as indicated by receiving SIGWINCH.  */
@@ -566,16 +584,17 @@ bar_create (wgint initial, wgint total)
     {
       screen_width = determine_screen_width ();
       if (!screen_width)
     {
       screen_width = determine_screen_width ();
       if (!screen_width)
-       screen_width = DEFAULT_SCREEN_WIDTH;
+        screen_width = DEFAULT_SCREEN_WIDTH;
       else if (screen_width < MINIMUM_SCREEN_WIDTH)
       else if (screen_width < MINIMUM_SCREEN_WIDTH)
-       screen_width = MINIMUM_SCREEN_WIDTH;
+        screen_width = MINIMUM_SCREEN_WIDTH;
       received_sigwinch = 0;
     }
 
   /* - 1 because we don't want to use the last screen column. */
   bp->width = screen_width - 1;
       received_sigwinch = 0;
     }
 
   /* - 1 because we don't want to use the last screen column. */
   bp->width = screen_width - 1;
-  /* + 1 for the terminating zero. */
-  bp->buffer = xmalloc (bp->width + 1);
+  /* + enough space for the terminating zero, and hopefully enough room
+   * for multibyte characters. */
+  bp->buffer = xmalloc (bp->width + 100);
 
   logputs (LOG_VERBOSE, "\n");
 
 
   logputs (LOG_VERBOSE, "\n");
 
@@ -591,8 +610,8 @@ static void
 bar_update (void *progress, wgint howmuch, double dltime)
 {
   struct bar_progress *bp = progress;
 bar_update (void *progress, wgint howmuch, double dltime)
 {
   struct bar_progress *bp = progress;
-  bool force_screen_update = false;
 
 
+  bp->dltime = dltime;
   bp->count += howmuch;
   if (bp->total_length > 0
       && bp->count + bp->initial_length > bp->total_length)
   bp->count += howmuch;
   if (bp->total_length > 0
       && bp->count + bp->initial_length > bp->total_length)
@@ -604,6 +623,13 @@ bar_update (void *progress, wgint howmuch, double dltime)
     bp->total_length = bp->initial_length + bp->count;
 
   update_speed_ring (bp, howmuch, dltime);
     bp->total_length = bp->initial_length + bp->count;
 
   update_speed_ring (bp, howmuch, dltime);
+}
+
+static void
+bar_draw (void *progress)
+{
+  bool force_screen_update = false;
+  struct bar_progress *bp = progress;
 
   /* If SIGWINCH (the window size change signal) been received,
      determine the new screen size and update the screen.  */
 
   /* If SIGWINCH (the window size change signal) been received,
      determine the new screen size and update the screen.  */
@@ -612,25 +638,25 @@ bar_update (void *progress, wgint howmuch, double dltime)
       int old_width = screen_width;
       screen_width = determine_screen_width ();
       if (!screen_width)
       int old_width = screen_width;
       screen_width = determine_screen_width ();
       if (!screen_width)
-       screen_width = DEFAULT_SCREEN_WIDTH;
+        screen_width = DEFAULT_SCREEN_WIDTH;
       else if (screen_width < MINIMUM_SCREEN_WIDTH)
       else if (screen_width < MINIMUM_SCREEN_WIDTH)
-       screen_width = MINIMUM_SCREEN_WIDTH;
+        screen_width = MINIMUM_SCREEN_WIDTH;
       if (screen_width != old_width)
       if (screen_width != old_width)
-       {
-         bp->width = screen_width - 1;
-         bp->buffer = xrealloc (bp->buffer, bp->width + 1);
-         force_screen_update = true;
-       }
+        {
+          bp->width = screen_width - 1;
+          bp->buffer = xrealloc (bp->buffer, bp->width + 100);
+          force_screen_update = true;
+        }
       received_sigwinch = 0;
     }
 
       received_sigwinch = 0;
     }
 
-  if (dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
+  if (bp->dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
     /* Don't update more often than five times per second. */
     return;
 
     /* Don't update more often than five times per second. */
     return;
 
-  create_image (bp, dltime, false);
+  create_image (bp, bp->dltime, false);
   display_image (bp->buffer);
   display_image (bp->buffer);
-  bp->last_screen_update = dltime;
+  bp->last_screen_update = bp->dltime;
 }
 
 static void
 }
 
 static void
@@ -646,7 +672,8 @@ bar_finish (void *progress, double dltime)
   create_image (bp, dltime, true);
   display_image (bp->buffer);
 
   create_image (bp, dltime, true);
   display_image (bp->buffer);
 
-  logputs (LOG_VERBOSE, "\n\n");
+  logputs (LOG_VERBOSE, "\n");
+  logputs (LOG_PROGRESS, "\n");
 
   xfree (bp->buffer);
   xfree (bp);
 
   xfree (bp->buffer);
   xfree (bp);
@@ -688,18 +715,18 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
   if (howmuch == 0)
     {
       /* If we're not downloading anything, we might be stalling,
   if (howmuch == 0)
     {
       /* If we're not downloading anything, we might be stalling,
-        i.e. not downloading anything for an extended period of time.
-        Since 0-reads do not enter the history ring, recent_age
-        effectively measures the time since last read.  */
+         i.e. not downloading anything for an extended period of time.
+         Since 0-reads do not enter the history ring, recent_age
+         effectively measures the time since last read.  */
       if (recent_age >= STALL_START_TIME)
       if (recent_age >= STALL_START_TIME)
-       {
-         /* If we're stalling, reset the ring contents because it's
-            stale and because it will make bar_update stop printing
-            the (bogus) current bandwidth.  */
-         bp->stalled = true;
-         xzero (*hist);
-         bp->recent_bytes = 0;
-       }
+        {
+          /* If we're stalling, reset the ring contents because it's
+             stale and because it will make bar_update stop printing
+             the (bogus) current bandwidth.  */
+          bp->stalled = true;
+          xzero (*hist);
+          bp->recent_bytes = 0;
+        }
       return;
     }
 
       return;
     }
 
@@ -709,11 +736,11 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
   if (bp->stalled)
     {
       bp->stalled = false;
   if (bp->stalled)
     {
       bp->stalled = false;
-      /* "recent_age" includes the the entired stalled period, which
-        could be very long.  Don't update the speed ring with that
-        value because the current bandwidth would start too small.
-        Start with an arbitrary (but more reasonable) time value and
-        let it level out.  */
+      /* "recent_age" includes the entired stalled period, which
+         could be very long.  Don't update the speed ring with that
+         value because the current bandwidth would start too small.
+         Start with an arbitrary (but more reasonable) time value and
+         let it level out.  */
       recent_age = 1;
     }
 
       recent_age = 1;
     }
 
@@ -746,8 +773,8 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
     double sumt = 0, sumb = 0;
     for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
       {
     double sumt = 0, sumb = 0;
     for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)
       {
-       sumt += hist->times[i];
-       sumb += hist->bytes[i];
+        sumt += hist->times[i];
+        sumb += hist->bytes[i];
       }
     assert (sumb == hist->total_bytes);
     /* We can't use assert(sumt==hist->total_time) because some
       }
     assert (sumb == hist->total_bytes);
     /* We can't use assert(sumt==hist->total_time) because some
@@ -761,9 +788,76 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #endif
 }
 
 #endif
 }
 
-#define APPEND_LITERAL(s) do {                 \
-  memcpy (p, s, sizeof (s) - 1);               \
-  p += sizeof (s) - 1;                         \
+#if USE_NLS_PROGRESS_BAR
+static int
+count_cols (const char *mbs)
+{
+  wchar_t wc;
+  int     bytes;
+  int     remaining = strlen(mbs);
+  int     cols = 0;
+  int     wccols;
+
+  while (*mbs != '\0')
+    {
+      bytes = mbtowc (&wc, mbs, remaining);
+      assert (bytes != 0);  /* Only happens when *mbs == '\0' */
+      if (bytes == -1)
+        {
+          /* Invalid sequence. We'll just have to fudge it. */
+          return cols + remaining;
+        }
+      mbs += bytes;
+      remaining -= bytes;
+      wccols = wcwidth(wc);
+      cols += (wccols == -1? 1 : wccols);
+    }
+  return cols;
+}
+#else
+# define count_cols(mbs) ((int)(strlen(mbs)))
+#endif
+
+static const char *
+get_eta (int *bcd)
+{
+  /* TRANSLATORS: "ETA" is English-centric, but this must
+     be short, ideally 3 chars.  Abbreviate if necessary.  */
+  static const char eta_str[] = N_("   eta %s");
+  static const char *eta_trans;
+  static int bytes_cols_diff;
+  if (eta_trans == NULL)
+    {
+      int nbytes;
+      int ncols;
+
+#if USE_NLS_PROGRESS_BAR
+      eta_trans = _(eta_str);
+#else
+      eta_trans = eta_str;
+#endif
+
+      /* Determine the number of bytes used in the translated string,
+       * versus the number of columns used. This is to figure out how
+       * many spaces to add at the end to pad to the full line width.
+       *
+       * We'll store the difference between the number of bytes and
+       * number of columns, so that removing this from the string length
+       * will reveal the total number of columns in the progress bar. */
+      nbytes = strlen (eta_trans);
+      ncols = count_cols (eta_trans);
+      bytes_cols_diff = nbytes - ncols;
+    }
+
+  if (bcd != NULL)
+    *bcd = bytes_cols_diff;
+
+  return eta_trans;
+}
+
+#define APPEND_LITERAL(s) do {                  \
+  memcpy (p, s, sizeof (s) - 1);                \
+  p += sizeof (s) - 1;                          \
 } while (0)
 
 /* Use move_to_end (s) to get S to point the end of the string (the
 } while (0)
 
 /* Use move_to_end (s) to get S to point the end of the string (the
@@ -774,20 +868,28 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #ifndef MAX
 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
 #endif
 #ifndef MAX
 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
 #endif
+#ifndef MIN
+# define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#endif
 
 static void
 create_image (struct bar_progress *bp, double dl_total_time, bool done)
 {
 
 static void
 create_image (struct bar_progress *bp, double dl_total_time, bool done)
 {
+  const int MAX_FILENAME_LEN = bp->width / 4;
   char *p = bp->buffer;
   wgint size = bp->initial_length + bp->count;
 
   const char *size_grouped = with_thousand_seps (size);
   char *p = bp->buffer;
   wgint size = bp->initial_length + bp->count;
 
   const char *size_grouped = with_thousand_seps (size);
-  int size_grouped_len = strlen (size_grouped);
+  int size_grouped_len = count_cols (size_grouped);
+  /* Difference between num cols and num bytes: */
+  int size_grouped_diff = strlen (size_grouped) - size_grouped_len;
+  int size_grouped_pad; /* Used to pad the field width for size_grouped. */
 
   struct bar_progress_hist *hist = &bp->hist;
 
   struct bar_progress_hist *hist = &bp->hist;
+  int orig_filename_len = strlen (bp->f_download);
 
   /* The progress bar should look like this:
 
   /* The progress bar should look like this:
-     xx% [=======>             ] nn,nnn 12.34K/s  eta 36m 51s
+     file xx% [=======>             ] nn,nnn 12.34KB/s  eta 36m 51s
 
      Calculate the geometry.  The idea is to assign as much room as
      possible to the progress bar.  The other idea is to never let
 
      Calculate the geometry.  The idea is to assign as much room as
      possible to the progress bar.  The other idea is to never let
@@ -796,20 +898,46 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
      It would be especially bad for the progress bar to be resized
      randomly.
 
      It would be especially bad for the progress bar to be resized
      randomly.
 
+     "file "           - Downloaded filename      - MAX MAX_FILENAME_LEN chars + 1
      "xx% " or "100%"  - percentage               - 4 chars
      "[]"              - progress bar decorations - 2 chars
      " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more
      "xx% " or "100%"  - percentage               - 4 chars
      "[]"              - progress bar decorations - 2 chars
      " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more
-     " 12.5K/s"        - download rate             - 8 chars
-     "  eta 36m 51s"   - ETA                      - 13 chars
+     " 12.5KB/s"       - download rate            - 9 chars
+     "  eta 36m 51s"   - ETA                      - 14 chars
 
      "=====>..."       - progress bar             - the rest
   */
   int dlbytes_size = 1 + MAX (size_grouped_len, 11);
 
      "=====>..."       - progress bar             - the rest
   */
   int dlbytes_size = 1 + MAX (size_grouped_len, 11);
-  int progress_size = bp->width - (4 + 2 + dlbytes_size + 8 + 13);
+  int progress_size = bp->width - (MAX_FILENAME_LEN + 1 + 4 + 2 + dlbytes_size + 8 + 14);
+
+  /* The difference between the number of bytes used,
+     and the number of columns used. */
+  int bytes_cols_diff = 0;
 
   if (progress_size < 5)
     progress_size = 0;
 
 
   if (progress_size < 5)
     progress_size = 0;
 
+  if (orig_filename_len <= MAX_FILENAME_LEN)
+    {
+      int padding = MAX_FILENAME_LEN - orig_filename_len;
+      sprintf (p, "%s ", bp->f_download);
+      p += orig_filename_len + 1;
+      for (;padding;padding--)
+        *p++ = ' ';
+    }
+  else
+    {
+      int offset;
+
+      if (orig_filename_len > MAX_FILENAME_LEN)
+        offset = ((int) bp->tick) % (orig_filename_len - MAX_FILENAME_LEN);
+      else
+        offset = 0;
+      memcpy (p, bp->f_download + offset, MAX_FILENAME_LEN);
+      p += MAX_FILENAME_LEN;
+      *p++ = ' ';
+    }
+
   /* "xx% " */
   if (bp->total_length > 0)
     {
   /* "xx% " */
   if (bp->total_length > 0)
     {
@@ -817,9 +945,9 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       assert (percentage <= 100);
 
       if (percentage < 100)
       assert (percentage <= 100);
 
       if (percentage < 100)
-       sprintf (p, "%2d%% ", percentage);
+        sprintf (p, "%2d%% ", percentage);
       else
       else
-       strcpy (p, "100%");
+        strcpy (p, "100%");
       p += 4;
     }
   else
       p += 4;
     }
   else
@@ -844,127 +972,143 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       begin = p;
 
       /* Print the initial portion of the download with '+' chars, the
       begin = p;
 
       /* Print the initial portion of the download with '+' chars, the
-        rest with '=' and one '>'.  */
+         rest with '=' and one '>'.  */
       for (i = 0; i < insz; i++)
       for (i = 0; i < insz; i++)
-       *p++ = '+';
+        *p++ = '+';
       dlsz -= insz;
       if (dlsz > 0)
       dlsz -= insz;
       if (dlsz > 0)
-       {
-         for (i = 0; i < dlsz - 1; i++)
-           *p++ = '=';
-         *p++ = '>';
-       }
+        {
+          for (i = 0; i < dlsz - 1; i++)
+            *p++ = '=';
+          *p++ = '>';
+        }
 
       while (p - begin < progress_size)
 
       while (p - begin < progress_size)
-       *p++ = ' ';
+        *p++ = ' ';
       *p++ = ']';
     }
   else if (progress_size)
     {
       /* If we can't draw a real progress bar, then at least show
       *p++ = ']';
     }
   else if (progress_size)
     {
       /* If we can't draw a real progress bar, then at least show
-        *something* to the user.  */
+         *something* to the user.  */
       int ind = bp->tick % (progress_size * 2 - 6);
       int i, pos;
 
       /* Make the star move in two directions. */
       if (ind < progress_size - 2)
       int ind = bp->tick % (progress_size * 2 - 6);
       int i, pos;
 
       /* Make the star move in two directions. */
       if (ind < progress_size - 2)
-       pos = ind + 1;
+        pos = ind + 1;
       else
       else
-       pos = progress_size - (ind - progress_size + 5);
+        pos = progress_size - (ind - progress_size + 5);
 
       *p++ = '[';
       for (i = 0; i < progress_size; i++)
 
       *p++ = '[';
       for (i = 0; i < progress_size; i++)
-       {
-         if      (i == pos - 1) *p++ = '<';
-         else if (i == pos    ) *p++ = '=';
-         else if (i == pos + 1) *p++ = '>';
-         else
-           *p++ = ' ';
-       }
+        {
+          if      (i == pos - 1) *p++ = '<';
+          else if (i == pos    ) *p++ = '=';
+          else if (i == pos + 1) *p++ = '>';
+          else
+            *p++ = ' ';
+        }
       *p++ = ']';
 
       *p++ = ']';
 
-      ++bp->tick;
     }
     }
+ ++bp->tick;
 
   /* " 234,567,890" */
 
   /* " 234,567,890" */
-  sprintf (p, " %-11s", size_grouped);
+  sprintf (p, " %s", size_grouped);
   move_to_end (p);
   move_to_end (p);
+  /* Pad with spaces to 11 chars for the size_grouped field;
+   * couldn't use the field width specifier in sprintf, because
+   * it counts in bytes, not characters. */
+  for (size_grouped_pad = 11 - size_grouped_len;
+       size_grouped_pad > 0;
+       --size_grouped_pad)
+    {
+      *p++ = ' ';
+    }
 
 
-  /* " 12.52K/s" */
+  /* " 12.52Kb/s or 12.52KB/s" */
   if (hist->total_time > 0 && hist->total_bytes)
     {
   if (hist->total_time > 0 && hist->total_bytes)
     {
-      static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
+      static const char *short_units[] = { "B/s", "KB/s", "MB/s", "GB/s" };
+      static const char *short_units_bits[] = { "b/s", "Kb/s", "Mb/s", "Gb/s" };
       int units = 0;
       /* Calculate the download speed using the history ring and
       int units = 0;
       /* Calculate the download speed using the history ring and
-        recent data that hasn't made it to the ring yet.  */
+         recent data that hasn't made it to the ring yet.  */
       wgint dlquant = hist->total_bytes + bp->recent_bytes;
       double dltime = hist->total_time + (dl_total_time - bp->recent_start);
       double dlspeed = calc_rate (dlquant, dltime, &units);
       wgint dlquant = hist->total_bytes + bp->recent_bytes;
       double dltime = hist->total_time + (dl_total_time - bp->recent_start);
       double dlspeed = calc_rate (dlquant, dltime, &units);
-      sprintf (p, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
-              dlspeed, short_units[units]);
+      sprintf (p, "%4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
+               dlspeed,  !opt.report_bps ? short_units[units] : short_units_bits[units]);
       move_to_end (p);
     }
   else
       move_to_end (p);
     }
   else
-    APPEND_LITERAL (" --.-K/s");
+    APPEND_LITERAL ("--.-KB/s");
 
   if (!done)
     {
       /* "  eta ..m ..s"; wait for three seconds before displaying the ETA.
 
   if (!done)
     {
       /* "  eta ..m ..s"; wait for three seconds before displaying the ETA.
-        That's because the ETA value needs a while to become
-        reliable.  */
+         That's because the ETA value needs a while to become
+         reliable.  */
       if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3)
       if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3)
-       {
-         int eta;
-
-         /* Don't change the value of ETA more than approximately once
-            per second; doing so would cause flashing without providing
-            any value to the user. */
-         if (bp->total_length != size
-             && bp->last_eta_value != 0
-             && dl_total_time - bp->last_eta_time < ETA_REFRESH_INTERVAL)
-           eta = bp->last_eta_value;
-         else
-           {
-             /* Calculate ETA using the average download speed to predict
-                the future speed.  If you want to use a speed averaged
-                over a more recent period, replace dl_total_time with
-                hist->total_time and bp->count with hist->total_bytes.
-                I found that doing that results in a very jerky and
-                ultimately unreliable ETA.  */
-             wgint bytes_remaining = bp->total_length - size;
-             eta = (int) (dl_total_time * bytes_remaining / bp->count + 0.5);
-             bp->last_eta_value = eta;
-             bp->last_eta_time = dl_total_time;
-           }
-
-         /* Translation note: "ETA" is English-centric, but this must
-            be short, ideally 3 chars.  Abbreviate if necessary.  */
-         sprintf (p, _("  eta %s"), eta_to_human_short (eta, false));
-         move_to_end (p);
-       }
+        {
+          int eta;
+
+          /* Don't change the value of ETA more than approximately once
+             per second; doing so would cause flashing without providing
+             any value to the user. */
+          if (bp->total_length != size
+              && bp->last_eta_value != 0
+              && dl_total_time - bp->last_eta_time < ETA_REFRESH_INTERVAL)
+            eta = bp->last_eta_value;
+          else
+            {
+              /* Calculate ETA using the average download speed to predict
+                 the future speed.  If you want to use a speed averaged
+                 over a more recent period, replace dl_total_time with
+                 hist->total_time and bp->count with hist->total_bytes.
+                 I found that doing that results in a very jerky and
+                 ultimately unreliable ETA.  */
+              wgint bytes_remaining = bp->total_length - size;
+              double eta_ = dl_total_time * bytes_remaining / bp->count;
+              if (eta_ >= INT_MAX - 1)
+                goto skip_eta;
+              eta = (int) (eta_ + 0.5);
+              bp->last_eta_value = eta;
+              bp->last_eta_time = dl_total_time;
+            }
+
+          sprintf (p, get_eta(&bytes_cols_diff),
+                   eta_to_human_short (eta, false));
+          move_to_end (p);
+        }
       else if (bp->total_length > 0)
       else if (bp->total_length > 0)
-       {
-         APPEND_LITERAL ("             ");
-       }
+        {
+        skip_eta:
+          APPEND_LITERAL ("             ");
+        }
     }
   else
     {
       /* When the download is done, print the elapsed time.  */
     }
   else
     {
       /* When the download is done, print the elapsed time.  */
+      int nbytes;
+      int ncols;
 
       /* Note to translators: this should not take up more room than
 
       /* Note to translators: this should not take up more room than
-        available here.  Abbreviate if necessary.  */
+         available here.  Abbreviate if necessary.  */
       strcpy (p, _("   in "));
       strcpy (p, _("   in "));
-      move_to_end (p);         /* not p+=6, think translations! */
+      nbytes = strlen (p);
+      ncols  = count_cols (p);
+      bytes_cols_diff = nbytes - ncols;
+      p += nbytes;
       if (dl_total_time >= 10)
       if (dl_total_time >= 10)
-       strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
+        strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
       else
       else
-       sprintf (p, "%ss", print_decimal (dl_total_time));
+        sprintf (p, "%ss", print_decimal (dl_total_time));
       move_to_end (p);
     }
 
       move_to_end (p);
     }
 
-  assert (p - bp->buffer <= bp->width);
-
-  while (p < bp->buffer + bp->width)
+  while (p - bp->buffer - bytes_cols_diff - size_grouped_diff < bp->width)
     *p++ = ' ';
   *p = '\0';
 }
     *p++ = ' ';
   *p = '\0';
 }
@@ -976,8 +1120,8 @@ static void
 display_image (char *buf)
 {
   bool old = log_set_save_context (false);
 display_image (char *buf)
 {
   bool old = log_set_save_context (false);
-  logputs (LOG_VERBOSE, "\r");
-  logputs (LOG_VERBOSE, buf);
+  logputs (LOG_PROGRESS, "\r");
+  logputs (LOG_PROGRESS, buf);
   log_set_save_context (old);
 }
 
   log_set_save_context (old);
 }
 
@@ -993,24 +1137,24 @@ bar_set_params (const char *params)
   if ((opt.lfilename
 #ifdef HAVE_ISATTY
        /* The progress bar doesn't make sense if the output is not a
   if ((opt.lfilename
 #ifdef HAVE_ISATTY
        /* The progress bar doesn't make sense if the output is not a
-         TTY -- when logging to file, it is better to review the
-         dots.  */
+          TTY -- when logging to file, it is better to review the
+          dots.  */
        || !isatty (fileno (stderr))
 #endif
        /* Normally we don't depend on terminal type because the
        || !isatty (fileno (stderr))
 #endif
        /* Normally we don't depend on terminal type because the
-         progress bar only uses ^M to move the cursor to the
-         beginning of line, which works even on dumb terminals.  But
-         Jamie Zawinski reports that ^M and ^H tricks don't work in
-         Emacs shell buffers, and only make a mess.  */
+          progress bar only uses ^M to move the cursor to the
+          beginning of line, which works even on dumb terminals.  But
+          Jamie Zawinski reports that ^M and ^H tricks don't work in
+          Emacs shell buffers, and only make a mess.  */
        || (term && 0 == strcmp (term, "emacs"))
        )
       && !current_impl_locked)
     {
       /* We're not printing to a TTY, so revert to the fallback
        || (term && 0 == strcmp (term, "emacs"))
        )
       && !current_impl_locked)
     {
       /* We're not printing to a TTY, so revert to the fallback
-        display.  #### We're recursively calling
-        set_progress_implementation here, which is slightly kludgy.
-        It would be nicer if we provided that function a return value
-        indicating a failure of some sort.  */
+         display.  #### We're recursively calling
+         set_progress_implementation here, which is slightly kludgy.
+         It would be nicer if we provided that function a return value
+         indicating a failure of some sort.  */
       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
       return;
     }
       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
       return;
     }
@@ -1018,7 +1162,7 @@ bar_set_params (const char *params)
 
 #ifdef SIGWINCH
 void
 
 #ifdef SIGWINCH
 void
-progress_handle_sigwinch (int sig)
+progress_handle_sigwinch (int sig _GL_UNUSED)
 {
   received_sigwinch = 1;
   signal (SIGWINCH, progress_handle_sigwinch);
 {
   received_sigwinch = 1;
   signal (SIGWINCH, progress_handle_sigwinch);
@@ -1044,7 +1188,7 @@ progress_handle_sigwinch (int sig)
 static const char *
 eta_to_human_short (int secs, bool condensed)
 {
 static const char *
 eta_to_human_short (int secs, bool condensed)
 {
-  static char buf[10];         /* 8 should be enough, but just in case */
+  static char buf[10];          /* 8 should be enough, but just in case */
   static int last = -1;
   const char *space = condensed ? "" : " ";
 
   static int last = -1;
   const char *space = condensed ? "" : " ";
 
@@ -1062,7 +1206,7 @@ eta_to_human_short (int secs, bool condensed)
   else if (secs < 48 * 3600)
     sprintf (buf, "%dh%s%dm", secs / 3600, space, (secs / 60) % 60);
   else if (secs < 100 * 86400)
   else if (secs < 48 * 3600)
     sprintf (buf, "%dh%s%dm", secs / 3600, space, (secs / 60) % 60);
   else if (secs < 100 * 86400)
-    sprintf (buf, "%dd%s%dh", secs / 86400, space, (secs / 3600) % 60);
+    sprintf (buf, "%dd%s%dh", secs / 86400, space, (secs / 3600) % 24);
   else
     /* even (2^31-1)/86400 doesn't overflow BUF. */
     sprintf (buf, "%dd", secs / 86400);
   else
     /* even (2^31-1)/86400 doesn't overflow BUF. */
     sprintf (buf, "%dd", secs / 86400);