]> sjero.net Git - wget/blobdiff - src/progress.c
[svn] New ETA display.
[wget] / src / progress.c
index 04c7fc5cad831cf59ea96bf44ce6ab21395cdd82..137794d6cb4c3047dc6933f210390b5f517cd154 100644 (file)
@@ -36,9 +36,7 @@ so, delete this exception statement from your version.  */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-#ifdef HAVE_SIGNAL_H
-# include <signal.h>
-#endif
+#include <signal.h>
 
 #include "wget.h"
 #include "progress.h"
@@ -47,7 +45,7 @@ so, delete this exception statement from your version.  */
 
 struct progress_implementation {
   const char *name;
-  int interactive;
+  bool interactive;
   void *(*create) (wgint, wgint);
   void (*update) (void *, wgint, double);
   void (*finish) (void *, double);
@@ -86,10 +84,10 @@ static int current_impl_locked;
 
 #define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
 
-/* Return non-zero if NAME names a valid progress bar implementation.
-   The characters after the first : will be ignored.  */
+/* Return true if NAME names a valid progress bar implementation.  The
+   characters after the first : will be ignored.  */
 
-int
+bool
 valid_progress_implementation_p (const char *name)
 {
   int i;
@@ -99,8 +97,8 @@ valid_progress_implementation_p (const char *name)
 
   for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
-      return 1;
-  return 0;
+      return true;
+  return false;
 }
 
 /* Set the progress implementation to NAME.  */
@@ -165,12 +163,12 @@ progress_create (wgint initial, wgint total)
   return current_impl->create (initial, total);
 }
 
-/* Return non-zero if the progress gauge is "interactive", i.e. if it
-   can profit from being called regularly even in absence of data.
-   The progress bar is interactive because it regularly updates the
-   ETA and current update.  */
+/* Return true if the progress gauge is "interactive", i.e. if it can
+   profit from being called regularly even in absence of data.  The
+   progress bar is interactive because it regularly updates the ETA
+   and current update.  */
 
-int
+bool
 progress_interactive_p (void *progress)
 {
   return current_impl->interactive;
@@ -281,7 +279,7 @@ dot_update (void *progress, wgint howmuch, double dltime)
   int dot_bytes = opt.dot_bytes;
   wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
 
-  log_set_flush (0);
+  log_set_flush (false);
 
   dp->accumulated += howmuch;
   for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
@@ -309,7 +307,7 @@ dot_update (void *progress, wgint howmuch, double dltime)
        }
     }
 
-  log_set_flush (1);
+  log_set_flush (true);
 }
 
 /* Dot-progress backend for progress_finish. */
@@ -322,7 +320,7 @@ dot_finish (void *progress, double dltime)
   wgint row_bytes = opt.dot_bytes * opt.dots_in_line;
   int i;
 
-  log_set_flush (0);
+  log_set_flush (false);
 
   if (dp->dots == 0)
     logprintf (LOG_VERBOSE, "\n%5ldK", (long) (dp->rows * row_bytes / 1024));
@@ -348,7 +346,7 @@ dot_finish (void *progress, double dltime)
   }
 
   logputs (LOG_VERBOSE, "\n\n");
-  log_set_flush (0);
+  log_set_flush (false);
 
   xfree (dp);
 }
