mirror of
https://github.com/mirror/wget.git
synced 2024-12-29 14:30:48 +08:00
[svn] Big progress bar update.
Published in <sxsn11ehyn1.fsf@florida.arsdigita.de>.
This commit is contained in:
parent
4d352013ac
commit
cdcf67a5bd
@ -1,3 +1,7 @@
|
||||
2001-11-23 Hrvoje Niksic <hniksic@arsdigita.com>
|
||||
|
||||
* configure.in: Check for sys/ioctl.h.
|
||||
|
||||
2001-11-22 Herold Heiko <Heiko.Herold@previnet.it>
|
||||
|
||||
* windows/Readme
|
||||
|
@ -155,7 +155,7 @@ dnl
|
||||
dnl Checks for headers
|
||||
dnl
|
||||
AC_CHECK_HEADERS(string.h stdarg.h unistd.h sys/time.h utime.h sys/utime.h)
|
||||
AC_CHECK_HEADERS(sys/select.h sys/utsname.h pwd.h signal.h)
|
||||
AC_CHECK_HEADERS(sys/ioctl.h sys/select.h sys/utsname.h pwd.h signal.h)
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl
|
||||
|
@ -1,3 +1,31 @@
|
||||
2001-11-23 Hrvoje Niksic <hniksic@arsdigita.com>
|
||||
|
||||
* utils.c (determine_screen_width): New function.
|
||||
|
||||
* main.c (main): New option `--progress=TYPE'.
|
||||
(main): Implement compatibility with the old option `--dot-style'.
|
||||
|
||||
* init.c: Removed cmd_spec_dotstyle -- that logic is now in
|
||||
dp_set_params.
|
||||
(cmd_spec_progress): New function.
|
||||
|
||||
* retr.c (get_contents): Use the progress_* functions instead of
|
||||
the old show_progress().
|
||||
(show_progress): Removed.
|
||||
(rate): Print "xxxx.xx K/s" instead of "KB/s". Ditto for MB/s,
|
||||
etc.
|
||||
|
||||
* progress.c (set_progress_implementation): New function.
|
||||
(valid_progress_implementation_p): Ditto.
|
||||
(progress_create): Ditto.
|
||||
(progress_update): Ditto.
|
||||
(progress_finish): Ditto.
|
||||
(dp_create): Ditto.
|
||||
(dp_update): Ditto.
|
||||
(dp_finish): Ditto.
|
||||
(dp_set_params): Ditto.
|
||||
(print_elapsed): Ditto.
|
||||
|
||||
2001-11-22 Hrvoje Niksic <hniksic@arsdigita.com>
|
||||
|
||||
* retr.c (show_progress): Use it.
|
||||
|
@ -65,8 +65,8 @@ GETOPT_OBJ = @GETOPT_OBJ@
|
||||
OBJ = $(ALLOCA) cmpt$o connect$o cookies$o fnmatch$o ftp$o \
|
||||
ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \
|
||||
headers$o host$o html-parse$o html-url$o http$o init$o \
|
||||
log$o main$o $(MD5_OBJ) netrc$o rbuf$o recur$o res$o \
|
||||
retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o \
|
||||
log$o main$o $(MD5_OBJ) netrc$o progress$o rbuf$o recur$o \
|
||||
res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o \
|
||||
utils$o version$o
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -180,6 +180,9 @@ char *alloca ();
|
||||
/* Define if you have the <sys/utime.h> header file. */
|
||||
#undef HAVE_SYS_UTIME_H
|
||||
|
||||
/* Define if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
|
73
src/init.c
73
src/init.c
@ -82,10 +82,10 @@ CMD_DECLARE (cmd_time);
|
||||
CMD_DECLARE (cmd_vector);
|
||||
|
||||
CMD_DECLARE (cmd_spec_dirstruct);
|
||||
CMD_DECLARE (cmd_spec_dotstyle);
|
||||
CMD_DECLARE (cmd_spec_header);
|
||||
CMD_DECLARE (cmd_spec_htmlify);
|
||||
CMD_DECLARE (cmd_spec_mirror);
|
||||
CMD_DECLARE (cmd_spec_progress);
|
||||
CMD_DECLARE (cmd_spec_recursive);
|
||||
CMD_DECLARE (cmd_spec_useragent);
|
||||
|
||||
@ -122,7 +122,6 @@ static struct {
|
||||
{ "dotbytes", &opt.dot_bytes, cmd_bytes },
|
||||
{ "dotsinline", &opt.dots_in_line, cmd_number },
|
||||
{ "dotspacing", &opt.dot_spacing, cmd_number },
|
||||
{ "dotstyle", NULL, cmd_spec_dotstyle },
|
||||
{ "excludedirectories", &opt.excludes, cmd_directory_vector },
|
||||
{ "excludedomains", &opt.exclude_domains, cmd_vector },
|
||||
{ "followftp", &opt.follow_ftp, cmd_boolean },
|
||||
@ -156,6 +155,7 @@ static struct {
|
||||
{ "pagerequisites", &opt.page_requisites, cmd_boolean },
|
||||
{ "passiveftp", &opt.ftp_pasv, cmd_lockable_boolean },
|
||||
{ "passwd", &opt.ftp_pass, cmd_string },
|
||||
{ "progress", NULL, cmd_spec_progress },
|
||||
{ "proxypasswd", &opt.proxy_passwd, cmd_string },
|
||||
{ "proxyuser", &opt.proxy_user, cmd_string },
|
||||
{ "quiet", &opt.quiet, cmd_boolean },
|
||||
@ -249,6 +249,7 @@ defaults (void)
|
||||
|
||||
opt.remove_listing = 1;
|
||||
|
||||
set_progress_implementation ("dot");
|
||||
opt.dot_bytes = 1024;
|
||||
opt.dot_spacing = 10;
|
||||
opt.dots_in_line = 50;
|
||||
@ -870,61 +871,6 @@ cmd_spec_dirstruct (const char *com, const char *val, void *closure)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_spec_dotstyle (const char *com, const char *val, void *closure)
|
||||
{
|
||||
/* Retrieval styles. */
|
||||
if (!strcasecmp (val, "default"))
|
||||
{
|
||||
/* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
|
||||
line. */
|
||||
opt.dot_bytes = 1024;
|
||||
opt.dot_spacing = 10;
|
||||
opt.dots_in_line = 50;
|
||||
}
|
||||
else if (!strcasecmp (val, "binary"))
|
||||
{
|
||||
/* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
|
||||
(384K) in a line. */
|
||||
opt.dot_bytes = 8192;
|
||||
opt.dot_spacing = 16;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (val, "mega"))
|
||||
{
|
||||
/* "Mega" retrieval, for retrieving very long files; each dot is
|
||||
64K, 8 dots in a cluster, 6 clusters (3M) in a line. */
|
||||
opt.dot_bytes = 65536L;
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (val, "giga"))
|
||||
{
|
||||
/* "Giga" retrieval, for retrieving very very *very* long files;
|
||||
each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
|
||||
line. */
|
||||
opt.dot_bytes = (1L << 20);
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 32;
|
||||
}
|
||||
else if (!strcasecmp (val, "micro"))
|
||||
{
|
||||
/* "Micro" retrieval, for retrieving very small files (and/or
|
||||
slow connections); each dot is 128 bytes, 8 dots in a
|
||||
cluster, 6 clusters (6K) in a line. */
|
||||
opt.dot_bytes = 128;
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
|
||||
exec_name, com, val);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_spec_header (const char *com, const char *val, void *closure)
|
||||
{
|
||||
@ -984,6 +930,19 @@ cmd_spec_mirror (const char *com, const char *val, void *closure)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_spec_progress (const char *com, const char *val, void *closure)
|
||||
{
|
||||
if (!valid_progress_implementation_p (val))
|
||||
{
|
||||
fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
|
||||
exec_name, com, val);
|
||||
return 0;
|
||||
}
|
||||
set_progress_implementation (val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_spec_recursive (const char *com, const char *val, void *closure)
|
||||
{
|
||||
|
20
src/main.c
20
src/main.c
@ -51,6 +51,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "host.h"
|
||||
#include "cookies.h"
|
||||
#include "url.h"
|
||||
#include "progress.h" /* for progress_handle_sigwinch */
|
||||
|
||||
/* On GNU system this will include system-wide getopt.h. */
|
||||
#include "getopt.h"
|
||||
@ -165,7 +166,7 @@ Download:\n\
|
||||
-O --output-document=FILE write documents to FILE.\n\
|
||||
-nc, --no-clobber don\'t clobber existing files or use .# suffixes.\n\
|
||||
-c, --continue resume getting a partially-downloaded file.\n\
|
||||
--dot-style=STYLE set retrieval display style.\n\
|
||||
--progress=TYPE select progress gauge type.\n\
|
||||
-N, --timestamping don\'t re-retrieve files unless newer than local.\n\
|
||||
-S, --server-response print server response.\n\
|
||||
--spider don\'t download anything.\n\
|
||||
@ -312,6 +313,7 @@ main (int argc, char *const *argv)
|
||||
{ "no", required_argument, NULL, 'n' },
|
||||
{ "output-document", required_argument, NULL, 'O' },
|
||||
{ "output-file", required_argument, NULL, 'o' },
|
||||
{ "progress", required_argument, NULL, 163 },
|
||||
{ "proxy", required_argument, NULL, 'Y' },
|
||||
{ "proxy-passwd", required_argument, NULL, 144 },
|
||||
{ "proxy-user", required_argument, NULL, 143 },
|
||||
@ -499,7 +501,13 @@ GNU General Public License for more details.\n"));
|
||||
setval ("header", optarg);
|
||||
break;
|
||||
case 134:
|
||||
setval ("dotstyle", optarg);
|
||||
/* Supported for compatibility; --dot-style=foo equivalent
|
||||
to --progress=dot:foo. */
|
||||
{
|
||||
char *tmp = alloca (3 + 1 + strlen (optarg));
|
||||
sprintf (tmp, "dot:%s", optarg);
|
||||
setval ("progress", tmp);
|
||||
}
|
||||
break;
|
||||
case 135:
|
||||
setval ("htmlify", optarg);
|
||||
@ -531,6 +539,9 @@ GNU General Public License for more details.\n"));
|
||||
case 162:
|
||||
setval ("savecookies", optarg);
|
||||
break;
|
||||
case 163:
|
||||
setval ("progress", optarg);
|
||||
break;
|
||||
case 157:
|
||||
setval ("referer", optarg);
|
||||
break;
|
||||
@ -784,6 +795,9 @@ Can't timestamp and not clobber old files at the same time.\n"));
|
||||
process exits. What we want is to ignore SIGPIPE and just check
|
||||
for the return value of write(). */
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
#ifdef SIGWINCH
|
||||
signal (SIGWINCH, progress_handle_sigwinch);
|
||||
#endif
|
||||
#endif /* HAVE_SIGNAL */
|
||||
|
||||
status = RETROK; /* initialize it, just-in-case */
|
||||
@ -860,11 +874,11 @@ Can't timestamp and not clobber old files at the same time.\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNAL
|
||||
/* Hangup signal handler. When wget receives SIGHUP or SIGUSR1, it
|
||||
will proceed operation as usual, trying to write into a log file.
|
||||
If that is impossible, the output will be turned off. */
|
||||
|
||||
#ifdef HAVE_SIGNAL
|
||||
static RETSIGTYPE
|
||||
redirect_output_signal (int sig)
|
||||
{
|
||||
|
584
src/progress.c
Normal file
584
src/progress.c
Normal file
@ -0,0 +1,584 @@
|
||||
/* Download progress.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
\(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#include <assert.h>
|
||||
|
||||
#include "wget.h"
|
||||
#include "progress.h"
|
||||
#include "utils.h"
|
||||
#include "retr.h"
|
||||
|
||||
struct progress_implementation {
|
||||
char *name;
|
||||
void *(*create) (long, long);
|
||||
void (*update) (void *, long);
|
||||
void (*finish) (void *);
|
||||
void (*set_params) (const char *);
|
||||
};
|
||||
|
||||
/* Necessary forward declarations. */
|
||||
|
||||
static void *dp_create PARAMS ((long, long));
|
||||
static void dp_update PARAMS ((void *, long));
|
||||
static void dp_finish PARAMS ((void *));
|
||||
static void dp_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_set_params PARAMS ((const char *));
|
||||
|
||||
static struct progress_implementation implementations[] = {
|
||||
{ "dot", dp_create, dp_update, dp_finish, dp_set_params },
|
||||
{ "bar", bar_create, bar_update, bar_finish, bar_set_params }
|
||||
};
|
||||
static struct progress_implementation *current_impl;
|
||||
|
||||
/* Return non-zero if NAME names a valid progress bar implementation.
|
||||
The characters after the first : will be ignored. */
|
||||
|
||||
int
|
||||
valid_progress_implementation_p (const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct progress_implementation *pi = implementations;
|
||||
char *colon = strchr (name, ':');
|
||||
int namelen = colon ? colon - name : strlen (name);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (implementations); i++, pi++)
|
||||
if (!strncmp (pi->name, name, namelen))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the progress implementation to NAME. */
|
||||
|
||||
void
|
||||
set_progress_implementation (const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct progress_implementation *pi = implementations;
|
||||
char *colon = strchr (name, ':');
|
||||
int namelen = colon ? colon - name : strlen (name);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (implementations); i++, pi++)
|
||||
if (!strncmp (pi->name, name, namelen))
|
||||
{
|
||||
current_impl = pi;
|
||||
|
||||
if (colon)
|
||||
/* We call pi->set_params even if colon is NULL because we
|
||||
want to give the implementation a chance to set up some
|
||||
things it needs to run. */
|
||||
++colon;
|
||||
|
||||
if (pi->set_params)
|
||||
pi->set_params (colon);
|
||||
return;
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Create a progress gauge. INITIAL is the number of bytes the
|
||||
download starts from (zero if the download starts from scratch).
|
||||
TOTAL is the expected total number of bytes in this download. If
|
||||
TOTAL is zero, it means that the download size is not known in
|
||||
advance. */
|
||||
|
||||
void *
|
||||
progress_create (long initial, long total)
|
||||
{
|
||||
return current_impl->create (initial, total);
|
||||
}
|
||||
|
||||
/* Inform the progress gauge of newly received bytes. */
|
||||
|
||||
void
|
||||
progress_update (void *progress, long howmuch)
|
||||
{
|
||||
current_impl->update (progress, howmuch);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
current_impl->finish (progress);
|
||||
}
|
||||
|
||||
/* Dot-printing. */
|
||||
|
||||
struct dot_progress {
|
||||
long initial_length; /* how many bytes have been downloaded
|
||||
previously. */
|
||||
long total_length; /* expected total byte count when the
|
||||
download finishes */
|
||||
|
||||
int accumulated;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* Dot-progress backend for progress_create. */
|
||||
|
||||
static void *
|
||||
dp_create (long initial, long total)
|
||||
{
|
||||
struct dot_progress *dp = xmalloc (sizeof (struct dot_progress));
|
||||
|
||||
memset (dp, 0, sizeof (*dp));
|
||||
|
||||
dp->initial_length = initial;
|
||||
dp->total_length = total;
|
||||
dp->timer = wtimer_new ();
|
||||
|
||||
if (dp->initial_length)
|
||||
{
|
||||
int dot_bytes = opt.dot_bytes;
|
||||
long row_bytes = opt.dot_bytes * opt.dots_in_line;
|
||||
|
||||
int remainder = (int) (dp->initial_length % row_bytes);
|
||||
long skipped = dp->initial_length - remainder;
|
||||
|
||||
if (skipped)
|
||||
{
|
||||
logputs (LOG_VERBOSE, "\n "); /* leave spacing untranslated */
|
||||
logprintf (LOG_VERBOSE, _("[ skipping %dK ]"),
|
||||
(int) (skipped / 1024));
|
||||
}
|
||||
|
||||
logprintf (LOG_VERBOSE, "\n%5ldK", skipped / 1024);
|
||||
for (; remainder >= dot_bytes; remainder -= dot_bytes)
|
||||
{
|
||||
if (dp->dots % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, ",");
|
||||
++dp->dots;
|
||||
}
|
||||
assert (dp->dots < opt.dots_in_line);
|
||||
|
||||
dp->accumulated = remainder;
|
||||
dp->rows = skipped / row_bytes;
|
||||
}
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
static void
|
||||
print_percentage (long bytes, long expected)
|
||||
{
|
||||
int percentage = (int)(100.0 * bytes / expected);
|
||||
logprintf (LOG_VERBOSE, "%3d%%", percentage);
|
||||
}
|
||||
|
||||
static void
|
||||
print_elapsed (struct dot_progress *dp, long bytes)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Dot-progress backend for progress_update. */
|
||||
|
||||
static void
|
||||
dp_update (void *progress, long howmuch)
|
||||
{
|
||||
struct dot_progress *dp = progress;
|
||||
int dot_bytes = opt.dot_bytes;
|
||||
long row_bytes = opt.dot_bytes * opt.dots_in_line;
|
||||
|
||||
log_set_flush (0);
|
||||
|
||||
dp->accumulated += howmuch;
|
||||
for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
|
||||
{
|
||||
if (dp->dots == 0)
|
||||
logprintf (LOG_VERBOSE, "\n%5ldK", dp->rows * row_bytes / 1024);
|
||||
|
||||
if (dp->dots % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, ".");
|
||||
|
||||
++dp->dots;
|
||||
if (dp->dots >= opt.dots_in_line)
|
||||
{
|
||||
++dp->rows;
|
||||
dp->dots = 0;
|
||||
|
||||
if (dp->total_length)
|
||||
print_percentage (dp->rows * row_bytes, dp->total_length);
|
||||
|
||||
print_elapsed (dp, row_bytes - (dp->initial_length % row_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
log_set_flush (1);
|
||||
}
|
||||
|
||||
/* Dot-progress backend for progress_finish. */
|
||||
|
||||
static void
|
||||
dp_finish (void *progress)
|
||||
{
|
||||
struct dot_progress *dp = progress;
|
||||
int dot_bytes = opt.dot_bytes;
|
||||
long row_bytes = opt.dot_bytes * opt.dots_in_line;
|
||||
int i;
|
||||
|
||||
log_set_flush (0);
|
||||
|
||||
for (i = dp->dots; i < opt.dots_in_line; i++)
|
||||
{
|
||||
if (i % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
}
|
||||
if (dp->total_length)
|
||||
{
|
||||
print_percentage (dp->rows * row_bytes
|
||||
+ dp->dots * dot_bytes
|
||||
+ dp->accumulated,
|
||||
dp->total_length);
|
||||
}
|
||||
|
||||
print_elapsed (dp, dp->dots * dot_bytes
|
||||
+ dp->accumulated
|
||||
- dp->initial_length % row_bytes);
|
||||
logputs (LOG_VERBOSE, "\n\n");
|
||||
|
||||
log_set_flush (0);
|
||||
|
||||
wtimer_delete (dp->timer);
|
||||
xfree (dp);
|
||||
}
|
||||
|
||||
/* This function interprets the progress "parameters". For example,
|
||||
if Wget is invoked with --progress=bar:mega, it will set the
|
||||
"dot-style" to "mega". Valid styles are default, binary, mega, and
|
||||
giga. */
|
||||
|
||||
static void
|
||||
dp_set_params (const char *params)
|
||||
{
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
/* We use this to set the retrieval style. */
|
||||
if (!strcasecmp (params, "default"))
|
||||
{
|
||||
/* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
|
||||
line. */
|
||||
opt.dot_bytes = 1024;
|
||||
opt.dot_spacing = 10;
|
||||
opt.dots_in_line = 50;
|
||||
}
|
||||
else if (!strcasecmp (params, "binary"))
|
||||
{
|
||||
/* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
|
||||
(384K) in a line. */
|
||||
opt.dot_bytes = 8192;
|
||||
opt.dot_spacing = 16;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (params, "mega"))
|
||||
{
|
||||
/* "Mega" retrieval, for retrieving very long files; each dot is
|
||||
64K, 8 dots in a cluster, 6 clusters (3M) in a line. */
|
||||
opt.dot_bytes = 65536L;
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (params, "giga"))
|
||||
{
|
||||
/* "Giga" retrieval, for retrieving very very *very* long files;
|
||||
each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
|
||||
line. */
|
||||
opt.dot_bytes = (1L << 20);
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 32;
|
||||
}
|
||||
else
|
||||
fprintf (stderr,
|
||||
_("Invalid dot style specification `%s'; leaving unchanged.\n"),
|
||||
params);
|
||||
}
|
||||
|
||||
/* "Thermometer" (bar) progress. */
|
||||
|
||||
/* Assumed screen width if we can't find the real value. */
|
||||
#define DEFAULT_SCREEN_WIDTH 80
|
||||
|
||||
/* Minimum screen width we'll try to work with. If this is too small,
|
||||
create_image will overflow the buffer. */
|
||||
#define MINIMUM_SCREEN_WIDTH 45
|
||||
|
||||
static int screen_width = DEFAULT_SCREEN_WIDTH;
|
||||
|
||||
struct bar_progress {
|
||||
long initial_length; /* how many bytes have been downloaded
|
||||
previously. */
|
||||
long total_length; /* expected total byte count when the
|
||||
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. */
|
||||
};
|
||||
|
||||
static void create_image PARAMS ((struct bar_progress *, long));
|
||||
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));
|
||||
|
||||
bp->initial_length = initial;
|
||||
bp->total_length = total;
|
||||
bp->timer = wtimer_new ();
|
||||
bp->width = screen_width;
|
||||
bp->buffer = xmalloc (bp->width + 1);
|
||||
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
|
||||
create_image (bp, 0);
|
||||
display_image (bp->buffer);
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_update (void *progress, long howmuch)
|
||||
{
|
||||
struct bar_progress *bp = progress;
|
||||
int force_update = 0;
|
||||
long dltime = wtimer_elapsed (bp->timer);
|
||||
|
||||
bp->count += howmuch;
|
||||
|
||||
if (screen_width != bp->width)
|
||||
{
|
||||
bp->width = screen_width;
|
||||
bp->buffer = xrealloc (bp->buffer, bp->width + 1);
|
||||
}
|
||||
|
||||
if (dltime - bp->last_update < 200 && !force_update)
|
||||
/* Don't update more often than every half a second. */
|
||||
return;
|
||||
|
||||
bp->last_update = dltime;
|
||||
|
||||
create_image (bp, dltime);
|
||||
display_image (bp->buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
bar_finish (void *progress)
|
||||
{
|
||||
struct bar_progress *bp = progress;
|
||||
|
||||
create_image (bp, wtimer_elapsed (bp->timer));
|
||||
display_image (bp->buffer);
|
||||
|
||||
logputs (LOG_VERBOSE, "\n\n");
|
||||
|
||||
xfree (bp->buffer);
|
||||
wtimer_delete (bp->timer);
|
||||
xfree (bp);
|
||||
}
|
||||
|
||||
static void
|
||||
create_image (struct bar_progress *bp, long dltime)
|
||||
{
|
||||
char *p = bp->buffer;
|
||||
long size = bp->initial_length + bp->count;
|
||||
|
||||
/* The progress bar should look like this:
|
||||
xxx% |=======> | xx KB/s nnnnn ETA: 00:00
|
||||
|
||||
Calculate its geometry:
|
||||
|
||||
"xxx% " - percentage - 5 chars
|
||||
"| ... | " - progress bar decorations - 3 chars
|
||||
"1234.56 K/s " - dl rate - 12 chars
|
||||
"nnnn " - downloaded bytes - 11 chars
|
||||
"ETA: xx:xx:xx" - ETA - 13 chars
|
||||
|
||||
"=====>..." - progress bar content - the rest
|
||||
*/
|
||||
int progress_len = screen_width - (5 + 3 + 12 + 11 + 13);
|
||||
|
||||
if (progress_len < 7)
|
||||
progress_len = 0;
|
||||
|
||||
/* "xxx% " */
|
||||
if (bp->total_length > 0)
|
||||
{
|
||||
int percentage = (int)(100.0 * size / bp->total_length);
|
||||
|
||||
assert (percentage <= 100);
|
||||
|
||||
sprintf (p, "%3d%% ", percentage);
|
||||
p += 5;
|
||||
}
|
||||
|
||||
/* The progress bar: "|====> | " */
|
||||
if (progress_len && bp->total_length > 0)
|
||||
{
|
||||
double fraction = (double)size / bp->total_length;
|
||||
int dlsz = (int)(fraction * progress_len);
|
||||
char *begin;
|
||||
|
||||
assert (dlsz <= progress_len);
|
||||
|
||||
*p++ = '|';
|
||||
begin = p;
|
||||
|
||||
if (dlsz > 0)
|
||||
{
|
||||
/* Draw dlsz-1 '=' chars and one arrow char. */
|
||||
while (dlsz-- > 1)
|
||||
*p++ = '=';
|
||||
*p++ = '>';
|
||||
}
|
||||
|
||||
while (p - begin < progress_len)
|
||||
*p++ = ' ';
|
||||
|
||||
*p++ = '|';
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
/* "2.3 KB/s " */
|
||||
if (dltime && bp->count)
|
||||
{
|
||||
char *rt = rate (bp->count, dltime, 1);
|
||||
strcpy (p, rt);
|
||||
p += strlen (p);
|
||||
*p++ = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (p, "----.-- KB/s ");
|
||||
p += 13;
|
||||
}
|
||||
|
||||
/* "12376 " */
|
||||
sprintf (p, _("%ld "), size);
|
||||
p += strlen (p);
|
||||
|
||||
/* "ETA: xx:xx:xx" */
|
||||
if (bp->total_length > 0 && bp->count > 0)
|
||||
{
|
||||
int eta, eta_hrs, eta_min, eta_sec;
|
||||
double tm_sofar = (double)dltime / 1000;
|
||||
long bytes_remaining = bp->total_length - size;
|
||||
|
||||
eta = (int) (tm_sofar * bytes_remaining / bp->count);
|
||||
|
||||
eta_hrs = eta / 3600, eta %= 3600;
|
||||
eta_min = eta / 60, eta %= 60;
|
||||
eta_sec = eta;
|
||||
|
||||
/*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++ = 'E';
|
||||
*p++ = 'T';
|
||||
*p++ = 'A';
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
|
||||
if (eta_hrs > 99)
|
||||
/* Bogus value, for whatever reason. We must avoid overflow. */
|
||||
sprintf (p, "--:--");
|
||||
else if (eta_hrs > 0)
|
||||
sprintf (p, "%d:%02d:%02d", eta_hrs, eta_min, eta_sec);
|
||||
else
|
||||
sprintf (p, "%02d:%02d", eta_min, eta_sec);
|
||||
p += strlen (p);
|
||||
}
|
||||
else if (bp->total_length > 0)
|
||||
{
|
||||
strcpy (p, "ETA: --:--");
|
||||
p += 10;
|
||||
}
|
||||
|
||||
assert (p - bp->buffer <= screen_width);
|
||||
|
||||
while (p < bp->buffer + screen_width)
|
||||
*p++ = ' ';
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
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';
|
||||
|
||||
logputs (LOG_VERBOSE, del_buf);
|
||||
}
|
||||
|
||||
static void
|
||||
bar_set_params (const char *ignored)
|
||||
{
|
||||
int sw = determine_screen_width ();
|
||||
if (sw && sw >= MINIMUM_SCREEN_WIDTH)
|
||||
screen_width = sw;
|
||||
}
|
||||
|
||||
RETSIGTYPE
|
||||
progress_handle_sigwinch (int sig)
|
||||
{
|
||||
int sw = determine_screen_width ();
|
||||
if (sw && sw >= MINIMUM_SCREEN_WIDTH)
|
||||
screen_width = sw;
|
||||
}
|
27
src/progress.h
Normal file
27
src/progress.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* Download progress.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
\(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
int valid_progress_implementation_p PARAMS ((const char *));
|
||||
void set_progress_implementation PARAMS ((const char *));
|
||||
|
||||
void *progress_create PARAMS ((long, long));
|
||||
void progress_update PARAMS ((void *, long));
|
||||
void progress_finish PARAMS ((void *));
|
||||
|
||||
RETSIGTYPE progress_handle_sigwinch PARAMS ((int));
|
168
src/retr.c
168
src/retr.c
@ -36,6 +36,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "wget.h"
|
||||
#include "utils.h"
|
||||
#include "retr.h"
|
||||
#include "progress.h"
|
||||
#include "url.h"
|
||||
#include "recur.h"
|
||||
#include "ftp.h"
|
||||
@ -51,11 +52,6 @@ extern int errno;
|
||||
int global_download_count;
|
||||
|
||||
|
||||
/* Flags for show_progress(). */
|
||||
enum spflags { SP_NONE, SP_INIT, SP_FINISH };
|
||||
|
||||
static int show_progress PARAMS ((long, long, enum spflags));
|
||||
|
||||
#define MIN(i, j) ((i) <= (j) ? (i) : (j))
|
||||
|
||||
/* Reads the contents of file descriptor FD, until it is closed, or a
|
||||
@ -85,23 +81,28 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
|
||||
{
|
||||
int res = 0;
|
||||
static char c[8192];
|
||||
void *progress = NULL;
|
||||
|
||||
*len = restval;
|
||||
if (opt.verbose)
|
||||
show_progress (restval, expected, SP_INIT);
|
||||
progress = progress_create (restval, expected);
|
||||
|
||||
if (rbuf && RBUF_FD (rbuf) == fd)
|
||||
{
|
||||
int need_flush = 0;
|
||||
while ((res = rbuf_flush (rbuf, c, sizeof (c))) != 0)
|
||||
{
|
||||
if (fwrite (c, sizeof (char), res, fp) < res)
|
||||
return -2;
|
||||
if (opt.verbose)
|
||||
{
|
||||
if (show_progress (res, expected, SP_NONE))
|
||||
fflush (fp);
|
||||
}
|
||||
progress_update (progress, res);
|
||||
*len += res;
|
||||
need_flush = 1;
|
||||
}
|
||||
if (need_flush)
|
||||
fflush (fp);
|
||||
if (ferror (fp))
|
||||
return -2;
|
||||
}
|
||||
/* Read from fd while there is available data.
|
||||
|
||||
@ -124,13 +125,15 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
|
||||
#endif /* HAVE_SSL */
|
||||
if (res > 0)
|
||||
{
|
||||
if (fwrite (c, sizeof (char), res, fp) < res)
|
||||
fwrite (c, sizeof (char), res, fp);
|
||||
/* Always flush the contents of the network packet. This
|
||||
should not be adverse to performance, as the network
|
||||
packets typically won't be too tiny anyway. */
|
||||
fflush (fp);
|
||||
if (ferror (fp))
|
||||
return -2;
|
||||
if (opt.verbose)
|
||||
{
|
||||
if (show_progress (res, expected, SP_NONE))
|
||||
fflush (fp);
|
||||
}
|
||||
progress_update (progress, res);
|
||||
*len += res;
|
||||
}
|
||||
else
|
||||
@ -139,132 +142,14 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
|
||||
if (res < -1)
|
||||
res = -1;
|
||||
if (opt.verbose)
|
||||
show_progress (0, expected, SP_FINISH);
|
||||
progress_finish (progress);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
print_percentage (long bytes, long expected)
|
||||
{
|
||||
int percentage = (int)(100.0 * bytes / expected);
|
||||
logprintf (LOG_VERBOSE, "%3d%%", percentage);
|
||||
}
|
||||
|
||||
/* Show the dotted progress report of file loading. Called with
|
||||
length and a flag to tell it whether to reset or not. It keeps the
|
||||
offset information in static local variables.
|
||||
|
||||
Return value: 1 or 0, designating whether any dots have been drawn.
|
||||
|
||||
If the init argument is set, the routine will initialize.
|
||||
|
||||
If the res is non-zero, res/line_bytes lines are skipped
|
||||
(meaning the appropriate number ok kilobytes), and the number of
|
||||
"dots" fitting on the first line are drawn as ','. */
|
||||
static int
|
||||
show_progress (long res, long expected, enum spflags flags)
|
||||
{
|
||||
static struct wget_timer *timer;
|
||||
static long line_bytes;
|
||||
static long offs, initial_skip;
|
||||
static int ndot, nrow;
|
||||
static long last_timer_value, time_offset;
|
||||
int any_output = 0;
|
||||
|
||||
if (flags == SP_FINISH)
|
||||
{
|
||||
int dot = ndot;
|
||||
char *tmpstr = (char *)alloca (2 * opt.dots_in_line + 1);
|
||||
char *tmpp = tmpstr;
|
||||
time_offset = wtimer_elapsed (timer) - last_timer_value;
|
||||
for (; dot < opt.dots_in_line; dot++)
|
||||
{
|
||||
if (!(dot % opt.dot_spacing))
|
||||
*tmpp++ = ' ';
|
||||
*tmpp++ = ' ';
|
||||
}
|
||||
*tmpp = '\0';
|
||||
logputs (LOG_VERBOSE, tmpstr);
|
||||
if (expected)
|
||||
print_percentage (nrow * line_bytes + ndot * opt.dot_bytes + offs,
|
||||
expected);
|
||||
logprintf (LOG_VERBOSE, " @%s",
|
||||
rate (ndot * opt.dot_bytes
|
||||
+ offs - (initial_skip % line_bytes),
|
||||
time_offset, 1));
|
||||
logputs (LOG_VERBOSE, "\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Temporarily disable flushing. */
|
||||
log_set_flush (0);
|
||||
|
||||
/* init set means initialization. If res is set, it also means that
|
||||
the retrieval is *not* done from the beginning. The part that
|
||||
was already retrieved is not shown again. */
|
||||
if (flags == SP_INIT)
|
||||
{
|
||||
/* Generic initialization of static variables. */
|
||||
offs = 0L;
|
||||
ndot = nrow = 0;
|
||||
line_bytes = (long)opt.dots_in_line * opt.dot_bytes;
|
||||
if (!timer)
|
||||
timer = wtimer_allocate ();
|
||||
wtimer_reset (timer);
|
||||
last_timer_value = 0;
|
||||
time_offset = 0;
|
||||
initial_skip = res;
|
||||
if (res)
|
||||
{
|
||||
if (res >= line_bytes)
|
||||
{
|
||||
nrow = res / line_bytes;
|
||||
res %= line_bytes;
|
||||
logprintf (LOG_VERBOSE,
|
||||
_("\n [ skipping %dK ]"),
|
||||
(int) ((nrow * line_bytes) / 1024));
|
||||
ndot = 0;
|
||||
}
|
||||
}
|
||||
logprintf (LOG_VERBOSE, "\n%5ldK", nrow * line_bytes / 1024);
|
||||
}
|
||||
/* Offset gets incremented by current value. */
|
||||
offs += res;
|
||||
/* While offset is >= opt.dot_bytes, print dots, taking care to
|
||||
precede every 50th dot with a status message. */
|
||||
for (; offs >= opt.dot_bytes; offs -= opt.dot_bytes)
|
||||
{
|
||||
if (!(ndot % opt.dot_spacing))
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
any_output = 1;
|
||||
logputs (LOG_VERBOSE, flags == SP_INIT ? "," : ".");
|
||||
++ndot;
|
||||
if (ndot == opt.dots_in_line)
|
||||
{
|
||||
time_offset = wtimer_elapsed (timer) - last_timer_value;
|
||||
last_timer_value += time_offset;
|
||||
|
||||
ndot = 0;
|
||||
++nrow;
|
||||
if (expected)
|
||||
print_percentage (nrow * line_bytes, expected);
|
||||
logprintf (LOG_VERBOSE, " @%s",
|
||||
rate (line_bytes - (initial_skip % line_bytes),
|
||||
time_offset, 1));
|
||||
initial_skip = 0;
|
||||
logprintf (LOG_VERBOSE, "\n%5ldK", nrow * line_bytes / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reenable flushing. */
|
||||
log_set_flush (1);
|
||||
|
||||
return any_output;
|
||||
}
|
||||
|
||||
/* Print out the appropriate download rate. Appropriate means that if
|
||||
rate is > 1024 bytes per second, kilobytes are used, and if rate >
|
||||
1024 * 1024 bps, megabytes are used.
|
||||
/* Return a printed representation of the download rate, as
|
||||
appropriate for the speed. Appropriate means that if rate is
|
||||
greater than 1K/s, kilobytes are used, and if rate is greater than
|
||||
1MB/s, megabytes are used.
|
||||
|
||||
If PAD is non-zero, strings will be padded to the width of 7
|
||||
characters (xxxx.xx). */
|
||||
@ -274,6 +159,9 @@ rate (long bytes, long msecs, int pad)
|
||||
static char res[15];
|
||||
double dlrate;
|
||||
|
||||
assert (msecs >= 0);
|
||||
assert (bytes >= 0);
|
||||
|
||||
if (msecs == 0)
|
||||
/* If elapsed time is 0, it means we're under the granularity of
|
||||
the timer. This often happens on systems that use time() for
|
||||
@ -284,9 +172,9 @@ rate (long bytes, long msecs, int pad)
|
||||
if (dlrate < 1024.0)
|
||||
sprintf (res, pad ? "%7.2f B/s" : "%.2f B/s", dlrate);
|
||||
else if (dlrate < 1024.0 * 1024.0)
|
||||
sprintf (res, pad ? "%7.2f KB/s" : "%.2f KB/s", dlrate / 1024.0);
|
||||
sprintf (res, pad ? "%7.2f K/s" : "%.2f K/s", dlrate / 1024.0);
|
||||
else if (dlrate < 1024.0 * 1024.0 * 1024.0)
|
||||
sprintf (res, pad ? "%7.2f MB/s" : "%.2f MB/s", dlrate / (1024.0 * 1024.0));
|
||||
sprintf (res, pad ? "%7.2f M/s" : "%.2f M/s", dlrate / (1024.0 * 1024.0));
|
||||
else
|
||||
/* Maybe someone will need this one day. More realistically, it
|
||||
will get tickled by buggy timers. */
|
||||
|
28
src/utils.c
28
src/utils.c
@ -50,6 +50,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "wget.h"
|
||||
#include "utils.h"
|
||||
@ -1704,3 +1707,28 @@ html_quote_string (const char *s)
|
||||
*p = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Determine the width of the terminal we're running on. If that's
|
||||
not possible, return 0. */
|
||||
|
||||
int
|
||||
determine_screen_width (void)
|
||||
{
|
||||
/* If there's a way to get the terminal size using POSIX
|
||||
tcgetattr(), somebody please tell me. */
|
||||
#ifndef TIOCGWINSZ
|
||||
return 0;
|
||||
#else /* TIOCGWINSZ */
|
||||
int fd;
|
||||
struct winsize wsz;
|
||||
|
||||
if (opt.lfilename != NULL)
|
||||
return 0;
|
||||
|
||||
fd = fileno (stderr);
|
||||
if (ioctl (fd, TIOCGWINSZ, &wsz) < 0)
|
||||
return 0; /* most likely ENOTTY */
|
||||
|
||||
return wsz.ws_col;
|
||||
#endif /* TIOCGWINSZ */
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
# define NDEBUG /* To kill off assertions */
|
||||
#endif /* not DEBUG */
|
||||
|
||||
#define DEBUG_MALLOC
|
||||
|
||||
#ifndef PARAMS
|
||||
# if PROTOTYPES
|
||||
# define PARAMS(args) args
|
||||
|
Loading…
Reference in New Issue
Block a user