]> sjero.net Git - wget/blobdiff - src/progress.c
progress: Split update into update and draw
[wget] / src / progress.c
index d77f99b6951d12b7c63360704c86a21e2ac2f413..47d13e6ae53df5cf3f8af81a966acc17f4fda191 100644 (file)
@@ -1,6 +1,6 @@
 /* Download progress.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008 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.
 
@@ -34,9 +34,7 @@ as that of the covered work.  */
 #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>
@@ -51,6 +49,7 @@ struct progress_implementation {
   bool interactive;
   void *(*create) (wgint, wgint);
   void (*update) (void *, wgint, double);
+  void (*draw) (void *);
   void (*finish) (void *, double);
   void (*set_params) (const char *);
 };
@@ -60,16 +59,18 @@ struct progress_implementation {
 static void *dot_create (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_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;
@@ -93,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))
@@ -109,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;
 
@@ -117,7 +118,7 @@ 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))
@@ -184,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
@@ -206,6 +208,7 @@ struct dot_progress {
   int accumulated;              /* number of bytes accumulated after
                                    the last printed dot */
 
+  double dltime;                /* download time so far */
   int rows;                     /* number of rows printed so far */
   int dots;                     /* number of dots printed in this row */
 
@@ -344,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;
@@ -351,7 +362,6 @@ 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)
@@ -368,7 +378,7 @@ dot_update (void *progress, wgint howmuch, double dltime)
           ++dp->rows;
           dp->dots = 0;
 
-          print_row_stats (dp, dltime, false);
+          print_row_stats (dp, dp->dltime, false);
         }
     }
 
@@ -453,8 +463,8 @@ dot_set_params (const char *params)
     }
   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. */
@@ -507,6 +517,7 @@ struct bar_progress {
                                    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
@@ -597,8 +608,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)
@@ -610,6 +621,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.  */
@@ -630,13 +648,13 @@ bar_update (void *progress, wgint howmuch, double dltime)
       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
@@ -715,7 +733,7 @@ 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
+      /* "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
@@ -767,43 +785,54 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #endif
 }
 
-#if ! HAVE_WCWIDTH
-#define wcwidth(wc) (1)
-#endif
-
-int
+#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;
-      cols += wcwidth(wc);
+      wccols = wcwidth(wc);
+      cols += (wccols == -1? 1 : wccols);
     }
   return cols;
 }
+#else
+# define count_cols(mbs) ((int)(strlen(mbs)))
+#endif
 
-/* Translation note: "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;
-
-const char *
-get_eta (void)
+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
@@ -817,6 +846,9 @@ get_eta (void)
       bytes_cols_diff = nbytes - ncols;
     }
 
+  if (bcd != NULL)
+    *bcd = bytes_cols_diff;
+
   return eta_trans;
 }
 
@@ -849,7 +881,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
   struct bar_progress_hist *hist = &bp->hist;
 
   /* The progress bar should look like this:
-     xx% [=======>             ] nn,nnn 12.34K/s  eta 36m 51s
+     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
@@ -861,13 +893,17 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
      "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 - (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;
@@ -961,10 +997,11 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       *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.  */
@@ -972,7 +1009,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       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]);
+               dlspeed,  !opt.report_bps ? short_units[units] : short_units_bits[units]);
       move_to_end (p);
     }
   else
@@ -1011,7 +1048,8 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
               bp->last_eta_time = dl_total_time;
             }
 
-          sprintf (p, get_eta(), eta_to_human_short (eta, false));
+          sprintf (p, get_eta(&bytes_cols_diff),
+                   eta_to_human_short (eta, false));
           move_to_end (p);
         }
       else if (bp->total_length > 0)
@@ -1023,11 +1061,16 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
   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.  */
       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));
       else
@@ -1035,8 +1078,6 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       move_to_end (p);
     }
 
-  assert (p - bp->buffer - bytes_cols_diff - size_grouped_diff <= bp->width);
-
   while (p - bp->buffer - bytes_cols_diff - size_grouped_diff < bp->width)
     *p++ = ' ';
   *p = '\0';
@@ -1135,7 +1176,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);