]> sjero.net Git - wget/blobdiff - src/progress.c
[svn] Document print_percentage.
[wget] / src / progress.c
index 524aaf4e3bcc1410f7ca3831cb4bdbed7d1e66ce..6f24cd290e027094504b7479910e109141256f33 100644 (file)
@@ -76,7 +76,7 @@ static int current_impl_locked;
 
 #define DEFAULT_PROGRESS_IMPLEMENTATION "bar"
 
-/* Fallnback progress implementation should be something that works
+/* Fallback progress implementation should be something that works
    under all display types.  If you put something other than "dot"
    here, remember that bar_set_params tries to switch to this if we're
    not running on a TTY.  So changing this to "bar" could cause
@@ -108,7 +108,7 @@ set_progress_implementation (const char *name)
 {
   int i, namelen;
   struct progress_implementation *pi = implementations;
-  char *colon;
+  const char *colon;
 
   if (!name)
     name = DEFAULT_PROGRESS_IMPLEMENTATION;
@@ -258,15 +258,21 @@ dot_create (wgint initial, wgint total)
 static void
 print_percentage (wgint bytes, wgint expected)
 {
-  int percentage = (int)(100.0 * bytes / expected);
+  /* This intentionally rounds to the floor value because it is a
+     measure of how much data *has* been retrieved.  Therefore 12.8%
+     rounds to 12% because the 13% mark has not yet been reached.
+     Likewise, 100% is only shown when all data has been retrieved,
+     not before.  */
+
+  int percentage = 100.0 * bytes / expected;
   logprintf (LOG_VERBOSE, "%3d%%", percentage);
 }
 
 static void
 print_download_speed (struct dot_progress *dp, wgint bytes, double dltime)
 {
-  logprintf (LOG_VERBOSE, " %s",
-            retr_rate (bytes, dltime - dp->last_timer_value, 1));
+  logprintf (LOG_VERBOSE, " %7s",
+            retr_rate (bytes, dltime - dp->last_timer_value));
   dp->last_timer_value = dltime;
 }
 
@@ -489,7 +495,7 @@ struct bar_progress {
   int last_eta_value;
 };
 
-static void create_image (struct bar_progress *, double);
+static void create_image (struct bar_progress *, double, bool);
 static void display_image (char *);
 
 static void *
@@ -524,7 +530,7 @@ bar_create (wgint initial, wgint total)
 
   logputs (LOG_VERBOSE, "\n");
 
-  create_image (bp, 0);
+  create_image (bp, 0, false);
   display_image (bp->buffer);
 
   return bp;
@@ -573,7 +579,7 @@ bar_update (void *progress, wgint howmuch, double dltime)
     /* Don't update more often than five times per second. */
     return;
 
-  create_image (bp, dltime);
+  create_image (bp, dltime, false);
   display_image (bp->buffer);
   bp->last_screen_update = dltime;
 }
@@ -588,7 +594,7 @@ bar_finish (void *progress, double dltime)
     /* See bar_update() for explanation. */
     bp->total_length = bp->initial_length + bp->count;
 
-  create_image (bp, dltime);
+  create_image (bp, dltime, true);
   display_image (bp->buffer);
 
   logputs (LOG_VERBOSE, "\n\n");
@@ -700,19 +706,24 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
 #endif
 }
 
-static const char *eta_to_human (int);
+static const char *eta_to_human_short (int);
 
 #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
+   terminating \0).  This is faster than s+=strlen(s), but some people
+   are confused when they see strchr (s, '\0') in the code.  */
+#define move_to_end(s) s = strchr (s, '\0');
+
 #ifndef MAX
 # define MAX(a, b) ((a) >= (b) ? (a) : (b))
 #endif
 
 static void