@@ -479,7 +477,7 @@ struct bar_progress {
                                   position. */
   wgint recent_bytes;          /* bytes downloaded so far. */
 
-  int stalled;                 /* set when no data arrives for longer
+  bool stalled;                        /* set when no data arrives for longer
                                   than STALL_START_TIME, then reset
                                   when new data arrives. */
 
@@ -488,7 +486,7 @@ struct bar_progress {
   double last_eta_time;                /* time of the last update to download
                                   speed and ETA, measured since the
                                   beginning of download. */
-  wgint last_eta_value;
+  int last_eta_value;
 };
 
 static void create_image (struct bar_progress *, double);
@@ -538,7 +536,7 @@ static void
 bar_update (void *progress, wgint howmuch, double dltime)
 {
   struct bar_progress *bp = progress;
-  int force_screen_update = 0;
+  bool force_screen_update = false;
 
   bp->count += howmuch;
   if (bp->total_length > 0
@@ -566,7 +564,7 @@ bar_update (void *progress, wgint howmuch, double dltime)
        {
          bp->width = screen_width - 1;
          bp->buffer = xrealloc (bp->buffer, bp->width + 1);
-         force_screen_update = 1;
+         force_screen_update = true;
        }
       received_sigwinch = 0;
     }
@@ -643,7 +641,7 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
          /* 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 = 1;
+         bp->stalled = true;
          xzero (*hist);
          bp->recent_bytes = 0;
        }
@@ -655,7 +653,7 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
   /* If the stall status was acquired, reset it. */
   if (bp->stalled)
     {
-      bp->stalled = 0;
+      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.
@@ -702,6 +700,8 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #endif
 }
 
+static const char *eta_to_human (int);
+
 #define APPEND_LITERAL(s) do {                 \
   memcpy (p, s, sizeof (s) - 1);               \
   p += sizeof (s) - 1;                         \
@@ -723,7 +723,7 @@ create_image (struct bar_progress *bp, double dl_total_time)
   struct bar_progress_hist *hist = &bp->hist;
 
   /* The progress bar should look like this:
-     xx% [=======>             ] nn,nnn 12.34K/s ETA 00:00
+     xx% [=======>             ] nn,nnn 12.34K/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
@@ -736,7 +736,7 @@ create_image (struct bar_progress *bp, double dl_total_time)
      "[]"              - progress bar decorations - 2 chars
      " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more
      " 1012.56K/s"     - dl rate                  - 11 chars
-     " ETA xx:xx:xx"   - ETA                      - 13 chars
+     "  eta 36m 51s"   - ETA                      - 13 chars
 
      "=====>..."       - progress bar             - the rest
   */
@@ -750,7 +750,6 @@ create_image (struct bar_progress *bp, double dl_total_time)
   if (bp->total_length > 0)
     {
       int percentage = (int)(100.0 * size / bp->total_length);
-
       assert (percentage <= 100);
 
       if (percentage < 100)
@@ -843,13 +842,12 @@ create_image (struct bar_progress *bp, double dl_total_time)
   else
     APPEND_LITERAL ("   --.--K/s");
 
-  /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.
+  /* "  ETA ..m ..s"; wait for three seconds before displaying the ETA.
      That's because the ETA value needs a while to become
      reliable.  */
   if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
     {
-      wgint eta;
-      int eta_hrs, eta_min, eta_sec;
+      int eta;
 
       /* Don't change the value of ETA more than approximately once
         per second; doing so would cause flashing without providing
@@ -866,38 +864,18 @@ create_image (struct bar_progress *bp, double dl_total_time)
             hist->total_time and bp->count with hist->total_bytes.
             I found that doing that results in a very jerky and
             ultimately unreliable ETA.  */
-         double time_sofar = (double)dl_total_time / 1000;
+         double time_sofar = (double) dl_total_time / 1000;
          wgint bytes_remaining = bp->total_length - size;
-         eta = (wgint) (time_sofar * bytes_remaining / bp->count);
+         eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5);
          bp->last_eta_value = eta;
          bp->last_eta_time = dl_total_time;
        }
 
-      eta_hrs = eta / 3600, eta %= 3600;
-      eta_min = eta / 60,   eta %= 60;
-      eta_sec = eta;
-
-      if (eta_hrs > 99)
-       goto no_eta;
-
-      if (eta_hrs == 0)
-       {
-         /* Hours not printed: pad with three spaces. */
-         APPEND_LITERAL ("   ");
-         sprintf (p, " ETA %02d:%02d", eta_min, eta_sec);
-       }
-      else
-       {
-         if (eta_hrs < 10)
-           /* Hours printed with one digit: pad with one space. */
-           *p++ = ' ';
-         sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec);
-       }
+      sprintf (p, "  eta %s", eta_to_human (eta));
       p += strlen (p);
     }
   else if (bp->total_length > 0)
     {
-    no_eta:
       APPEND_LITERAL ("             ");
     }
 
@@ -914,7 +892,7 @@ create_image (struct bar_progress *bp, double dl_total_time)
 static void
 display_image (char *buf)
 {
-  int old = log_set_save_context (0);
+  bool old = log_set_save_context (false);
   logputs (LOG_VERBOSE, "\r");
   logputs (LOG_VERBOSE, buf);
   log_set_save_context (old);
@@ -956,10 +934,41 @@ bar_set_params (const char *params)
 }
 
 #ifdef SIGWINCH
-RETSIGTYPE
+void
 progress_handle_sigwinch (int sig)
 {
   received_sigwinch = 1;
   signal (SIGWINCH, progress_handle_sigwinch);
 }
 #endif
+
+/* Provide a human-readable rendition of the ETA.  It never occupies
+   more than 7 characters of screen space.  */
+
+static const char *
+eta_to_human (int secs)
+{
+  static char buf[10];         /* 8 is enough, but just in case */
+  static int last = -1;
+
+  /* Trivial optimization.  This function can be called every 200
+     msecs (see bar_update) for fast downloads, but ETA will only
+     change once per 900 msecs (see create_image).  */
+  if (secs == last)
+    return buf;
+  last = secs;
+
+  if (secs < 100)
+    sprintf (buf, "%ds", secs);
+  else if (secs < 100 * 60)
+    sprintf (buf, "%dm %ds", secs / 60, secs % 60);
+  else if (secs < 100 * 3600)
+    sprintf (buf, "%dh %dm", secs / 3600, (secs / 60) % 60);
+  else if (secs < 100 * 86400)
+    sprintf (buf, "%dd %dh", secs / 86400, (secs / 3600) % 60);
+  else
+    /* (2^31-1)/86400 doesn't overflow BUF. */
+    sprintf (buf, "%dd", secs / 86400);
+
+  return buf;
+}