]> sjero.net Git - wget/blobdiff - src/progress.c
[svn] Only set a flag in the SIGWINCH handler.
[wget] / src / progress.c
index 0e6267965047b0809618a53c3848050cbc65e9cc..8ae09c32689df0492222116eee374749080aebab 100644 (file)
@@ -100,7 +100,7 @@ valid_progress_implementation_p (const char *name)
   char *colon = strchr (name, ':');
   int namelen = colon ? colon - name : strlen (name);
 
-  for (i = 0; i < ARRAY_SIZE (implementations); i++, pi++)
+  for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
       return 1;
   return 0;
@@ -121,7 +121,7 @@ set_progress_implementation (const char *name)
   colon = strchr (name, ':');
   namelen = colon ? colon - name : strlen (name);
 
-  for (i = 0; i < ARRAY_SIZE (implementations); i++, pi++)
+  for (i = 0; i < countof (implementations); i++, pi++)
     if (!strncmp (pi->name, name, namelen))
       {
        current_impl = pi;
@@ -206,10 +206,7 @@ struct dot_progress {
 static void *
 dot_create (long initial, long total)
 {
-  struct dot_progress *dp = xmalloc (sizeof (struct dot_progress));
-
-  memset (dp, 0, sizeof (*dp));
-
+  struct dot_progress *dp = xnew0 (struct dot_progress);
   dp->initial_length = initial;
   dp->total_length   = total;
 
@@ -411,16 +408,22 @@ dot_set_params (const char *params)
    create_image will overflow the buffer.  */
 #define MINIMUM_SCREEN_WIDTH 45
 
-static int screen_width = DEFAULT_SCREEN_WIDTH;
+/* The last known screen width.  This can be updated by the code that
+   detects that SIGWINCH was received (but it's never updated from the
+   signal handler).  */
+static int screen_width;
+
+/* A flag that, when set, means SIGWINCH was received.  */
+static volatile sig_atomic_t received_sigwinch;
 
 /* Size of the download speed history ring. */
-#define DLSPEED_HISTORY_SIZE 30
+#define DLSPEED_HISTORY_SIZE 20
 
 /* The minimum time length of a history sample.  By default, each
-   sample is at least 100ms long, which means that, over the course of
-   30 samples, "current" download speed spans at least 3s into the
+   sample is at least 150ms long, which means that, over the course of
+   20 samples, "current" download speed spans at least 3s into the
    past.  */
-#define DLSPEED_SAMPLE_MIN 100
+#define DLSPEED_SAMPLE_MIN 150
 
 struct bar_progress {
   long initial_length;         /* how many bytes have been downloaded
@@ -477,9 +480,7 @@ static void display_image PARAMS ((char *));
 static void *
 bar_create (long initial, long total)
 {
-  struct bar_progress *bp = xmalloc (sizeof (struct bar_progress));
-
-  memset (bp, 0, sizeof (*bp));
+  struct bar_progress *bp = xnew0 (struct bar_progress);
 
   /* In theory, our callers should take care of this pathological
      case, but it can sometimes happen. */
@@ -489,6 +490,18 @@ bar_create (long initial, long total)
   bp->initial_length = initial;
   bp->total_length   = total;
 
+  /* Initialize screen_width if this hasn't been done or if it might
+     have changed, as indicated by receiving SIGWINCH.  */
+  if (!screen_width || received_sigwinch)
+    {
+      screen_width = determine_screen_width ();
+      if (!screen_width)
+       screen_width = DEFAULT_SCREEN_WIDTH;
+      else if (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. */
@@ -522,11 +535,23 @@ bar_update (void *progress, long howmuch, double dltime)
 
   update_speed_ring (bp, howmuch, dltime);
 
-  if (screen_width - 1 != bp->width)
+  /* If SIGWINCH (the window size change signal) been received,
+     determine the new screen size and update the screen.  */
+  if (received_sigwinch)
     {
-      bp->width = screen_width - 1;
-      bp->buffer = xrealloc (bp->buffer, bp->width + 1);
-      force_screen_update = 1;
+      int old_width = screen_width;
+      screen_width = determine_screen_width ();
+      if (!screen_width)
+       screen_width = DEFAULT_SCREEN_WIDTH;
+      else if (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 = 1;
+       }
+      received_sigwinch = 0;
     }
 
   if (dltime - bp->last_screen_update < 200 && !force_screen_update)
@@ -561,19 +586,19 @@ bar_finish (void *progress, double dltime)
    speed, over the course of no less than 3s.  (Shorter intervals
    produce very erratic results.)
 
-   To do so, it samples the speed in 0.1s intervals and stores the
+   To do so, it samples the speed in 150ms intervals and stores the
    recorded samples in a FIFO history ring.  The ring stores no more
-   than 30 intervals, hence the history covers the period of at least
-   three seconds and at most 30 reads into the past.  This method
-   should produce good results for both very fast and very slow
-   downloads.
+   than 20 intervals, hence the history covers the period of at least
+   three seconds and at most 20 reads into the past.  This method
+   should produce reasonable results for downloads ranging from very
+   slow to very fast.
 
    The idea is that for fast downloads, we get the speed over exactly
    the last three seconds.  For slow downloads (where a network read
-   takes more than 0.1s to complete), we get the speed over a larger
+   takes more than 150ms to complete), we get the speed over a larger
    time period, as large as it takes to complete thirty reads.  This
    is good because slow downloads tend to fluctuate more and a
-   3-second average would be very erratic.  */
+   3-second average would be too erratic.  */
 
 static void
 update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
@@ -688,29 +713,38 @@ create_image (struct bar_progress *bp, double dl_total_time)
   else
     APPEND_LITERAL ("    ");
 
-  /* The progress bar: "[====>      ]" */
+  /* The progress bar: "[====>      ]" or "[++==>      ]". */
   if (progress_size && bp->total_length > 0)
     {
-      double fraction = (double)size / bp->total_length;
-      int dlsz = (int)(fraction * progress_size);
+      /* Size of the initial portion. */
+      int insz = (double)bp->initial_length / bp->total_length * progress_size;
+
+      /* Size of the downloaded portion. */
+      int dlsz = (double)size / bp->total_length * progress_size;
+
       char *begin;
+      int i;
 
       assert (dlsz <= progress_size);
+      assert (insz <= dlsz);
 
       *p++ = '[';
       begin = p;
 
+      /* Print the initial portion of the download with '+' chars, the
+        rest with '=' and one '>'.  */
+      for (i = 0; i < insz; i++)
+       *p++ = '+';
+      dlsz -= insz;
       if (dlsz > 0)
        {
-         /* Draw dlsz-1 '=' chars and one arrow char.  */
-         while (dlsz-- > 1)
+         for (i = 0; i < dlsz - 1; i++)
            *p++ = '=';
          *p++ = '>';
        }
 
       while (p - begin < progress_size)
        *p++ = ' ';
-
       *p++ = ']';
     }
   else if (progress_size)
@@ -749,16 +783,20 @@ create_image (struct bar_progress *bp, double dl_total_time)
     {
       static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
       int units = 0;
-      long bytes = hist->total_bytes + bp->recent_bytes;
-      double tm = hist->total_time + dl_total_time - bp->recent_start;
-      double dlrate = calc_rate (bytes, tm, &units);
-      sprintf (p, " %7.2f%s", dlrate, short_units[units]);
+      /* Calculate the download speed using the history ring and
+        recent data that hasn't made it to the ring yet.  */
+      long 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, " %7.2f%s", dlspeed, short_units[units]);
       p += strlen (p);
     }
   else
     APPEND_LITERAL ("   --.--K/s");
 
-  /* " ETA xx:xx:xx" */
+  /* " ETA xx:xx:xx"; 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 && dl_total_time > 3000)
     {
       long eta;
@@ -767,8 +805,9 @@ create_image (struct bar_progress *bp, double dl_total_time)
       /* 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 (dl_total_time - bp->last_eta_time < 900
-         && bp->last_eta_value != 0)
+      if (bp->total_length != size
+         && bp->last_eta_value != 0
+         && dl_total_time - bp->last_eta_time < 900)
        eta = bp->last_eta_value;
       else
        {
@@ -835,7 +874,6 @@ display_image (char *buf)
 static void
 bar_set_params (const char *params)
 {
-  int sw;
   char *term = getenv ("TERM");
 
   if (params
@@ -868,19 +906,13 @@ bar_set_params (const char *params)
       set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);
       return;
     }
-
-  sw = determine_screen_width ();
-  if (sw && sw >= MINIMUM_SCREEN_WIDTH)
-    screen_width = sw;
 }
 
 #ifdef SIGWINCH
 RETSIGTYPE
 progress_handle_sigwinch (int sig)
 {
-  int sw = determine_screen_width ();
-  if (sw && sw >= MINIMUM_SCREEN_WIDTH)
-    screen_width = sw;
+  received_sigwinch = 1;
   signal (SIGWINCH, progress_handle_sigwinch);
 }
 #endif