-create_image (struct bar_progress *bp, double dl_total_time)
+create_image (struct bar_progress *bp, double dl_total_time, bool done)
 {
   char *p = bp->buffer;
   wgint size = bp->initial_length + bp->count;
@@ -749,7 +760,7 @@ create_image (struct bar_progress *bp, double dl_total_time)
   /* "xx% " */
   if (bp->total_length > 0)
     {
-      int percentage = (int)(100.0 * size / bp->total_length);
+      int percentage = 100.0 * size / bp->total_length;
       assert (percentage <= 100);
 
       if (percentage < 100)
@@ -824,7 +835,7 @@ create_image (struct bar_progress *bp, double dl_total_time)
 
   /* " 234,567,890" */
   sprintf (p, " %-11s", size_grouped);
-  p += strlen (p);
+  move_to_end (p);
 
   /* " 1012.45K/s" */
   if (hist->total_time && hist->total_bytes)
@@ -837,46 +848,71 @@ create_image (struct bar_progress *bp, double dl_total_time)
       double dltime = hist->total_time + (dl_total_time - bp->recent_start);
       double dlspeed = calc_rate (dlquant, dltime, &units);
       sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
-      p += strlen (p);
+      move_to_end (p);
     }
   else
     APPEND_LITERAL ("   --.--K/s");
 
-  /* "  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)
+  if (!done)
     {
-      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 < 900)
-       eta = bp->last_eta_value;
-      else
+      /* "  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)
        {
-         /* 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.  */
-         double time_sofar = (double) dl_total_time / 1000;
-         wgint bytes_remaining = bp->total_length - size;
-         eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5);
-         bp->last_eta_value = eta;
-         bp->last_eta_time = dl_total_time;
+         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 < 900)
+           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.  */
+             double time_sofar = (double) dl_total_time / 1000;
+             wgint bytes_remaining = bp->total_length - size;
+             eta = (int) (time_sofar * 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));
+         move_to_end (p);
+       }
+      else if (bp->total_length > 0)
+       {
+         APPEND_LITERAL ("             ");
        }
-
-      sprintf (p, "  eta %s", eta_to_human (eta));
-      p += strlen (p);
     }
-  else if (bp->total_length > 0)
+  else
     {
-      APPEND_LITERAL ("             ");
+      /* When the download is done, print the elapsed time.  */
+      double secs = dl_total_time / 1000;
+      /* 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! */
+      if (secs >= 10)
+       strcpy (p, eta_to_human_short ((int) (secs + 0.5)));
+      else
+       /* For very quick downloads show more exact timing information. */
+       sprintf (p, "%.*fs",
+                secs < 0.001 ? 0 : /* 0s instead of 0.000s */
+                secs < 0.01 ? 3 :  /* 0.00x */
+                secs < 0.1 ? 2 :   /* 0.0x */
+                1,                 /* 0.x, 1.x, ..., 9.x */
+                secs);
+      move_to_end (p);
     }
 
   assert (p - bp->buffer <= bp->width);
@@ -942,18 +978,30 @@ progress_handle_sigwinch (int sig)
 }
 #endif
 
-/* Provide a human-readable rendition of the ETA.  It never occupies
-   more than 7 characters of screen space.  */
+/* Provide a short human-readable rendition of the ETA.  This is like
+   secs_to_human_time in main.c, except the output doesn't include
+   fractions (which would look silly in by nature imprecise ETA) and
+   takes less room.  If the time is measured in hours, hours and
+   minutes (but not seconds) are shown; if measured in days, then days
+   and hours are shown.  This ensures brevity while still displaying
+   as much as possible.
+
+   If SEP is false, the separator between minutes and seconds (and
+   hours and minutes, etc.) is not included, shortening the display by
+   one additional character.  This is used for dot progress.
+
+   The display never occupies more than 7 characters of screen
+   space.  */
 
 static const char *
-eta_to_human (int secs)
+eta_to_human_short (int secs)
 {
-  static char buf[10];         /* 8 is enough, but just in case */
+  static char buf[10];         /* 8 should be 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).  */
+  /* Trivial optimization.  create_image can call us every 200 msecs
+     (see bar_update) for fast downloads, but ETA will only change
+     once per 900 msecs.  */
   if (secs == last)
     return buf;
   last = secs;
@@ -967,7 +1015,7 @@ eta_to_human (int secs)
   else if (secs < 100 * 86400)
     sprintf (buf, "%dd %dh", secs / 86400, (secs / 3600) % 60);
   else
-    /* (2^31-1)/86400 doesn't overflow BUF. */
+    /* even (2^31-1)/86400 doesn't overflow BUF. */
     sprintf (buf, "%dd", secs / 86400);
 
   return buf;