]> sjero.net Git - wget/blobdiff - src/progress.c
Fix compiler warnings
[wget] / src / progress.c
index f8a581af2f82d3da8d31c5ccacea4f91a00ac76f..6cb22d70ecb53304c6b2c71b9755d03ffa14f0ff 100644 (file)
@@ -1,11 +1,12 @@
 /* Download progress.
-   Copyright (C) 2001-2006 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
-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,
@@ -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
-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>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #include <signal.h>
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
 
-#include "wget.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;
-  void *(*create) (wgint, wgint);
+  void *(*create) (const char *, wgint, wgint);
   void (*update) (void *, wgint, double);
+  void (*draw) (void *);
   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_draw (void *);
 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_draw (void *);
 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;
@@ -90,10 +94,10 @@ static int current_impl_locked;
 bool
 valid_progress_implementation_p (const char *name)
 {
-  int i;
+  size_t i;
   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))
@@ -106,7 +110,7 @@ valid_progress_implementation_p (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;
 
@@ -114,23 +118,23 @@ set_progress_implementation (const char *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))
       {
-       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 ();
 }
@@ -150,17 +154,17 @@ progress_schedule_redirect (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)
-       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
+        set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
       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
@@ -169,7 +173,7 @@ progress_create (wgint initial, wgint total)
    and current update.  */
 
 bool
-progress_interactive_p (void *progress)
+progress_interactive_p (void *progress _GL_UNUSED)
 {
   return current_impl->interactive;
 }
@@ -181,6 +185,7 @@ void
 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
@@ -195,16 +200,17 @@ progress_finish (void *progress, double dltime)
 /* 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;
 };
@@ -212,7 +218,7 @@ struct dot_progress {
 /* 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;
@@ -227,29 +233,29 @@ dot_create (wgint initial, wgint total)
       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)
-       {
-         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;
@@ -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*
-        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;
-      logprintf (LOG_VERBOSE, "%3d%%", percentage);
+      logprintf (LOG_PROGRESS, "%3d%%", percentage);
     }
 
   {
@@ -305,35 +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);
-    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
-        Belperchinov-Shabanski's "wget-new-percentage" patch.  */
+         Belperchinov-Shabanski's "wget-new-percentage" patch.  */
       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;
-         double eta = dltime * bytes_remaining / bytes_sofar;
-         if (eta < INT_MAX - 1)
-           logprintf (LOG_VERBOSE, " %s",
-                      eta_to_human_short ((int) (eta + 0.5), 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)
-       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
-       logprintf (LOG_VERBOSE, "=%ss", print_decimal (dltime));
+        logprintf (LOG_PROGRESS, "=%ss", print_decimal (dltime));
     }
 }
 
@@ -341,6 +347,14 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
 
 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;
@@ -348,25 +362,24 @@ dot_update (void *progress, wgint howmuch, double dltime)
 
   log_set_flush (false);
 
-  dp->accumulated += howmuch;
   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)
-       logputs (LOG_VERBOSE, " ");
-      logputs (LOG_VERBOSE, ".");
+        logputs (LOG_PROGRESS, " ");
+      logputs (LOG_PROGRESS, ".");
 
       ++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);
@@ -384,13 +397,13 @@ dot_finish (void *progress, double dltime)
   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)
-       logputs (LOG_VERBOSE, " ");
-      logputs (LOG_VERBOSE, " ");
+        logputs (LOG_PROGRESS, " ");
+      logputs (LOG_PROGRESS, " ");
     }
 
   print_row_stats (dp, dltime, true);
@@ -418,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
-        line.  */
+         line.  */
       opt.dot_bytes = 1024;
       opt.dot_spacing = 10;
       opt.dots_in_line = 50;
@@ -426,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
-        (384K) in a line.  */
+         (384K) in a line.  */
       opt.dot_bytes = 8192;
       opt.dot_spacing = 16;
       opt.dots_in_line = 48;
@@ -434,7 +447,7 @@ dot_set_params (const char *params)
   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;
@@ -442,16 +455,16 @@ dot_set_params (const char *params)
   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,
-            _("Invalid dot style specification `%s'; leaving unchanged.\n"),
-            params);
+             _("Invalid dot style specification %s; leaving unchanged.\n"),
+             quote (params));
 }
 \f
 /* "Thermometer" (bar) progress. */
