# include <strings.h>
#endif /* HAVE_STRING_H */
#include <assert.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include "wget.h"
#include "progress.h"
struct progress_implementation {
char *name;
void *(*create) (long, long);
- void (*update) (void *, long);
- void (*finish) (void *);
+ void (*update) (void *, long, long);
+ void (*finish) (void *, long);
void (*set_params) (const char *);
};
/* Necessary forward declarations. */
static void *dot_create PARAMS ((long, long));
-static void dot_update PARAMS ((void *, long));
-static void dot_finish PARAMS ((void *));
+static void dot_update PARAMS ((void *, long, long));
+static void dot_finish PARAMS ((void *, long));
static void dot_set_params PARAMS ((const char *));
static void *bar_create PARAMS ((long, long));
-static void bar_update PARAMS ((void *, long));
-static void bar_finish PARAMS ((void *));
+static void bar_update PARAMS ((void *, long, long));
+static void bar_finish PARAMS ((void *, long));
static void bar_set_params PARAMS ((const char *));
static struct progress_implementation implementations[] = {
return current_impl->create (initial, total);
}
-/* Inform the progress gauge of newly received bytes. */
+/* Inform the progress gauge of newly received bytes. DLTIME is the
+ time in milliseconds since the beginning of the download. */
void
-progress_update (void *progress, long howmuch)
+progress_update (void *progress, long howmuch, long dltime)
{
- current_impl->update (progress, howmuch);
+ current_impl->update (progress, howmuch, dltime);
}
/* Tell the progress gauge to clean up. Calling this will free the
PROGRESS object, the further use of which is not allowed. */
void
-progress_finish (void *progress)
+progress_finish (void *progress, long dltime)
{
- current_impl->finish (progress);
+ current_impl->finish (progress, dltime);
}
\f
/* Dot-printing. */
int rows; /* number of rows printed so far */
int dots; /* number of dots printed in this row */
-
- struct wget_timer *timer; /* timer used to measure per-row
- download rates. */
long last_timer_value;
};
dp->initial_length = initial;
dp->total_length = total;
- dp->timer = wtimer_new ();
if (dp->initial_length)
{
if (skipped)
{
- logputs (LOG_VERBOSE, "\n "); /* leave spacing untranslated */
- logprintf (LOG_VERBOSE, _("[ skipping %dK ]"),
- (int) (skipped / 1024));
+ int skipped_k = (int) (skipped / 1024); /* skipped amount in K */
+ int skipped_k_len = numdigit (skipped_k);
+ if (skipped_k_len < 5)
+ skipped_k_len = 5;
+
+ /* 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 %dK ]"),
+ 2 + skipped_k_len, "", skipped_k);
}
logprintf (LOG_VERBOSE, "\n%5ldK", skipped / 1024);
}
static void
-print_download_speed (struct dot_progress *dp, long bytes)
+print_download_speed (struct dot_progress *dp, long bytes, long dltime)
{
- long timer_value = wtimer_elapsed (dp->timer);
logprintf (LOG_VERBOSE, " %s",
- rate (bytes, timer_value - dp->last_timer_value, 1));
- dp->last_timer_value = timer_value;
+ retr_rate (bytes, dltime - dp->last_timer_value, 1));
+ dp->last_timer_value = dltime;
}
/* Dot-progress backend for progress_update. */
static void
-dot_update (void *progress, long howmuch)
+dot_update (void *progress, long howmuch, long dltime)
{
struct dot_progress *dp = progress;
int dot_bytes = opt.dot_bytes;
++dp->dots;
if (dp->dots >= opt.dots_in_line)
{
+ long row_qty = row_bytes;
+ if (dp->rows == dp->initial_length / row_bytes)
+ row_qty -= dp->initial_length % row_bytes;
+
++dp->rows;
dp->dots = 0;
if (dp->total_length)
print_percentage (dp->rows * row_bytes, dp->total_length);
-
- print_download_speed (dp,
- row_bytes - (dp->initial_length % row_bytes));
+ print_download_speed (dp, row_qty, dltime);
}
}
/* Dot-progress backend for progress_finish. */
static void
-dot_finish (void *progress)
+dot_finish (void *progress, long dltime)
{
struct dot_progress *dp = progress;
int dot_bytes = opt.dot_bytes;
dp->total_length);
}
- print_download_speed (dp, dp->dots * dot_bytes
- + dp->accumulated
- - dp->initial_length % row_bytes);
- logputs (LOG_VERBOSE, "\n\n");
+ {
+ long row_qty = dp->dots * dot_bytes + dp->accumulated;
+ if (dp->rows == dp->initial_length / row_bytes)
+ row_qty -= dp->initial_length % row_bytes;
+ print_download_speed (dp, row_qty, dltime);
+ }
+ logputs (LOG_VERBOSE, "\n\n");
log_set_flush (0);
- wtimer_delete (dp->timer);
xfree (dp);
}
download finishes */
long count; /* bytes downloaded so far */
- struct wget_timer *timer; /* timer used to measure the download
- rates. */
long last_update; /* time of the last screen update. */
int width; /* screen width at the time the
progress gauge was created. */
char *buffer; /* buffer where the bar "image" is
stored. */
+
+ int tick;
};
static void create_image PARAMS ((struct bar_progress *, long));
bp->initial_length = initial;
bp->total_length = total;
- bp->timer = wtimer_new ();
bp->width = screen_width;
bp->buffer = xmalloc (bp->width + 1);
}
static void
-bar_update (void *progress, long howmuch)
+bar_update (void *progress, long howmuch, long dltime)
{
struct bar_progress *bp = progress;
int force_update = 0;
- long dltime = wtimer_elapsed (bp->timer);
bp->count += howmuch;
- if (bp->count + bp->initial_length > bp->total_length)
+ if (bp->total_length > 0
+ && bp->count + bp->initial_length > bp->total_length)
/* We could be downloading more than total_length, e.g. when the
server sends an incorrect Content-Length header. In that case,
adjust bp->total_length to the new reality, so that the code in
}
static void
-bar_finish (void *progress)
+bar_finish (void *progress, long dltime)
{
struct bar_progress *bp = progress;
- create_image (bp, wtimer_elapsed (bp->timer));
+ if (dltime == 0)
+ /* If the download was faster than the granularity of the timer,
+ fake some output so that we don't get the ugly "----.--" rate
+ at the download finish. */
+ dltime = 1;
+
+ create_image (bp, dltime);
display_image (bp->buffer);
logputs (LOG_VERBOSE, "\n\n");
xfree (bp->buffer);
- wtimer_delete (bp->timer);
xfree (bp);
}
long size = bp->initial_length + bp->count;
/* The progress bar should look like this:
- xxx% |=======> | xx KB/s nnnnn ETA: 00:00
+ xx% [=======> ] nn.nnn rrK/s ETA 00:00
Calculate its geometry:
- "xxx% " - percentage - 5 chars
- "| ... | " - progress bar decorations - 3 chars
- "1012.56 K/s " - dl rate - 12 chars
- "nnnn " - downloaded bytes - 11 chars
- "ETA: xx:xx:xx" - ETA - 13 chars
+ "xx% " or "100%" - percentage - 4 chars exactly
+ "[]" - progress bar decorations - 2 chars exactly
+ " n,nnn,nnn,nnn" - downloaded bytes - 14 or less chars
+ " 1012.56K/s" - dl rate - 11 chars exactly
+ " ETA xx:xx:xx" - ETA - 13 or less chars
- "=====>..." - progress bar content - the rest
+ "=====>..." - progress bar content - the rest
*/
- int progress_len = screen_width - (5 + 3 + 12 + 11 + 13);
+ int progress_size = screen_width - (4 + 2 + 14 + 11 + 13);
- if (progress_len < 7)
- progress_len = 0;
+ if (progress_size < 5)
+ progress_size = 0;
- /* "xxx% " */
+ /* "xx% " */
if (bp->total_length > 0)
{
int percentage = (int)(100.0 * size / bp->total_length);
assert (percentage <= 100);
- sprintf (p, "%3d%% ", percentage);
- p += 5;
+ if (percentage < 100)
+ sprintf (p, "%2d%% ", percentage);
+ else
+ strcpy (p, "100%");
+ p += 4;
+ }
+ else
+ {
+ *p++ = ' ';
+ *p++ = ' ';
+ *p++ = ' ';
+ *p++ = ' ';
}
- /* The progress bar: "|====> | " */
- if (progress_len && bp->total_length > 0)
+ /* The progress bar: "[====> ]" */
+ if (progress_size && bp->total_length > 0)
{
double fraction = (double)size / bp->total_length;
- int dlsz = (int)(fraction * progress_len);
+ int dlsz = (int)(fraction * progress_size);
char *begin;
- assert (dlsz <= progress_len);
+ assert (dlsz <= progress_size);
- *p++ = '|';
+ *p++ = '[';
begin = p;
if (dlsz > 0)
*p++ = '>';
}
- while (p - begin < progress_len)
+ while (p - begin < progress_size)
*p++ = ' ';
- *p++ = '|';
- *p++ = ' ';
+ *p++ = ']';
}
+ else if (progress_size)
+ {
+ /* If we can't draw a real progress bar, then at least show
+ *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;
+ else
+ 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++ = ' ';
+ }
+ *p++ = ']';
+
+ ++bp->tick;
+ }
+
+ /* " 1,234,567" */
+ /* If there are 7 or less digits (9 because of "legible" comas),
+ print the number in constant space. This will prevent the rest
+ of the line jerking at the beginning of download, but without
+ assigning maximum width in all cases. */
+ sprintf (p, " %9s", legible (size));
+ p += strlen (p);
- /* "1012.45 K/s " */
+ /* " 1012.45K/s" */
if (dltime && bp->count)
{
- char *rt = rate (bp->count, dltime, 1);
- strcpy (p, rt);
+ static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
+ int units = 0;
+ double dlrate = calc_rate (bp->count, dltime, &units);
+ sprintf (p, " %7.2f%s", dlrate, short_units[units]);
p += strlen (p);
- *p++ = ' ';
}
else
{
- strcpy (p, "----.-- K/s ");
- p += 12;
+ strcpy (p, " --.--K/s");
+ p += 11;
}
- /* "12376 " */
- sprintf (p, _("%ld "), size);
- p += strlen (p);
-
- /* "ETA: xx:xx:xx" */
+ /* " ETA xx:xx:xx" */
if (bp->total_length > 0 && bp->count > 0)
{
int eta, eta_hrs, eta_min, eta_sec;
/*printf ("\neta: %d, %d %d %d\n", eta, eta_hrs, eta_min, eta_sec);*/
/*printf ("\n%ld %f %ld %ld\n", dltime, tm_sofar, bytes_remaining, bp->count);*/
+ *p++ = ' ';
*p++ = 'E';
*p++ = 'T';
*p++ = 'A';
- *p++ = ':';
*p++ = ' ';
if (eta_hrs > 99)
}
else if (bp->total_length > 0)
{
- strcpy (p, "ETA: --:--");
+ strcpy (p, " ETA --:--");
p += 10;
}
static void
display_image (char *buf)
{
- int len = strlen (buf);
- char *del_buf = alloca (len + 1);
-
- logputs (LOG_VERBOSE, buf);
-
- memset (del_buf, '\b', len);
- del_buf[len] = '\0';
-
+ char *del_buf = alloca (screen_width + 1);
+ memset (del_buf, '\b', screen_width);
+ del_buf[screen_width] = '\0';
logputs (LOG_VERBOSE, del_buf);
+ logputs (LOG_VERBOSE, buf);
}
static void
-bar_set_params (const char *ignored)
+bar_set_params (const char *params)
{
int sw;
- if (opt.lfilename
+ if ((opt.lfilename
#ifdef HAVE_ISATTY
- || !isatty (fileno (stderr))
+ || !isatty (fileno (stderr))
#else
- 1
+ 1
#endif
- )
+ )
+ && !(params != NULL
+ && 0 == strcmp (params, "force")))
{
- /* We're not printing to a TTY. Revert to the fallback
- display. */
+ /* 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 that function could resolve this problem
+ itself. */
set_progress_implementation (NULL);
return;
}