@@ -494,27 +507,29 @@ static volatile sig_atomic_t received_sigwinch;
 #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
@@ -530,19 +545,19 @@ struct bar_progress {
     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. */
-  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;
 };
 
@@ -550,7 +565,7 @@ static void create_image (struct bar_progress *, double, bool);
 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);
 
@@ -561,6 +576,7 @@ bar_create (wgint initial, wgint 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.  */
@@ -568,16 +584,17 @@ bar_create (wgint initial, wgint total)
     {
       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)
-       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;
-  /* + 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");
 
@@ -593,8 +610,8 @@ static void
 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)
@@ -606,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);
+}
+
+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.  */
@@ -614,25 +638,25 @@ bar_update (void *progress, wgint howmuch, double dltime)
       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)
-       screen_width = MINIMUM_SCREEN_WIDTH;
+        screen_width = MINIMUM_SCREEN_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;
     }
 
-  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;
 
-  create_image (bp, dltime, false);
+  create_image (bp, bp->dltime, false);
   display_image (bp->buffer);
-  bp->last_screen_update = dltime;
+  bp->last_screen_update = bp->dltime;
 }
 
 static void
@@ -648,7 +672,8 @@ bar_finish (void *progress, double dltime)
   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);
@@ -690,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,
-        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 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;
     }
 
@@ -711,11 +736,11 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
   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;
     }
 
@@ -748,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++)
       {
-       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
@@ -763,9 +788,76 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #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
@@ -776,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 MIN
+# define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#endif
 
 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);
-  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;
+  int orig_filename_len = strlen (bp->f_download);
 
   /* 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
@@ -798,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.
 
+     "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
-     " 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);
-  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 (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)
     {
@@ -819,9 +945,9 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       assert (percentage <= 100);
 
       if (percentage < 100)
-       sprintf (p, "%2d%% ", percentage);
+        sprintf (p, "%2d%% ", percentage);
       else
-       strcpy (p, "100%");
+        strcpy (p, "100%");
       p += 4;
     }
   else
@@ -846,131 +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
-        rest with '=' and one '>'.  */
+         rest with '=' and one '>'.  */
       for (i = 0; i < insz; i++)
-       *p++ = '+';
+        *p++ = '+';
       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)
-       *p++ = ' ';
+        *p++ = ' ';
       *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)
-       pos = ind + 1;
+        pos = ind + 1;
       else
-       pos = progress_size - (ind - progress_size + 5);
+        pos = progress_size - (ind - progress_size + 5);
 
       *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++ = ']';
 
-      ++bp->tick;
     }
+ ++bp->tick;
 
   /* " 234,567,890" */
-  sprintf (p, " %-11s", size_grouped);
+  sprintf (p, " %s", size_grouped);
   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)
     {
-      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
-        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);
-      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
-    APPEND_LITERAL (" --.-K/s");
+    APPEND_LITERAL ("--.-KB/s");
 
   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)
-       {
-         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;
-           }
-
-         /* 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)
-       {
-       skip_eta:
-         APPEND_LITERAL ("             ");
-       }
+        {
+        skip_eta:
+          APPEND_LITERAL ("             ");
+        }
     }
   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
-        available here.  Abbreviate if necessary.  */
+         available here.  Abbreviate if necessary.  */
       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)
-       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
-       sprintf (p, "%ss", print_decimal (dl_total_time));
+        sprintf (p, "%ss", print_decimal (dl_total_time));
       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';
 }
@@ -982,8 +1120,8 @@ static void
 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);
 }
 
@@ -999,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
-         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
-         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
-        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;
     }
@@ -1024,7 +1162,7 @@ bar_set_params (const char *params)
 
 #ifdef SIGWINCH
 void
-progress_handle_sigwinch (int sig)
+progress_handle_sigwinch (int sig _GL_UNUSED)
 {
   received_sigwinch = 1;
   signal (SIGWINCH, progress_handle_sigwinch);
@@ -1050,7 +1188,7 @@ progress_handle_sigwinch (int sig)
 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 ? "" : " ";
 
@@ -1068,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)
-    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);